about summary refs log tree commit diff
path: root/app/views
diff options
context:
space:
mode:
authorDavid Yip <yipdw@member.fsf.org>2018-05-03 17:23:44 -0500
committerDavid Yip <yipdw@member.fsf.org>2018-05-03 17:23:44 -0500
commitc816701550d7cdb593371dc47d0b9430c78308b0 (patch)
treecc4417d14de20e69fd5f9a58d66f84af4a623329 /app/views
parent3a47842223ff93d8c057f804809f1b111dfd6f76 (diff)
parenta7e71bbd08e089938fbf20ddef5768c2f3ee0702 (diff)
Merge remote-tracking branch 'origin/master' into gs-master
  Conflicts:
 	.travis.yml
 	Gemfile.lock
 	README.md
 	app/controllers/settings/follower_domains_controller.rb
 	app/controllers/statuses_controller.rb
 	app/javascript/mastodon/locales/ja.json
 	app/lib/feed_manager.rb
 	app/models/media_attachment.rb
 	app/models/mute.rb
 	app/models/status.rb
 	app/services/mute_service.rb
 	app/views/home/index.html.haml
 	app/views/stream_entries/_simple_status.html.haml
 	config/locales/ca.yml
 	config/locales/en.yml
 	config/locales/es.yml
 	config/locales/fr.yml
 	config/locales/nl.yml
 	config/locales/pl.yml
 	config/locales/pt-BR.yml
 	config/themes.yml
Diffstat (limited to 'app/views')
-rw-r--r--app/views/admin/action_logs/_action_log.html.haml2
-rw-r--r--app/views/admin/action_logs/index.html.haml3
-rw-r--r--app/views/admin/report_notes/_report_note.html.haml14
-rw-r--r--app/views/admin/reports/_account.html.haml19
-rw-r--r--app/views/admin/reports/_account_details.html.haml20
-rw-r--r--app/views/admin/reports/_action_log.html.haml6
-rw-r--r--app/views/admin/reports/_report.html.haml6
-rw-r--r--app/views/admin/reports/_status.html.haml28
-rw-r--r--app/views/admin/reports/index.html.haml27
-rw-r--r--app/views/admin/reports/show.html.haml117
-rw-r--r--app/views/home/index.html.haml5
-rw-r--r--app/views/stream_entries/_detailed_status.html.haml6
-rw-r--r--app/views/stream_entries/_more.html.haml2
-rw-r--r--app/views/stream_entries/_simple_status.html.haml13
-rw-r--r--app/views/stream_entries/_status.html.haml31
-rw-r--r--app/views/well_known/host_meta/show.xml.ruby16
-rw-r--r--app/views/well_known/webfinger/show.xml.ruby57
17 files changed, 223 insertions, 149 deletions
diff --git a/app/views/admin/action_logs/_action_log.html.haml b/app/views/admin/action_logs/_action_log.html.haml
index ec90961cb..f059814bd 100644
--- a/app/views/admin/action_logs/_action_log.html.haml
+++ b/app/views/admin/action_logs/_action_log.html.haml
@@ -1,4 +1,4 @@
-%li.log-entry
+.log-entry
   .log-entry__header
     .log-entry__avatar
       = image_tag action_log.account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar'
diff --git a/app/views/admin/action_logs/index.html.haml b/app/views/admin/action_logs/index.html.haml
index bb6d7b5d7..a4d3871a9 100644
--- a/app/views/admin/action_logs/index.html.haml
+++ b/app/views/admin/action_logs/index.html.haml
@@ -1,7 +1,6 @@
 - content_for :page_title do
   = t('admin.action_logs.title')
 
-%ul
-  = render @action_logs
+= render @action_logs
 
 = paginate @action_logs
