diff --git a/Gemfile b/Gemfile index 27d65f272..ef2644eb2 100644 --- a/Gemfile +++ b/Gemfile @@ -12,7 +12,7 @@ gem 'thor', '~> 0.20' gem 'hamlit-rails', '~> 0.2' gem 'pg', '~> 1.0' gem 'makara', '~> 0.4' -gem 'pghero', '~> 2.1' +gem 'pghero', '~> 2.2' gem 'dotenv-rails', '~> 2.2', '< 2.3' gem 'aws-sdk-s3', '~> 1.9', require: false @@ -24,13 +24,13 @@ gem 'streamio-ffmpeg', '~> 3.0' gem 'active_model_serializers', '~> 0.10' gem 'addressable', '~> 2.5' -gem 'bootsnap', '~> 1.3' +gem 'bootsnap', '~> 1.3', require: false gem 'browser' gem 'charlock_holmes', '~> 0.7.6' gem 'iso-639' gem 'chewy', '~> 5.0' gem 'cld3', '~> 3.2.0' -gem 'devise', '~> 4.4' +gem 'devise', '~> 4.5' gem 'devise-two-factor', '~> 3.0' group :pam_authentication, optional: true do @@ -57,12 +57,12 @@ gem 'httplog', '~> 1.0' gem 'idn-ruby', require: 'idn' gem 'kaminari', '~> 1.1' gem 'link_header', '~> 0.0' -gem 'mime-types', '~> 3.1', require: 'mime/types/columnar' +gem 'mime-types', '~> 3.2', require: 'mime/types/columnar' gem 'nokogiri', '~> 1.8' gem 'nsa', '~> 0.2' -gem 'oj', '~> 3.5' +gem 'oj', '~> 3.6' gem 'ostatus2', '~> 2.0' -gem 'ox', '~> 2.9' +gem 'ox', '~> 2.10' gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c' gem 'pundit', '~> 1.1' gem 'premailer-rails' @@ -75,8 +75,8 @@ gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock' gem 'rqrcode', '~> 0.10' gem 'ruby-progressbar', '~> 1.4' gem 'sanitize', '~> 4.6' -gem 'sidekiq', '~> 5.1' -gem 'sidekiq-scheduler', '~> 2.2' +gem 'sidekiq', '~> 5.2' +gem 'sidekiq-scheduler', '~> 3.0' gem 'sidekiq-unique-jobs', '~> 5.0' gem 'sidekiq-bulk', '~>0.1.1' gem 'simple-navigation', '~> 4.0' @@ -85,7 +85,7 @@ gem 'sprockets-rails', '~> 3.2', require: 'sprockets/railtie' gem 'stoplight', '~> 2.1.3' gem 'strong_migrations', '~> 0.2' gem 'tty-command', '~> 0.8', require: false -gem 'tty-prompt', '~> 0.16', require: false +gem 'tty-prompt', '~> 0.17', require: false gem 'twitter-text', '~> 1.14' gem 'tzinfo-data', '~> 1.2018' gem 'webpacker', '~> 3.5' @@ -104,7 +104,7 @@ group :development, :test do end group :production, :test do - gem 'private_address_check', '~> 0.4.1' + gem 'private_address_check', '~> 0.5' end group :test do @@ -133,7 +133,7 @@ group :development do gem 'bundler-audit', '~> 0.6', require: false gem 'scss_lint', '~> 0.57', require: false - gem 'capistrano', '~> 3.10' + gem 'capistrano', '~> 3.11' gem 'capistrano-rails', '~> 1.3' gem 'capistrano-rbenv', '~> 2.1' gem 'capistrano-yarn', '~> 2.0' diff --git a/Gemfile.lock b/Gemfile.lock index e4e1c69df..f7e4fcd97 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -66,7 +66,7 @@ GEM public_suffix (>= 2.0.2, < 4.0) airbrussh (1.3.0) sshkit (>= 1.6.1, != 1.7.0) - annotate (2.7.3) + annotate (2.7.4) activerecord (>= 3.2, < 6.0) rake (>= 10.4, < 13.0) arel (9.0.0) @@ -96,7 +96,7 @@ GEM rack (>= 0.9.0) binding_of_caller (0.8.0) debug_inspector (>= 0.0.1) - bootsnap (1.3.0) + bootsnap (1.3.2) msgpack (~> 1.0) brakeman (4.2.1) browser (2.5.3) @@ -108,7 +108,7 @@ GEM bundler (~> 1.2) thor (~> 0.18) byebug (10.0.2) - capistrano (3.10.2) + capistrano (3.11.0) airbrussh (>= 1.0.0) i18n rake (>= 10.0.0) @@ -147,7 +147,7 @@ GEM coderay (1.1.2) colorize (0.8.1) concurrent-ruby (1.0.5) - connection_pool (2.2.1) + connection_pool (2.2.2) crack (0.4.3) safe_yaml (~> 1.0.0) crass (1.0.4) @@ -162,7 +162,7 @@ GEM rack (>= 1) rake (> 10, < 13) thor (~> 0.19) - devise (4.4.3) + devise (4.5.0) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 4.1.0, < 6.0) @@ -202,7 +202,7 @@ GEM encryptor (3.0.0) equatable (0.5.0) erubi (1.7.1) - et-orbi (1.1.0) + et-orbi (1.1.6) tzinfo excon (0.62.0) fabrication (2.20.1) @@ -212,7 +212,7 @@ GEM multipart-post (>= 1.2, < 3) fast_blank (1.0.0) fastimage (2.1.1) - ffi (1.9.23) + ffi (1.9.25) fog-core (1.45.0) builder excon (~> 0.58) @@ -225,6 +225,9 @@ GEM fog-json (>= 1.0) ipaddress (>= 0.8) formatador (0.2.5) + fugit (1.1.6) + et-orbi (~> 1.1, >= 1.1.6) + raabro (~> 1.1) fuubar (2.3.1) rspec-core (~> 3.0) ruby-progressbar (~> 1.4) @@ -252,7 +255,7 @@ GEM heapy (0.1.3) highline (1.7.10) hiredis (0.6.1) - hitimes (1.2.6) + hitimes (1.3.0) hkdf (0.3.0) html2text (0.2.1) nokogiri (~> 1.6) @@ -328,14 +331,14 @@ GEM mimemagic (~> 0.3.2) mario-redis-lock (1.2.1) redis (>= 3.0.5) - memory_profiler (0.9.10) + memory_profiler (0.9.11) method_source (0.9.0) microformats (4.0.7) json nokogiri - mime-types (3.1) + mime-types (3.2.2) mime-types-data (~> 3.2015) - mime-types-data (3.2016.0521) + mime-types-data (3.2018.0812) mimemagic (0.3.2) mini_mime (1.0.0) mini_portile2 (2.3.0) @@ -347,7 +350,7 @@ GEM net-ldap (0.16.1) net-scp (1.2.1) net-ssh (>= 2.6.5) - net-ssh (4.2.0) + net-ssh (5.0.2) nio4r (2.3.1) nokogiri (1.8.4) mini_portile2 (~> 2.3.0) @@ -358,7 +361,7 @@ GEM concurrent-ruby (~> 1.0.0) sidekiq (>= 3.5.0) statsd-ruby (~> 1.2.0) - oj (3.5.1) + oj (3.6.11) omniauth (1.8.1) hashie (>= 3.4.6, < 3.6.0) rack (>= 1.6.2, < 3) @@ -374,7 +377,7 @@ GEM addressable (~> 2.5) http (~> 3.0) nokogiri (~> 1.8) - ox (2.9.2) + ox (2.10.0) paperclip (6.0.0) activemodel (>= 4.2.0) activesupport (>= 4.2.0) @@ -393,9 +396,9 @@ GEM equatable (~> 0.5.0) tty-color (~> 0.4.0) pg (1.0.0) - pghero (2.1.0) + pghero (2.2.0) activerecord - pkg-config (1.3.0) + pkg-config (1.3.1) powerpack (0.1.1) premailer (1.11.1) addressable @@ -404,7 +407,7 @@ GEM premailer-rails (1.10.2) actionmailer (>= 3, < 6) premailer (~> 1.7, >= 1.7.9) - private_address_check (0.4.1) + private_address_check (0.5.0) pry (0.11.3) coderay (~> 1.1.0) method_source (~> 0.9.0) @@ -417,11 +420,12 @@ GEM puma (3.11.4) pundit (1.1.0) activesupport (>= 3.0.0) + raabro (1.1.6) rack (2.0.5) rack-attack (5.2.0) rack rack-cors (1.0.2) - rack-protection (2.0.1) + rack-protection (2.0.4) rack rack-proxy (0.6.4) rack @@ -528,10 +532,10 @@ GEM ruby-progressbar (1.9.0) ruby-saml (1.7.2) nokogiri (>= 1.5.10) - rufus-scheduler (3.4.2) - et-orbi (~> 1.0) + rufus-scheduler (3.5.2) + fugit (~> 1.1, >= 1.1.5) safe_yaml (1.0.4) - sanitize (4.6.4) + sanitize (4.6.6) crass (~> 1.0.2) nokogiri (>= 1.4.4) nokogumbo (~> 1.4) @@ -543,15 +547,14 @@ GEM scss_lint (0.57.0) rake (>= 0.9, < 13) sass (~> 3.5.5) - sidekiq (5.1.3) - concurrent-ruby (~> 1.0) - connection_pool (~> 2.2, >= 2.2.0) + sidekiq (5.2.2) + connection_pool (~> 2.2, >= 2.2.2) rack-protection (>= 1.5.0) redis (>= 3.3.5, < 5) sidekiq-bulk (0.1.1) activesupport sidekiq - sidekiq-scheduler (2.2.1) + sidekiq-scheduler (3.0.0) redis (>= 3, < 5) rufus-scheduler (~> 3.2) sidekiq (>= 3) @@ -561,9 +564,9 @@ GEM thor (~> 0) simple-navigation (4.0.5) activesupport (>= 2.3.2) - simple_form (4.0.0) - actionpack (> 4) - activemodel (> 4) + simple_form (4.0.1) + actionpack (>= 5.0) + activemodel (>= 5.0) simplecov (0.16.1) docile (~> 1.1) json (>= 1.8, < 3) @@ -576,15 +579,15 @@ GEM actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) - sshkit (1.16.0) + sshkit (1.17.0) net-scp (>= 1.1.2) net-ssh (>= 2.8.0) - stackprof (0.2.11) + stackprof (0.2.12) statsd-ruby (1.2.1) stoplight (2.1.3) streamio-ffmpeg (3.0.2) multi_json (~> 1.8) - strong_migrations (0.2.2) + strong_migrations (0.2.3) activerecord (>= 3.2.0) temple (0.8.0) terminal-table (1.8.0) @@ -597,26 +600,26 @@ GEM tilt (2.0.8) timers (4.1.2) hitimes - tty-color (0.4.2) - tty-command (0.8.0) + tty-color (0.4.3) + tty-command (0.8.2) pastel (~> 0.7.0) - tty-cursor (0.5.0) - tty-prompt (0.16.0) + tty-cursor (0.6.0) + tty-prompt (0.17.0) necromancer (~> 0.4.0) pastel (~> 0.7.0) timers (~> 4.0) - tty-cursor (~> 0.5.0) - tty-reader (~> 0.2.0) - tty-reader (0.2.0) - tty-cursor (~> 0.5.0) + tty-cursor (~> 0.6.0) + tty-reader (~> 0.4.0) + tty-reader (0.4.0) + tty-cursor (~> 0.6.0) tty-screen (~> 0.6.4) wisper (~> 2.0.0) - tty-screen (0.6.4) + tty-screen (0.6.5) twitter-text (1.14.7) unf (~> 0.1.0) tzinfo (1.2.5) thread_safe (~> 0.1) - tzinfo-data (1.2018.4) + tzinfo-data (1.2018.5) tzinfo (>= 1.0.0) unf (0.1.4) unf_ext @@ -659,7 +662,7 @@ DEPENDENCIES browser bullet (~> 5.7) bundler-audit (~> 0.6) - capistrano (~> 3.10) + capistrano (~> 3.11) capistrano-rails (~> 1.3) capistrano-rbenv (~> 2.1) capistrano-yarn (~> 2.0) @@ -669,7 +672,7 @@ DEPENDENCIES cld3 (~> 3.2.0) climate_control (~> 0.2) derailed_benchmarks - devise (~> 4.4) + devise (~> 4.5) devise-two-factor (~> 3.0) devise_pam_authenticatable2 (~> 9.2) doorkeeper (~> 5.0) @@ -703,25 +706,25 @@ DEPENDENCIES mario-redis-lock (~> 1.2) memory_profiler microformats (~> 4.0) - mime-types (~> 3.1) + mime-types (~> 3.2) net-ldap (~> 0.10) nokogiri (~> 1.8) nsa (~> 0.2) - oj (~> 3.5) + oj (~> 3.6) omniauth (~> 1.2) omniauth-cas (~> 1.1) omniauth-saml (~> 1.10) ostatus2 (~> 2.0) - ox (~> 2.9) + ox (~> 2.10) paperclip (~> 6.0) paperclip-av-transcoder (~> 0.6) parallel_tests (~> 2.21) pg (~> 1.0) - pghero (~> 2.1) + pghero (~> 2.2) pkg-config (~> 1.3) posix-spawn! premailer-rails - private_address_check (~> 0.4.1) + private_address_check (~> 0.5) pry-byebug (~> 3.6) pry-rails (~> 0.3) puma (~> 3.11) @@ -743,9 +746,9 @@ DEPENDENCIES ruby-progressbar (~> 1.4) sanitize (~> 4.6) scss_lint (~> 0.57) - sidekiq (~> 5.1) + sidekiq (~> 5.2) sidekiq-bulk (~> 0.1.1) - sidekiq-scheduler (~> 2.2) + sidekiq-scheduler (~> 3.0) sidekiq-unique-jobs (~> 5.0) simple-navigation (~> 4.0) simple_form (~> 4.0) @@ -757,7 +760,7 @@ DEPENDENCIES strong_migrations (~> 0.2) thor (~> 0.20) tty-command (~> 0.8) - tty-prompt (~> 0.16) + tty-prompt (~> 0.17) twitter-text (~> 1.14) tzinfo-data (~> 1.2018) webmock (~> 3.3) diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index 90f42251e..ac8de5fc0 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -53,6 +53,10 @@ class Api::BaseController < ApplicationController [params[:limit].to_i.abs, default_limit * 2].min end + def params_slice(*keys) + params.slice(*keys).permit(*keys) + end + def current_resource_owner @current_user ||= User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token end diff --git a/app/controllers/api/v1/accounts/statuses_controller.rb b/app/controllers/api/v1/accounts/statuses_controller.rb index 06fa6c762..b68a8805f 100644 --- a/app/controllers/api/v1/accounts/statuses_controller.rb +++ b/app/controllers/api/v1/accounts/statuses_controller.rb @@ -28,10 +28,9 @@ class Api::V1::Accounts::StatusesController < Api::BaseController def account_statuses statuses = truthy_param?(:pinned) ? pinned_scope : permitted_account_statuses - statuses = statuses.paginate_by_max_id( + statuses = statuses.paginate_by_id( limit_param(DEFAULT_STATUSES_LIMIT), - params[:max_id], - params[:since_id] + params_slice(:max_id, :since_id, :min_id) ) statuses.merge!(only_media_scope) if truthy_param?(:only_media) @@ -82,7 +81,7 @@ class Api::V1::Accounts::StatusesController < Api::BaseController def prev_path unless @statuses.empty? - api_v1_account_statuses_url pagination_params(since_id: pagination_since_id) + api_v1_account_statuses_url pagination_params(min_id: pagination_since_id) end end diff --git a/app/controllers/api/v1/favourites_controller.rb b/app/controllers/api/v1/favourites_controller.rb index ab5204355..db827f9d4 100644 --- a/app/controllers/api/v1/favourites_controller.rb +++ b/app/controllers/api/v1/favourites_controller.rb @@ -26,10 +26,9 @@ class Api::V1::FavouritesController < Api::BaseController end def results - @_results ||= account_favourites.paginate_by_max_id( + @_results ||= account_favourites.paginate_by_id( limit_param(DEFAULT_STATUSES_LIMIT), - params[:max_id], - params[:since_id] + params_slice(:max_id, :since_id, :min_id) ) end @@ -49,7 +48,7 @@ class Api::V1::FavouritesController < Api::BaseController def prev_path unless results.empty? - api_v1_favourites_url pagination_params(since_id: pagination_since_id) + api_v1_favourites_url pagination_params(min_id: pagination_since_id) end end diff --git a/app/controllers/api/v1/instances_controller.rb b/app/controllers/api/v1/instances_controller.rb index 1c6971c18..5686e8d7c 100644 --- a/app/controllers/api/v1/instances_controller.rb +++ b/app/controllers/api/v1/instances_controller.rb @@ -4,6 +4,8 @@ class Api::V1::InstancesController < Api::BaseController respond_to :json def show - render json: {}, serializer: REST::InstanceSerializer + render_cached_json('api:v1:instances', expires_in: 5.minutes) do + ActiveModelSerializers::SerializableResource.new({}, serializer: REST::InstanceSerializer) + end end end diff --git a/app/controllers/api/v1/notifications_controller.rb b/app/controllers/api/v1/notifications_controller.rb index a8ed5a63b..3b492c516 100644 --- a/app/controllers/api/v1/notifications_controller.rb +++ b/app/controllers/api/v1/notifications_controller.rb @@ -46,10 +46,9 @@ class Api::V1::NotificationsController < Api::BaseController end def paginated_notifications - browserable_account_notifications.paginate_by_max_id( + browserable_account_notifications.paginate_by_id( limit_param(DEFAULT_NOTIFICATIONS_LIMIT), - params[:max_id], - params[:since_id] + params_slice(:max_id, :since_id, :min_id) ) end @@ -73,7 +72,7 @@ class Api::V1::NotificationsController < Api::BaseController def prev_path unless @notifications.empty? - api_v1_notifications_url pagination_params(since_id: pagination_since_id) + api_v1_notifications_url pagination_params(min_id: pagination_since_id) end end diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb index a954101cb..9c6ee0a50 100644 --- a/app/controllers/api/v1/reports_controller.rb +++ b/app/controllers/api/v1/reports_controller.rb @@ -7,11 +7,6 @@ class Api::V1::ReportsController < Api::BaseController respond_to :json - def index - @reports = current_account.reports - render json: @reports, each_serializer: REST::ReportSerializer - end - def create @report = ReportService.new.call( current_account, diff --git a/app/controllers/api/v1/timelines/home_controller.rb b/app/controllers/api/v1/timelines/home_controller.rb index 4412aaaa3..fcd0757f1 100644 --- a/app/controllers/api/v1/timelines/home_controller.rb +++ b/app/controllers/api/v1/timelines/home_controller.rb @@ -30,7 +30,8 @@ class Api::V1::Timelines::HomeController < Api::BaseController account_home_feed.get( limit_param(DEFAULT_STATUSES_LIMIT), params[:max_id], - params[:since_id] + params[:since_id], + params[:min_id] ) end @@ -51,7 +52,7 @@ class Api::V1::Timelines::HomeController < Api::BaseController end def prev_path - api_v1_timelines_home_url pagination_params(since_id: pagination_since_id) + api_v1_timelines_home_url pagination_params(min_id: pagination_since_id) end def pagination_max_id diff --git a/app/controllers/api/v1/timelines/list_controller.rb b/app/controllers/api/v1/timelines/list_controller.rb index cfc5f3b5e..a15eae468 100644 --- a/app/controllers/api/v1/timelines/list_controller.rb +++ b/app/controllers/api/v1/timelines/list_controller.rb @@ -32,7 +32,8 @@ class Api::V1::Timelines::ListController < Api::BaseController list_feed.get( limit_param(DEFAULT_STATUSES_LIMIT), params[:max_id], - params[:since_id] + params[:since_id], + params[:min_id] ) end @@ -53,7 +54,7 @@ class Api::V1::Timelines::ListController < Api::BaseController end def prev_path - api_v1_timelines_list_url params[:id], pagination_params(since_id: pagination_since_id) + api_v1_timelines_list_url params[:id], pagination_params(min_id: pagination_since_id) end def pagination_max_id diff --git a/app/controllers/api/v1/timelines/public_controller.rb b/app/controllers/api/v1/timelines/public_controller.rb index 13fe015b7..aabe24324 100644 --- a/app/controllers/api/v1/timelines/public_controller.rb +++ b/app/controllers/api/v1/timelines/public_controller.rb @@ -21,10 +21,9 @@ class Api::V1::Timelines::PublicController < Api::BaseController end def public_statuses - statuses = public_timeline_statuses.paginate_by_max_id( + statuses = public_timeline_statuses.paginate_by_id( limit_param(DEFAULT_STATUSES_LIMIT), - params[:max_id], - params[:since_id] + params_slice(:max_id, :since_id, :min_id) ) if truthy_param?(:only_media) @@ -53,7 +52,7 @@ class Api::V1::Timelines::PublicController < Api::BaseController end def prev_path - api_v1_timelines_public_url pagination_params(since_id: pagination_since_id) + api_v1_timelines_public_url pagination_params(min_id: pagination_since_id) end def pagination_max_id diff --git a/app/controllers/api/v1/timelines/tag_controller.rb b/app/controllers/api/v1/timelines/tag_controller.rb index 7de49a5ed..cf58d5cf4 100644 --- a/app/controllers/api/v1/timelines/tag_controller.rb +++ b/app/controllers/api/v1/timelines/tag_controller.rb @@ -29,10 +29,9 @@ class Api::V1::Timelines::TagController < Api::BaseController if @tag.nil? [] else - statuses = tag_timeline_statuses.paginate_by_max_id( + statuses = tag_timeline_statuses.paginate_by_id( limit_param(DEFAULT_STATUSES_LIMIT), - params[:max_id], - params[:since_id] + params_slice(:max_id, :since_id, :min_id) ) if truthy_param?(:only_media) @@ -62,7 +61,7 @@ class Api::V1::Timelines::TagController < Api::BaseController end def prev_path - api_v1_timelines_tag_url params[:id], pagination_params(since_id: pagination_since_id) + api_v1_timelines_tag_url params[:id], pagination_params(min_id: pagination_since_id) end def pagination_max_id diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb index d60e6a89f..5c5f31d2b 100644 --- a/app/controllers/settings/preferences_controller.rb +++ b/app/controllers/settings/preferences_controller.rb @@ -37,7 +37,8 @@ class Settings::PreferencesController < Settings::BaseController :setting_favourite_modal, :setting_delete_modal, :setting_auto_play_gif, - :setting_display_sensitive_media, + :setting_display_media, + :setting_expand_spoilers, :setting_reduce_motion, :setting_system_font_ui, :setting_noindex, diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 6b41fd36e..c002017ef 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -7,8 +7,8 @@ module ApplicationHelper follow ).freeze - def active_nav_class(path) - current_page?(path) ? 'active' : '' + def active_nav_class(*paths) + paths.any? { |path| current_page?(path) } ? 'active' : '' end def active_link_to(label, path, **options) diff --git a/app/javascript/flavours/glitch/components/media_gallery.js b/app/javascript/flavours/glitch/components/media_gallery.js index 605a2862b..613318102 100644 --- a/app/javascript/flavours/glitch/components/media_gallery.js +++ b/app/javascript/flavours/glitch/components/media_gallery.js @@ -6,7 +6,7 @@ import IconButton from './icon_button'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { isIOS } from 'flavours/glitch/util/is_mobile'; import classNames from 'classnames'; -import { autoPlayGif, displaySensitiveMedia } from 'flavours/glitch/util/initial_state'; +import { autoPlayGif, displayMedia } from 'flavours/glitch/util/initial_state'; const messages = defineMessages({ hidden: { @@ -226,7 +226,7 @@ export default class MediaGallery extends React.PureComponent { }; state = { - visible: this.props.revealed === undefined ? (!this.props.sensitive || displaySensitiveMedia) : this.props.revealed, + visible: this.props.revealed === undefined ? (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all') : this.props.revealed, }; componentWillReceiveProps (nextProps) { diff --git a/app/javascript/flavours/glitch/features/video/index.js b/app/javascript/flavours/glitch/features/video/index.js index 5cbe01f26..227f298e4 100644 --- a/app/javascript/flavours/glitch/features/video/index.js +++ b/app/javascript/flavours/glitch/features/video/index.js @@ -5,7 +5,7 @@ import { fromJS } from 'immutable'; import { throttle } from 'lodash'; import classNames from 'classnames'; import { isFullscreen, requestFullscreen, exitFullscreen } from 'flavours/glitch/util/fullscreen'; -import { displaySensitiveMedia } from 'flavours/glitch/util/initial_state'; +import { displayMedia } from 'flavours/glitch/util/initial_state'; const messages = defineMessages({ play: { id: 'video.play', defaultMessage: 'Play' }, @@ -114,7 +114,7 @@ export default class Video extends React.PureComponent { fullscreen: false, hovered: false, muted: false, - revealed: this.props.revealed === undefined ? (!this.props.sensitive || displaySensitiveMedia) : this.props.revealed, + revealed: this.props.revealed === undefined ? (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all') : this.props.revealed, }; setPlayerRef = c => { diff --git a/app/javascript/flavours/glitch/styles/about.scss b/app/javascript/flavours/glitch/styles/about.scss index ba46c65c5..f676a8c77 100644 --- a/app/javascript/flavours/glitch/styles/about.scss +++ b/app/javascript/flavours/glitch/styles/about.scss @@ -16,7 +16,7 @@ $small-breakpoint: 960px; } .rich-formatting { - font-family: 'mastodon-font-sans-serif', sans-serif; + font-family: $font-sans-serif, sans-serif; font-size: 16px; font-weight: 400; font-size: 16px; @@ -31,7 +31,7 @@ $small-breakpoint: 960px; p, li { - font-family: 'mastodon-font-sans-serif', sans-serif; + font-family: $font-sans-serif, sans-serif; font-size: 16px; font-weight: 400; font-size: 16px; @@ -62,7 +62,7 @@ $small-breakpoint: 960px; } h1 { - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; font-size: 26px; line-height: 30px; font-weight: 500; @@ -70,7 +70,7 @@ $small-breakpoint: 960px; color: $secondary-text-color; small { - font-family: 'mastodon-font-sans-serif', sans-serif; + font-family: $font-sans-serif, sans-serif; display: block; font-size: 18px; font-weight: 400; @@ -79,7 +79,7 @@ $small-breakpoint: 960px; } h2 { - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; font-size: 22px; line-height: 26px; font-weight: 500; @@ -88,7 +88,7 @@ $small-breakpoint: 960px; } h3 { - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; font-size: 18px; line-height: 24px; font-weight: 500; @@ -97,7 +97,7 @@ $small-breakpoint: 960px; } h4 { - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; font-size: 16px; line-height: 24px; font-weight: 500; @@ -106,7 +106,7 @@ $small-breakpoint: 960px; } h5 { - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; font-size: 14px; line-height: 24px; font-weight: 500; @@ -115,7 +115,7 @@ $small-breakpoint: 960px; } h6 { - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; font-size: 12px; line-height: 24px; font-weight: 500; @@ -180,7 +180,7 @@ $small-breakpoint: 960px; &__section { flex: 1 0 0; - font-family: 'mastodon-font-sans-serif', sans-serif; + font-family: $font-sans-serif, sans-serif; font-size: 16px; line-height: 28px; color: $primary-text-color; @@ -221,7 +221,7 @@ $small-breakpoint: 960px; bottom: -40px; .panel-header { - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; font-size: 14px; line-height: 24px; font-weight: 500; @@ -452,7 +452,7 @@ $small-breakpoint: 960px; p, li { - font-family: 'mastodon-font-sans-serif', sans-serif; + font-family: $font-sans-serif, sans-serif; font-size: 16px; font-weight: 400; font-size: 16px; @@ -501,7 +501,7 @@ $small-breakpoint: 960px; } h1 { - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; font-size: 26px; line-height: 30px; font-weight: 500; @@ -509,7 +509,7 @@ $small-breakpoint: 960px; color: $secondary-text-color; small { - font-family: 'mastodon-font-sans-serif', sans-serif; + font-family: $font-sans-serif, sans-serif; display: block; font-size: 18px; font-weight: 400; @@ -518,7 +518,7 @@ $small-breakpoint: 960px; } h2 { - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; font-size: 22px; line-height: 26px; font-weight: 500; @@ -527,7 +527,7 @@ $small-breakpoint: 960px; } h3 { - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; font-size: 18px; line-height: 24px; font-weight: 500; @@ -536,7 +536,7 @@ $small-breakpoint: 960px; } h4 { - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; font-size: 16px; line-height: 24px; font-weight: 500; @@ -545,7 +545,7 @@ $small-breakpoint: 960px; } h5 { - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; font-size: 14px; line-height: 24px; font-weight: 500; @@ -554,7 +554,7 @@ $small-breakpoint: 960px; } h6 { - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; font-size: 12px; line-height: 24px; font-weight: 500; @@ -621,7 +621,7 @@ $small-breakpoint: 960px; .hero .heading { padding-bottom: 20px; - font-family: 'mastodon-font-sans-serif', sans-serif; + font-family: $font-sans-serif, sans-serif; font-size: 16px; font-weight: 400; font-size: 16px; @@ -672,7 +672,7 @@ $small-breakpoint: 960px; text-decoration: none; padding: 12px 16px; line-height: 32px; - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; font-weight: 500; font-size: 14px; @@ -745,7 +745,7 @@ $small-breakpoint: 960px; .about-short { background: darken($ui-base-color, 4%); padding: 50px 0 30px; - font-family: 'mastodon-font-sans-serif', sans-serif; + font-family: $font-sans-serif, sans-serif; font-size: 16px; font-weight: 400; font-size: 16px; @@ -1015,7 +1015,7 @@ $small-breakpoint: 960px; display: flex; -webkit-overflow-scrolling: touch; -ms-overflow-style: -ms-autohiding-scrollbar; - font-family: 'mastodon-font-sans-serif', sans-serif; + font-family: $font-sans-serif, sans-serif; font-size: 13px; line-height: 18px; font-weight: 400; diff --git a/app/javascript/flavours/glitch/styles/admin.scss b/app/javascript/flavours/glitch/styles/admin.scss index b8cc33039..e16920dd4 100644 --- a/app/javascript/flavours/glitch/styles/admin.scss +++ b/app/javascript/flavours/glitch/styles/admin.scss @@ -443,7 +443,7 @@ $no-columns-breakpoint: 600px; border-radius: 0 0 4px 4px; padding: 10px; color: $darker-text-color; - font-family: 'mastodon-font-monospace', monospace; + font-family: $font-monospace, monospace; font-size: 12px; word-wrap: break-word; min-height: 20px; diff --git a/app/javascript/flavours/glitch/styles/basics.scss b/app/javascript/flavours/glitch/styles/basics.scss index 9c2499ac4..550b7fdfc 100644 --- a/app/javascript/flavours/glitch/styles/basics.scss +++ b/app/javascript/flavours/glitch/styles/basics.scss @@ -6,7 +6,7 @@ } body { - font-family: 'mastodon-font-sans-serif', sans-serif; + font-family: $font-sans-serif, sans-serif; background: darken($ui-base-color, 8%); font-size: 13px; line-height: 18px; @@ -29,8 +29,8 @@ body { // Fira Sans => Firefox OS // Droid Sans => Older Androids (<4.0) // Helvetica Neue => Older macOS <10.11 - // mastodon-font-sans-serif => web-font (Roboto) fallback and newer Androids (>=4.0) - font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", mastodon-font-sans-serif, sans-serif; + // $font-sans-serif => web-font (Roboto) fallback and newer Androids (>=4.0) + font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", $font-sans-serif, sans-serif; } &.app-body { diff --git a/app/javascript/flavours/glitch/styles/containers.scss b/app/javascript/flavours/glitch/styles/containers.scss index d1b9934d7..398458e47 100644 --- a/app/javascript/flavours/glitch/styles/containers.scss +++ b/app/javascript/flavours/glitch/styles/containers.scss @@ -37,7 +37,7 @@ outline: 0; padding: 12px 16px; line-height: 32px; - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; font-weight: 500; font-size: 14px; } @@ -633,7 +633,7 @@ font-size: 18px; margin-bottom: 5px; color: $primary-text-color; - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; } } diff --git a/app/javascript/flavours/glitch/styles/dashboard.scss b/app/javascript/flavours/glitch/styles/dashboard.scss index 949ca733f..86cf6c61b 100644 --- a/app/javascript/flavours/glitch/styles/dashboard.scss +++ b/app/javascript/flavours/glitch/styles/dashboard.scss @@ -35,7 +35,7 @@ font-weight: 500; font-size: 24px; color: $primary-text-color; - font-family: 'mastodon-font-display', sans-serif; + font-family: $font-display, sans-serif; margin-bottom: 20px; } diff --git a/app/javascript/flavours/glitch/styles/forms.scss b/app/javascript/flavours/glitch/styles/forms.scss index cbd3de94c..be2bf7cea 100644 --- a/app/javascript/flavours/glitch/styles/forms.scss +++ b/app/javascript/flavours/glitch/styles/forms.scss @@ -1,7 +1,7 @@ $no-columns-breakpoint: 600px; code { - font-family: 'mastodon-font-monospace', monospace; + font-family: $font-monospace, monospace; font-weight: 400; } @@ -474,7 +474,7 @@ code { width: 100%; border: none; padding: 10px; - font-family: 'mastodon-font-monospace', monospace; + font-family: $font-monospace, monospace; background: $ui-base-color; color: $primary-text-color; font-size: 14px; @@ -718,7 +718,7 @@ code { .form_admin_settings_custom_css, .form_admin_settings_closed_registrations_message { textarea { - font-family: 'mastodon-font-monospace', monospace; + font-family: $font-monospace, monospace; } } @@ -742,7 +742,7 @@ code { border: 0; padding: 10px; font-size: 14px; - font-family: 'mastodon-font-monospace', monospace; + font-family: $font-monospace, monospace; } button { diff --git a/app/javascript/flavours/glitch/styles/rtl.scss b/app/javascript/flavours/glitch/styles/rtl.scss index b8c0efad8..23953304a 100644 --- a/app/javascript/flavours/glitch/styles/rtl.scss +++ b/app/javascript/flavours/glitch/styles/rtl.scss @@ -145,6 +145,19 @@ body.rtl { margin-right: 6px; } + .status__action-bar { + + &__counter { + margin-right: 0; + margin-left: 11px; + + .status__action-bar-button { + margin-right: 0; + margin-left: 4px; + } + } + } + .status__action-bar-button { float: right; margin-right: 0; @@ -285,4 +298,13 @@ body.rtl { } } } + + .public-layout { + .header { + .nav-button { + margin-left: 8px; + margin-right: 0; + } + } + } } diff --git a/app/javascript/flavours/glitch/styles/tables.scss b/app/javascript/flavours/glitch/styles/tables.scss index fa876e603..9fd0b95bb 100644 --- a/app/javascript/flavours/glitch/styles/tables.scss +++ b/app/javascript/flavours/glitch/styles/tables.scss @@ -90,7 +90,7 @@ } samp { - font-family: 'mastodon-font-monospace', monospace; + font-family: $font-monospace, monospace; } button.table-action-link { diff --git a/app/javascript/flavours/glitch/styles/variables.scss b/app/javascript/flavours/glitch/styles/variables.scss index 715ecf98f..1ed1a5778 100644 --- a/app/javascript/flavours/glitch/styles/variables.scss +++ b/app/javascript/flavours/glitch/styles/variables.scss @@ -51,6 +51,10 @@ $media-modal-media-max-height: 80%; $no-gap-breakpoint: 415px; +$font-sans-serif: 'mastodon-font-sans-serif' !default; +$font-display: 'mastodon-font-display' !default; +$font-monospace: 'mastodon-font-monospace' !default; + // Avatar border size (8% default, 100% for rounded avatars) $ui-avatar-border-size: 8%; diff --git a/app/javascript/flavours/glitch/util/initial_state.js b/app/javascript/flavours/glitch/util/initial_state.js index fdf004527..0aaf65904 100644 --- a/app/javascript/flavours/glitch/util/initial_state.js +++ b/app/javascript/flavours/glitch/util/initial_state.js @@ -14,6 +14,7 @@ const getMeta = (prop) => initialState && initialState.meta && initialState.meta export const reduceMotion = getMeta('reduce_motion'); export const autoPlayGif = getMeta('auto_play_gif'); export const displaySensitiveMedia = getMeta('display_sensitive_media'); +export const displayMedia = getMeta('display_media') || (getMeta('display_sensitive_media') ? 'show_all' : 'default'); export const unfollowModal = getMeta('unfollow_modal'); export const boostModal = getMeta('boost_modal'); export const favouriteModal = getMeta('favourite_modal'); diff --git a/app/javascript/mastodon/actions/importer/normalizer.js b/app/javascript/mastodon/actions/importer/normalizer.js index 10a39e050..a2af3222e 100644 --- a/app/javascript/mastodon/actions/importer/normalizer.js +++ b/app/javascript/mastodon/actions/importer/normalizer.js @@ -1,6 +1,7 @@ import escapeTextContentForBrowser from 'escape-html'; import emojify from '../../features/emoji/emoji'; import { unescapeHTML } from '../../utils/html'; +import { expandSpoilers } from '../../initial_state'; const domParser = new DOMParser(); @@ -57,7 +58,7 @@ export function normalizeStatus(status, normalOldStatus) { normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent; normalStatus.contentHtml = emojify(normalStatus.content, emojiMap); normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap); - normalStatus.hidden = spoilerText.length > 0 || normalStatus.sensitive; + normalStatus.hidden = expandSpoilers ? false : spoilerText.length > 0 || normalStatus.sensitive; } return normalStatus; diff --git a/app/javascript/mastodon/components/__tests__/__snapshots__/autosuggest_emoji-test.js.snap b/app/javascript/mastodon/components/__tests__/__snapshots__/autosuggest_emoji-test.js.snap new file mode 100644 index 000000000..1c3727848 --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/__snapshots__/autosuggest_emoji-test.js.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` renders emoji with custom url 1`] = ` +
+ foobar + :foobar: +
+`; + +exports[` renders native emoji 1`] = ` +
+ 💙 + :foobar: +
+`; diff --git a/app/javascript/mastodon/components/__tests__/autosuggest_emoji-test.js b/app/javascript/mastodon/components/__tests__/autosuggest_emoji-test.js new file mode 100644 index 000000000..05616e444 --- /dev/null +++ b/app/javascript/mastodon/components/__tests__/autosuggest_emoji-test.js @@ -0,0 +1,29 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import AutosuggestEmoji from '../autosuggest_emoji'; + +describe('', () => { + it('renders native emoji', () => { + const emoji = { + native: '💙', + colons: ':foobar:', + }; + const component = renderer.create(); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); + + it('renders emoji with custom url', () => { + const emoji = { + custom: true, + imageUrl: 'http://example.com/emoji.png', + native: 'foobar', + colons: ':foobar:', + }; + const component = renderer.create(); + const tree = component.toJSON(); + + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/app/javascript/mastodon/components/media_gallery.js b/app/javascript/mastodon/components/media_gallery.js index a1785196f..ed0e4ff1b 100644 --- a/app/javascript/mastodon/components/media_gallery.js +++ b/app/javascript/mastodon/components/media_gallery.js @@ -6,7 +6,7 @@ import IconButton from './icon_button'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { isIOS } from '../is_mobile'; import classNames from 'classnames'; -import { autoPlayGif, displaySensitiveMedia } from '../initial_state'; +import { autoPlayGif, displayMedia } from '../initial_state'; const messages = defineMessages({ toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Toggle visibility' }, @@ -197,7 +197,7 @@ class MediaGallery extends React.PureComponent { }; state = { - visible: !this.props.sensitive || displaySensitiveMedia, + visible: displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all', }; componentWillReceiveProps (nextProps) { diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js index 6c595c712..90c689a75 100644 --- a/app/javascript/mastodon/components/status.js +++ b/app/javascript/mastodon/components/status.js @@ -285,7 +285,7 @@ class Status extends ImmutablePureComponent { - + {media} diff --git a/app/javascript/mastodon/components/status_content.js b/app/javascript/mastodon/components/status_content.js index 81013747e..eda7d6ac3 100644 --- a/app/javascript/mastodon/components/status_content.js +++ b/app/javascript/mastodon/components/status_content.js @@ -6,6 +6,8 @@ import { FormattedMessage } from 'react-intl'; import Permalink from './permalink'; import classnames from 'classnames'; +const MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top) + export default class StatusContent extends React.PureComponent { static contextTypes = { @@ -17,10 +19,12 @@ export default class StatusContent extends React.PureComponent { expanded: PropTypes.bool, onExpandedToggle: PropTypes.func, onClick: PropTypes.func, + collapsable: PropTypes.bool, }; state = { hidden: true, + collapsed: null, // `collapsed: null` indicates that an element doesn't need collapsing, while `true` or `false` indicates that it does (and is/isn't). }; _updateStatusLinks () { @@ -53,6 +57,16 @@ export default class StatusContent extends React.PureComponent { link.setAttribute('target', '_blank'); link.setAttribute('rel', 'noopener'); } + + if ( + this.props.collapsable + && this.props.onClick + && this.state.collapsed === null + && node.clientHeight > MAX_HEIGHT + && this.props.status.get('spoiler_text').length === 0 + ) { + this.setState({ collapsed: true }); + } } componentDidMount () { @@ -113,6 +127,11 @@ export default class StatusContent extends React.PureComponent { } } + handleCollapsedClick = (e) => { + e.preventDefault(); + this.setState({ collapsed: !this.state.collapsed }); + } + setRef = (c) => { this.node = c; } @@ -132,12 +151,19 @@ export default class StatusContent extends React.PureComponent { const classNames = classnames('status__content', { 'status__content--with-action': this.props.onClick && this.context.router, 'status__content--with-spoiler': status.get('spoiler_text').length > 0, + 'status__content--collapsed': this.state.collapsed === true, }); if (isRtl(status.get('search_index'))) { directionStyle.direction = 'rtl'; } + const readMoreButton = ( + + ); + if (status.get('spoiler_text').length > 0) { let mentionsPlaceholder = ''; @@ -167,17 +193,23 @@ export default class StatusContent extends React.PureComponent { ); } else if (this.props.onClick) { - return ( + const output = [
- ); + />, + ]; + + if (this.state.collapsed) { + output.push(readMoreButton); + } + + return output; } else { return (
{ diff --git a/app/javascript/mastodon/features/notifications/components/column_settings.js b/app/javascript/mastodon/features/notifications/components/column_settings.js index d9638aaf3..fcdf5c6e6 100644 --- a/app/javascript/mastodon/features/notifications/components/column_settings.js +++ b/app/javascript/mastodon/features/notifications/components/column_settings.js @@ -27,7 +27,6 @@ export default class ColumnSettings extends React.PureComponent { const showPushSettings = pushSettings.get('browserSupport') && pushSettings.get('isSubscribed'); const pushStr = showPushSettings && ; - const pushMeta = showPushSettings && ; return (
@@ -40,7 +39,7 @@ export default class ColumnSettings extends React.PureComponent {
- {showPushSettings && } + {showPushSettings && }
@@ -51,7 +50,7 @@ export default class ColumnSettings extends React.PureComponent {
- {showPushSettings && } + {showPushSettings && }
@@ -62,7 +61,7 @@ export default class ColumnSettings extends React.PureComponent {
- {showPushSettings && } + {showPushSettings && }
@@ -73,7 +72,7 @@ export default class ColumnSettings extends React.PureComponent {
- {showPushSettings && } + {showPushSettings && }
diff --git a/app/javascript/mastodon/features/notifications/components/notification.js b/app/javascript/mastodon/features/notifications/components/notification.js index ed4a44ca6..8df6830c5 100644 --- a/app/javascript/mastodon/features/notifications/components/notification.js +++ b/app/javascript/mastodon/features/notifications/components/notification.js @@ -85,8 +85,9 @@ class Notification extends ImmutablePureComponent {
- - + + +