diff --git a/app/views/admin/report_notes/_report_note.html.haml b/app/views/admin/report_notes/_report_note.html.haml
index 1f621e0d3..d34dc3d15 100644
--- a/app/views/admin/report_notes/_report_note.html.haml
+++ b/app/views/admin/report_notes/_report_note.html.haml
@@ -1,9 +1,7 @@
-%li
-  %h4
-    = report_note.account.acct
-    %div{ style: 'float: right' }
-      %time.formatted{ datetime: report_note.created_at.iso8601, title: l(report_note.created_at) }
-        = l report_note.created_at
-      = table_link_to 'trash', t('admin.reports.notes.delete'), admin_report_note_path(report_note), method: :delete if can?(:destroy, report_note)
-  %div{ class: 'report-note__comment' }
+.speech-bubble
+  .speech-bubble__bubble
     = simple_format(h(report_note.content))
+  .speech-bubble__owner
+    = admin_account_link_to report_note.account
+    %time.formatted{ datetime: report_note.created_at.iso8601 }= l report_note.created_at
+    = table_link_to 'trash', t('admin.reports.notes.delete'), admin_report_note_path(report_note), method: :delete if can?(:destroy, report_note)
diff --git a/app/views/admin/reports/_account.html.haml b/app/views/admin/reports/_account.html.haml
new file mode 100644
index 000000000..22b7a0861
--- /dev/null
+++ b/app/views/admin/reports/_account.html.haml
@@ -0,0 +1,19 @@
+- size ||= 36
+
+.account.compact
+  .account__wrapper
+    - if account.nil?
+      .account__display-name
+        .account__avatar-wrapper
+          .account__avatar{ style: "background-image: url(#{full_asset_url('avatars/original/missing.png', skip_pipeline: true)}); width: #{size}px; height: #{size}px; background-size: #{size}px #{size}px" }
+        %span.display-name
+          %strong= t 'about.contact_missing'
+          %span.display-name__account= t 'about.contact_unavailable'
+    - else
+      = link_to TagManager.instance.url_for(account), class: 'account__display-name' do
+        .account__avatar-wrapper
+          .account__avatar{ style: "background-image: url(#{account.avatar.url}); width: #{size}px; height: #{size}px; background-size: #{size}px #{size}px" }
+        %span.display-name
+          %bdi
+            %strong.display-name__html.emojify= display_name(account)
+          %span.display-name__account @#{account.acct}
diff --git a/app/views/admin/reports/_account_details.html.haml b/app/views/admin/reports/_account_details.html.haml
deleted file mode 100644
index a8af39bef..000000000
--- a/app/views/admin/reports/_account_details.html.haml
+++ /dev/null
@@ -1,20 +0,0 @@
-.table-wrapper
-  %table.table
-    %tbody
-      %tr
-        %td= t('admin.reports.account.created_reports')
-        %td= link_to pluralize(account.reports.count, t('admin.reports.account.report')), admin_reports_path(account_id: account.id)
-      %tr
-        %td= t('admin.reports.account.targeted_reports')
-        %td= link_to pluralize(account.targeted_reports.count, t('admin.reports.account.report')), admin_reports_path(target_account_id: account.id)
-      %tr
-        %td= t('admin.reports.account.moderation_notes')
-        %td= link_to pluralize(account.targeted_moderation_notes.count, t('admin.reports.account.note')), admin_reports_path(target_account_id: account.id)
-      - if account.silenced? || account.suspended?
-        %tr
-          %td= t('admin.reports.account.moderation.title')
-          %td
-            - if account.silenced?
-              %p= t('admin.reports.account.moderation.silenced')
-            - if account.suspended?
-              %p= t('admin.reports.account.moderation.suspended')
diff --git a/app/views/admin/reports/_action_log.html.haml b/app/views/admin/reports/_action_log.html.haml
new file mode 100644
index 000000000..024078eb9
--- /dev/null
+++ b/app/views/admin/reports/_action_log.html.haml
@@ -0,0 +1,6 @@
+.speech-bubble.positive
+  .speech-bubble__bubble
+    = t("admin.action_logs.actions.#{action_log.action}_#{action_log.target_type.underscore}", name: content_tag(:span, action_log.account.username, class: 'username'), target: content_tag(:span, log_target(action_log), class: 'target')).html_safe
+  .speech-bubble__owner
+    = admin_account_link_to(action_log.account)
+    %time.formatted{ datetime: action_log.created_at.iso8601 }= l action_log.created_at
diff --git a/app/views/admin/reports/_report.html.haml b/app/views/admin/reports/_report.html.haml
index 84db00ad5..d6c881955 100644
--- a/app/views/admin/reports/_report.html.haml
+++ b/app/views/admin/reports/_report.html.haml
@@ -2,9 +2,9 @@
   %td.id
     = "##{report.id}"
   %td.target
-    = link_to report.target_account.acct, admin_account_path(report.target_account.id)
+    = admin_account_link_to report.target_account
   %td.reporter
-    = link_to report.account.acct, admin_account_path(report.account.id)
+    = admin_account_link_to report.account
   %td
     %div{ title: report.comment }
       = truncate(report.comment, length: 30, separator: ' ')
@@ -21,6 +21,6 @@
     - if report.assigned_account.nil?
       \-
     - else
-      = link_to report.assigned_account.acct, admin_account_path(report.assigned_account.id)
+      = admin_account_link_to report.assigned_account
   %td
     = table_link_to 'circle', t('admin.reports.view'), admin_report_path(report)
diff --git a/app/views/admin/reports/_status.html.haml b/app/views/admin/reports/_status.html.haml
new file mode 100644
index 000000000..137609539
--- /dev/null
+++ b/app/views/admin/reports/_status.html.haml
@@ -0,0 +1,28 @@
+.batch-table__row
+  %label.batch-table__row__select.batch-checkbox
+    = f.check_box :status_ids, { multiple: true, include_hidden: false }, status.id
+  .batch-table__row__content
+    .status__content><
+      - unless status.spoiler_text.blank?
+        %p><
+          %strong= Formatter.instance.format_spoiler(status)
+
+      = Formatter.instance.format(status)
+
+    - unless status.media_attachments.empty?
+      - if status.media_attachments.first.video?
+        - video = status.media_attachments.first
+        = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), sensitive: status.sensitive? && !current_account&.user&.setting_display_sensitive_media, width: 610, height: 343, inline: true
+      - else
+        = react_component :media_gallery, height: 343, sensitive: status.sensitive? && !current_account&.user&.setting_display_sensitive_media, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
+
+    .detailed-status__meta
+      = link_to TagManager.instance.url_for(status), class: 'detailed-status__datetime', target: stream_link_target, rel: 'noopener' do
+        %time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
+      ·
+      = fa_visibility_icon(status)
+      = t("statuses.visibilities.#{status.visibility}")
+      - if status.sensitive?
+        ·
+        = fa_icon('eye-slash fw')
+        = t('stream_entries.sensitive_content')
diff --git a/app/views/admin/reports/index.html.haml b/app/views/admin/reports/index.html.haml
index c3baaf6be..44a531f2c 100644
--- a/app/views/admin/reports/index.html.haml
+++ b/app/views/admin/reports/index.html.haml
@@ -8,20 +8,17 @@
       %li= filter_link_to t('admin.reports.unresolved'), resolved: nil
       %li= filter_link_to t('admin.reports.resolved'), resolved: '1'
 
-= form_tag do
-
-  .table-wrapper
-    %table.table
-      %thead
-        %tr
-          -# %th
-          %th= t('admin.reports.id')
-          %th= t('admin.reports.target')
-          %th= t('admin.reports.reported_by')
-          %th= t('admin.reports.report_contents')
-          %th= t('admin.reports.assigned')
-          %th
-      %tbody
-        = render @reports
+.table-wrapper
+  %table.table
+    %thead
+      %tr
+        %th= t('admin.reports.id')
+        %th= t('admin.reports.target')
+        %th= t('admin.reports.reported_by')
+        %th= t('admin.reports.report_contents')
+        %th= t('admin.reports.assigned')
+        %th
+    %tbody
+      = render @reports
 
 = paginate @reports
diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml
index 60a8cab8e..cbfbdcfa9 100644
--- a/app/views/admin/reports/show.html.haml
+++ b/app/views/admin/reports/show.html.haml
@@ -11,16 +11,28 @@
   - else
     = link_to t('admin.reports.mark_as_unresolved'), admin_report_path(@report, outcome: 'reopen'), method: :put, class: 'button'
 
+%hr.spacer
+
 .table-wrapper
   %table.table.inline-table
     %tbody
       %tr
+        %th= t('admin.reports.reported_account')
+        %td= admin_account_link_to @report.target_account
+        %td= table_link_to 'flag', pluralize(@report.target_account.targeted_reports.count, t('admin.reports.account.report')), admin_reports_path(target_account_id: @report.target_account.id)
+        %td= table_link_to 'file', pluralize(@report.target_account.targeted_moderation_notes.count, t('admin.reports.account.note')), admin_reports_path(target_account_id: @report.target_account.id)
+      %tr
+        %th= t('admin.reports.reported_by')
+        %td= admin_account_link_to @report.account
+        %td= table_link_to 'flag', pluralize(@report.account.targeted_reports.count, t('admin.reports.account.report')), admin_reports_path(target_account_id: @report.account.id)
+        %td= table_link_to 'file', pluralize(@report.account.targeted_moderation_notes.count, t('admin.reports.account.note')), admin_reports_path(target_account_id: @report.account.id)
+      %tr
         %th= t('admin.reports.created_at')
-        %td{colspan: 2}
+        %td{ colspan: 3 }
           %time.formatted{ datetime: @report.created_at.iso8601 }
       %tr
         %th= t('admin.reports.updated_at')
-        %td{colspan: 2}
+        %td{ colspan: 3 }
           %time.formatted{ datetime: @report.updated_at.iso8601 }
       %tr
         %th= t('admin.reports.status')
@@ -29,14 +41,14 @@
             = t('admin.reports.resolved')
           - else
             = t('admin.reports.unresolved')
-        %td{style: "text-align: right; overflow: hidden;"}
+        %td{ colspan: 2 }
           - if @report.action_taken?
             = table_link_to 'envelope-open', t('admin.reports.reopen'), admin_report_path(@report, outcome: 'reopen'), method: :put
       - if !@report.action_taken_by_account.nil?
         %tr
           %th= t('admin.reports.action_taken_by')
-          %td{colspan: 2}
-            = @report.action_taken_by_account.acct
+          %td{ colspan: 3 }
+            = admin_account_link_to @report.action_taken_by_account
       - else
         %tr
           %th= t('admin.reports.assigned')
@@ -44,78 +56,55 @@
             - if @report.assigned_account.nil?
               \-
             - else
-              = link_to @report.assigned_account.acct, admin_account_path(@report.assigned_account.id)
-          %td{style: "text-align: right"}
+              = admin_account_link_to @report.assigned_account
+          %td
             - if @report.assigned_account != current_user.account
               = table_link_to 'user', t('admin.reports.assign_to_self'), admin_report_path(@report, outcome: 'assign_to_self'), method: :put
+          %td
             - if !@report.assigned_account.nil?
               = table_link_to 'trash', t('admin.reports.unassign'), admin_report_path(@report, outcome: 'unassign'), method: :put
 
-%hr{ class: "section-break"}/
-
-.report-accounts
-  .report-accounts__item
-    %h3= t('admin.reports.reported_account')
-    = render 'authorize_follows/card', account: @report.target_account, admin: true
-    = render 'admin/reports/account_details', account: @report.target_account
-  .report-accounts__item
-    %h3= t('admin.reports.reported_by')
-    = render 'authorize_follows/card', account: @report.account, admin: true
-    = render 'admin/reports/account_details', account: @report.account
-
-%h3= t('admin.reports.comment.label')
+%hr.spacer
 
-= simple_format(@report.comment.presence || t('admin.reports.comment.none'))
+.speech-bubble
+  .speech-bubble__bubble= simple_format(@report.comment.presence || t('admin.reports.comment.none'))
+  .speech-bubble__owner
+    = admin_account_link_to @report.account
+    %time.formatted{ datetime: @report.created_at.iso8601 }
 
 - unless @report.statuses.empty?
-  %hr/
-
-  %h3= t('admin.reports.statuses')
+  %hr.spacer/
 
   = form_for(@form, url: admin_report_reported_statuses_path(@report.id)) do |f|
-    .batch-form-box
-      .batch-checkbox-all
-        = check_box_tag :batch_checkbox_all, nil, false
-      = f.select :action, Form::StatusBatch::ACTION_TYPE.map{|action| [t("admin.statuses.batch.#{action}"), action]}
-      = f.submit t('admin.statuses.execute'), data: { confirm: t('admin.reports.are_you_sure') }, class: 'button'
-      .media-spoiler-toggle-buttons
-        .media-spoiler-show-button.button= t('admin.statuses.media.show')
-        .media-spoiler-hide-button.button= t('admin.statuses.media.hide')
-    - @report.statuses.each do |status|
-      .report-status{ data: { id: status.id } }
-        .batch-checkbox
-          = f.check_box :status_ids, { multiple: true, include_hidden: false }, status.id
-        .activity-stream.activity-stream-headless
-          .entry= render 'stream_entries/simple_status', status: status
-        .report-status__actions
-          - unless status.media_attachments.empty?
-            = link_to admin_report_reported_status_path(@report, status, status: { sensitive: !status.sensitive }), method: :put, class: 'icon-button nsfw-button', title: t("admin.reports.nsfw.#{!status.sensitive}") do
-              = fa_icon status.sensitive? ? 'eye' : 'eye-slash'
-          = link_to admin_report_reported_status_path(@report, status), method: :delete, class: 'icon-button trash-button', title: t('admin.reports.delete'), data: { confirm: t('admin.reports.are_you_sure') }, remote: true do
-            = fa_icon 'trash'
-
-%hr{ class: "section-break"}/
+    .batch-table
+      .batch-table__toolbar
+        %label.batch-table__toolbar__select.batch-checkbox-all
+          = check_box_tag :batch_checkbox_all, nil, false
+        .batch-table__toolbar__actions
+          = f.button safe_join([fa_icon('eye-slash'), t('admin.statuses.batch.nsfw_on')]), name: :nsfw_on, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
+          = f.button safe_join([fa_icon('eye'), t('admin.statuses.batch.nsfw_off')]), name: :nsfw_off, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
+          = f.button safe_join([fa_icon('trash'), t('admin.statuses.batch.delete')]), name: :delete, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
+      .batch-table__body
+        = render partial: 'admin/reports/status', collection: @report.statuses, locals: { f: f }
 
-%h3= t('admin.reports.notes.label')
+%hr.spacer/
 
-- if @report_notes.length > 0
-  %ul
-    = render @report_notes
+- @report_notes.each do |item|
+  - if item.is_a?(Admin::ActionLog)
+    = render partial: 'action_log', locals: { action_log: item }
+  - elsif item.is_a?(ReportNote)
+    = render item
 
-%h4= t('admin.reports.notes.new_label')
-= form_for @report_note, url: admin_report_notes_path, html: { class: 'report-note__form' } do |f|
+= simple_form_for @report_note, url: admin_report_notes_path do |f|
   = render 'shared/error_messages', object: @report_note
-  = f.text_area :content, placeholder: t('admin.reports.notes.placeholder'), rows: 6, class: 'report-note__textarea'
-  = f.hidden_field :report_id
-  %div{ class: 'report-note__buttons' }
-    - if @report.unresolved?
-      = f.submit t('admin.reports.notes.create_and_resolve'), name: :create_and_resolve, class: 'button report-note__button'
-    - else
-      = f.submit t('admin.reports.notes.create_and_unresolve'), name: :create_and_unresolve, class: 'button report-note__button'
-    = f.submit t('admin.reports.notes.create'), class: 'button report-note__button'
+  = f.input :report_id, as: :hidden
 
-- if @report_history.length > 0
-  %h3= t('admin.reports.history')
+  .field-group
+    = f.input :content, placeholder: t('admin.reports.notes.placeholder'), rows: 6
 
-  %ul
-    = render @report_history
+  .actions
+    - if @report.unresolved?
+      = f.button :button, t('admin.reports.notes.create_and_resolve'), name: :create_and_resolve, type: :submit
+    - else
+      = f.button :button, t('admin.reports.notes.create_and_unresolve'), name: :create_and_unresolve, type: :submit
+    = f.button :button, t('admin.reports.notes.create'), type: :submit
diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml
index e8a81656c..789de47d1 100644
--- a/app/views/home/index.html.haml
+++ b/app/views/home/index.html.haml
@@ -1,4 +1,9 @@
 - content_for :header_tags do
+  = preload_link_tag asset_pack_path('features/getting_started.js'), crossorigin: 'anonymous'
+  = preload_link_tag asset_pack_path('features/compose.js'), crossorigin: 'anonymous'
+  = preload_link_tag asset_pack_path('features/home_timeline.js'), crossorigin: 'anonymous'
+  = preload_link_tag asset_pack_path('features/notifications.js'), crossorigin: 'anonymous'
+
   %meta{name: 'applicationServerKey', content: Rails.configuration.x.vapid_public_key}
   %script#initial-state{ type: 'application/json' }!= json_escape(@initial_state_json)
 
diff --git a/app/views/stream_entries/_detailed_status.html.haml b/app/views/stream_entries/_detailed_status.html.haml
index e1122d5a2..afc66d148 100644
--- a/app/views/stream_entries/_detailed_status.html.haml
+++ b/app/views/stream_entries/_detailed_status.html.haml
@@ -22,11 +22,11 @@
   - if !status.media_attachments.empty?
     - if status.media_attachments.first.video?
       - video = status.media_attachments.first
-      %div{ data: { component: 'Video', props: Oj.dump(src: video.file.url(:original), preview: video.file.url(:small), sensitive: status.sensitive? && !current_account&.user&.setting_display_sensitive_media, width: 670, height: 380, detailed: true, inline: true) }}
+      = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), sensitive: status.sensitive? && !current_account&.user&.setting_display_sensitive_media, width: 670, height: 380, detailed: true, inline: true
     - else
-      %div{ data: { component: 'MediaGallery', props: Oj.dump(height: 380, sensitive: status.sensitive? && !current_account&.user&.setting_display_sensitive_media, standalone: true, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, 'reduceMotion': current_account&.user&.setting_reduce_motion, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }) }}
+      = react_component :media_gallery, height: 380, sensitive: status.sensitive? && !current_account&.user&.setting_display_sensitive_media, standalone: true, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, 'reduceMotion': current_account&.user&.setting_reduce_motion, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
   - elsif status.preview_cards.first
-    %div{ data: { component: 'Card', props: Oj.dump('maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_cards.first, serializer: REST::PreviewCardSerializer).as_json) }}
+    = react_component :card, 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_cards.first, serializer: REST::PreviewCardSerializer).as_json
 
   .detailed-status__meta
     %data.dt-published{ value: status.created_at.to_time.iso8601 }
diff --git a/app/views/stream_entries/_more.html.haml b/app/views/stream_entries/_more.html.haml
new file mode 100644
index 000000000..9b1dfe4a7
--- /dev/null
+++ b/app/views/stream_entries/_more.html.haml
@@ -0,0 +1,2 @@
+= link_to url, class: 'more light'  do
+  = t('statuses.show_more')
diff --git a/app/views/stream_entries/_simple_status.html.haml b/app/views/stream_entries/_simple_status.html.haml
index 2ad1f5120..cc2b6abe8 100644
--- a/app/views/stream_entries/_simple_status.html.haml
+++ b/app/views/stream_entries/_simple_status.html.haml
@@ -20,9 +20,10 @@
         %a.status__content__spoiler-link{ href: '#' }= t('statuses.show_more')
     .e-content{ lang: status.language, style: "display: #{status.spoiler_text? ? 'none' : 'block'}; direction: #{rtl_status?(status) ? 'rtl' : 'ltr'}" }<
       = Formatter.instance.format(status, custom_emojify: true)
-      - unless status.media_attachments.empty?
-        - if status.media_attachments.first.video?
-          - video = status.media_attachments.first
-          %div{ data: { component: 'Video', props: Oj.dump(src: video.file.url(:original), preview: video.file.url(:small), sensitive: status.sensitive? && !current_account&.user&.setting_display_sensitive_media, width: 610, height: 343) }}
-        - else
-          %div{ data: { component: 'MediaGallery', props: Oj.dump(height: 343, sensitive: status.sensitive? && !current_account&.user&.setting_display_sensitive_media, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }) }}
+
+  - unless status.media_attachments.empty?
+    - if status.media_attachments.first.video?
+      - video = status.media_attachments.first
+      = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), sensitive: status.sensitive? && !current_account&.user&.setting_display_sensitive_media, width: 610, height: 343, inline: true
+    - else
+      = react_component :media_gallery, height: 343, sensitive: status.sensitive? && !current_account&.user&.setting_display_sensitive_media, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
diff --git a/app/views/stream_entries/_status.html.haml b/app/views/stream_entries/_status.html.haml
index 2d0dafcb7..9764bc74d 100644
--- a/app/views/stream_entries/_status.html.haml
+++ b/app/views/stream_entries/_status.html.haml
@@ -5,19 +5,19 @@
   is_successor    ||= false
   direct_reply_id ||= false
   parent_id       ||= false
-  is_direct_parent = direct_reply_id == status.id
-  is_direct_child  = parent_id == status.in_reply_to_id
-  centered ||= include_threads && !is_predecessor && !is_successor
-  h_class       = microformats_h_class(status, is_predecessor, is_successor, include_threads)
-  style_classes = style_classes(status, is_predecessor, is_successor, include_threads)
-  mf_classes    = microformats_classes(status, is_direct_parent, is_direct_child)
-  entry_classes = h_class + ' ' + mf_classes + ' ' + style_classes
+  is_direct_parent  = direct_reply_id == status.id
+  is_direct_child   = parent_id == status.in_reply_to_id
+  centered        ||= include_threads && !is_predecessor && !is_successor
+  h_class           = microformats_h_class(status, is_predecessor, is_successor, include_threads)
+  style_classes     = style_classes(status, is_predecessor, is_successor, include_threads)
+  mf_classes        = microformats_classes(status, is_direct_parent, is_direct_child)
+  entry_classes     = h_class + ' ' + mf_classes + ' ' + style_classes
 
 - if status.reply? && include_threads
   - if @next_ancestor
     .entry{ class: entry_classes }
-      = link_to short_account_status_url(@next_ancestor.account.username, @next_ancestor), class: 'more light'  do
-        = t('statuses.show_more')
+      = render 'stream_entries/more', url: TagManager.instance.url_for(@next_ancestor)
+
   = render partial: 'stream_entries/status', collection: @ancestors, as: :status, locals: { is_predecessor: true, direct_reply_id: status.in_reply_to_id }
 
 .entry{ class: entry_classes }
@@ -40,4 +40,15 @@
   = render (centered ? 'stream_entries/detailed_status' : 'stream_entries/simple_status'), status: status.proper
 
 - if include_threads
-  = render partial: 'stream_entries/status', collection: @descendants, as: :status, locals: { is_successor: true, parent_id: status.id }
+  - if @since_descendant_thread_id
+    .entry{ class: entry_classes }
+      = render 'stream_entries/more', url: short_account_status_url(status.account.username, status, max_descendant_thread_id: @since_descendant_thread_id + 1)
+  - @descendant_threads.each do |thread|
+    = render partial: 'stream_entries/status', collection: thread[:statuses], as: :status, locals: { is_successor: true, parent_id: status.id }
+
+    - if thread[:next_status]
+      .entry{ class: entry_classes }
+        = render 'stream_entries/more', url: TagManager.instance.url_for(thread[:next_status])
+  - if @next_descendant_thread
+    .entry{ class: entry_classes }
+      = render 'stream_entries/more', url: short_account_status_url(status.account.username, status, since_descendant_thread_id: @max_descendant_thread_id - 1)
diff --git a/app/views/well_known/host_meta/show.xml.ruby b/app/views/well_known/host_meta/show.xml.ruby
index 07d026471..0a6bdc322 100644
--- a/app/views/well_known/host_meta/show.xml.ruby
+++ b/app/views/well_known/host_meta/show.xml.ruby
@@ -1,5 +1,13 @@
-Nokogiri::XML::Builder.new do |xml|
-  xml.XRD(xmlns: 'http://docs.oasis-open.org/ns/xri/xrd-1.0') do
-    xml.Link(rel: 'lrdd', type: 'application/xrd+xml', template: @webfinger_template)
+doc = Ox::Document.new(version: '1.0')
+
+doc << Ox::Element.new('XRD').tap do |xrd|
+  xrd['xmlns'] = 'http://docs.oasis-open.org/ns/xri/xrd-1.0'
+
+  xrd << Ox::Element.new('Link').tap do |link|
+    link['rel']      = 'lrdd'
+    link['type']     = 'application/xrd+xml'
+    link['template'] = @webfinger_template
   end
-end.to_xml
+end
+
+('<?xml version="1.0" encoding="UTF-8"?>' + Ox.dump(doc, effort: :tolerant)).force_encoding('UTF-8')
diff --git a/app/views/well_known/webfinger/show.xml.ruby b/app/views/well_known/webfinger/show.xml.ruby
index 0c7289d6a..4352a24e9 100644
--- a/app/views/well_known/webfinger/show.xml.ruby
+++ b/app/views/well_known/webfinger/show.xml.ruby
@@ -1,13 +1,44 @@
-Nokogiri::XML::Builder.new do |xml|
-  xml.XRD(xmlns: 'http://docs.oasis-open.org/ns/xri/xrd-1.0') do
-    xml.Subject @account.to_webfinger_s
-    xml.Alias short_account_url(@account)
-    xml.Alias account_url(@account)
-    xml.Link(rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: short_account_url(@account))
-    xml.Link(rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: account_url(@account, format: 'atom'))
-    xml.Link(rel: 'self', type: 'application/activity+json', href: account_url(@account))
-    xml.Link(rel: 'salmon', href: api_salmon_url(@account.id))
-    xml.Link(rel: 'magic-public-key', href: "data:application/magic-public-key,#{@account.magic_key}")
-    xml.Link(rel: 'http://ostatus.org/schema/1.0/subscribe', template: "#{authorize_follow_url}?acct={uri}")
-  end
-end.to_xml
+doc = Ox::Document.new(version: '1.0')
+
+doc << Ox::Element.new('XRD').tap do |xrd|
+  xrd['xmlns'] = 'http://docs.oasis-open.org/ns/xri/xrd-1.0'
+
+  xrd << (Ox::Element.new('Subject') << @account.to_webfinger_s)
+  xrd << (Ox::Element.new('Alias') << short_account_url(@account))
+  xrd << (Ox::Element.new('Alias') << account_url(@account))
+
+  xrd << Ox::Element.new('Link').tap do |link|
+    link['rel']      = 'http://webfinger.net/rel/profile-page'
+    link['type']     = 'text/html'
+    link['href']     = short_account_url(@account)
+  end
+
+  xrd << Ox::Element.new('Link').tap do |link|
+    link['rel']      = 'http://schemas.google.com/g/2010#updates-from'
+    link['type']     = 'application/atom+xml'
+    link['href']     = account_url(@account, format: 'atom')
+  end
+
+  xrd << Ox::Element.new('Link').tap do |link|
+    link['rel']      = 'self'
+    link['type']     = 'application/activity+json'
+    link['href']     = account_url(@account)
+  end
+
+  xrd << Ox::Element.new('Link').tap do |link|
+    link['rel']      = 'salmon'
+    link['href']     = api_salmon_url(@account.id)
+  end
+
+  xrd << Ox::Element.new('Link').tap do |link|
+    link['rel']      = 'magic-public-key'
+    link['href']     = "data:application/magic-public-key,#{@account.magic_key}"
+  end
+
+  xrd << Ox::Element.new('Link').tap do |link|
+    link['rel']      = 'http://ostatus.org/schema/1.0/subscribe'
+    link['template'] = "#{authorize_follow_url}?acct={uri}"
+  end
+end
+
+('<?xml version="1.0" encoding="UTF-8"?>' + Ox.dump(doc, effort: :tolerant)).force_encoding('UTF-8')