Change about page to be mounted in the web UI (#19345)
parent
b04633a961
commit
1bd00036c2
@ -1,63 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class AboutController < ApplicationController
|
||||
include RegistrationSpamConcern
|
||||
include WebAppControllerConcern
|
||||
|
||||
layout 'public'
|
||||
skip_before_action :require_functional!
|
||||
|
||||
before_action :require_open_federation!, only: [:more]
|
||||
before_action :set_body_classes, only: :show
|
||||
before_action :set_instance_presenter
|
||||
before_action :set_expires_in, only: [:more]
|
||||
|
||||
skip_before_action :require_functional!, only: [:more]
|
||||
|
||||
def more
|
||||
flash.now[:notice] = I18n.t('about.instance_actor_flash') if params[:instance_actor]
|
||||
|
||||
toc_generator = TOCGenerator.new(@instance_presenter.extended_description)
|
||||
|
||||
@rules = Rule.ordered
|
||||
@contents = toc_generator.html
|
||||
@table_of_contents = toc_generator.toc
|
||||
@blocks = DomainBlock.with_user_facing_limitations.by_severity if display_blocks?
|
||||
end
|
||||
|
||||
helper_method :display_blocks?
|
||||
helper_method :display_blocks_rationale?
|
||||
helper_method :public_fetch_mode?
|
||||
helper_method :new_user
|
||||
|
||||
private
|
||||
|
||||
def require_open_federation!
|
||||
not_found if whitelist_mode?
|
||||
end
|
||||
|
||||
def display_blocks?
|
||||
Setting.show_domain_blocks == 'all' || (Setting.show_domain_blocks == 'users' && user_signed_in?)
|
||||
end
|
||||
|
||||
def display_blocks_rationale?
|
||||
Setting.show_domain_blocks_rationale == 'all' || (Setting.show_domain_blocks_rationale == 'users' && user_signed_in?)
|
||||
end
|
||||
|
||||
def new_user
|
||||
User.new.tap do |user|
|
||||
user.build_account
|
||||
user.build_invite_request
|
||||
end
|
||||
end
|
||||
|
||||
def set_instance_presenter
|
||||
@instance_presenter = InstancePresenter.new
|
||||
end
|
||||
|
||||
def set_body_classes
|
||||
@hide_navbar = true
|
||||
end
|
||||
|
||||
def set_expires_in
|
||||
expires_in 0, public: true
|
||||
def show
|
||||
expires_in 0, public: true unless user_signed_in?
|
||||
end
|
||||
end
|
||||
|
@ -0,0 +1,23 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Instances::DomainBlocksController < Api::BaseController
|
||||
skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
|
||||
|
||||
before_action :require_enabled_api!
|
||||
before_action :set_domain_blocks
|
||||
|
||||
def index
|
||||
expires_in 3.minutes, public: true
|
||||
render json: @domain_blocks, each_serializer: REST::DomainBlockSerializer, with_comment: (Setting.show_domain_blocks_rationale == 'all' || (Setting.show_domain_blocks_rationale == 'users' && user_signed_in?))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def require_enabled_api!
|
||||
head 404 unless Setting.show_domain_blocks == 'all' || (Setting.show_domain_blocks == 'users' && user_signed_in?)
|
||||
end
|
||||
|
||||
def set_domain_blocks
|
||||
@domain_blocks = DomainBlock.with_user_facing_limitations.by_severity
|
||||
end
|
||||
end
|
@ -0,0 +1,18 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::Instances::ExtendedDescriptionsController < Api::BaseController
|
||||
skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
|
||||
|
||||
before_action :set_extended_description
|
||||
|
||||
def show
|
||||
expires_in 3.minutes, public: true
|
||||
render json: @extended_description, serializer: REST::ExtendedDescriptionSerializer
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_extended_description
|
||||
@extended_description = ExtendedDescription.current
|
||||
end
|
||||
end
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,33 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Blurhash from './blurhash';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export default class Image extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
src: PropTypes.string,
|
||||
srcSet: PropTypes.string,
|
||||
blurhash: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
state = {
|
||||
loaded: false,
|
||||
};
|
||||
|
||||
handleLoad = () => this.setState({ loaded: true });
|
||||
|
||||
render () {
|
||||
const { src, srcSet, blurhash, className } = this.props;
|
||||
const { loaded } = this.state;
|
||||
|
||||
return (
|
||||
<div className={classNames('image', { loaded }, className)} role='presentation'>
|
||||
{blurhash && <Blurhash hash={blurhash} className='image__preview' />}
|
||||
<img src={src} srcSet={srcSet} alt='' onLoad={this.handleLoad} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
@font-face {
|
||||
font-family: mastodon-font-display;
|
||||
src:
|
||||
local('Montserrat'),
|
||||
url('../fonts/montserrat/Montserrat-Regular.woff2') format('woff2'),
|
||||
url('../fonts/montserrat/Montserrat-Regular.woff') format('woff'),
|
||||
url('../fonts/montserrat/Montserrat-Regular.ttf') format('truetype');
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: mastodon-font-display;
|
||||
src:
|
||||
local('Montserrat Medium'),
|
||||
url('../fonts/montserrat/Montserrat-Medium.ttf') format('truetype');
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
font-style: normal;
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
.compact-header {
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
line-height: 28px;
|
||||
color: $darker-text-color;
|
||||
font-weight: 500;
|
||||
margin-bottom: 20px;
|
||||
padding: 0 10px;
|
||||
word-wrap: break-word;
|
||||
|
||||
@media screen and (max-width: 740px) {
|
||||
text-align: center;
|
||||
padding: 20px 10px 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
small {
|
||||
font-weight: 400;
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
|
||||
img {
|
||||
display: inline-block;
|
||||
margin-bottom: -5px;
|
||||
margin-right: 15px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ExtendedDescription < ActiveModelSerializers::Model
|
||||
attributes :updated_at, :text
|
||||
|
||||
def self.current
|
||||
custom = Setting.find_by(var: 'site_extended_description')
|
||||
|
||||
if custom&.value.present?
|
||||
new(text: custom.value, updated_at: custom.updated_at)
|
||||
else
|
||||
new
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class REST::DomainBlockSerializer < ActiveModel::Serializer
|
||||
attributes :domain, :digest, :severity, :comment
|
||||
|
||||
def domain
|
||||
object.public_domain
|
||||
end
|
||||
|
||||
def digest
|
||||
object.domain_digest
|
||||
end
|
||||
|
||||
def comment
|
||||
object.public_comment if instance_options[:with_comment]
|
||||
end
|
||||
end
|
@ -0,0 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class REST::ExtendedDescriptionSerializer < ActiveModel::Serializer
|
||||
attributes :updated_at, :content
|
||||
|
||||
def updated_at
|
||||
object.updated_at&.iso8601
|
||||
end
|
||||
|
||||
def content
|
||||
object.text
|
||||
end
|
||||
end
|
@ -1,12 +0,0 @@
|
||||
%table
|
||||
%thead
|
||||
%tr
|
||||
%th= t('about.unavailable_content_description.domain')
|
||||
%th= t('about.unavailable_content_description.reason')
|
||||
%tbody
|
||||
- domain_blocks.each do |domain_block|
|
||||
%tr
|
||||
%td.nowrap
|
||||
%span{ title: "SHA-256: #{domain_block.domain_digest}" }= domain_block.public_domain
|
||||
%td
|
||||
= domain_block.public_comment if display_blocks_rationale?
|
@ -1,96 +0,0 @@
|
||||
- content_for :page_title do
|
||||
= site_hostname
|
||||
|
||||
- content_for :header_tags do
|
||||
= javascript_pack_tag 'public', crossorigin: 'anonymous'
|
||||
= render partial: 'shared/og'
|
||||
|
||||
.grid-4
|
||||
.column-0
|
||||
.public-account-header.public-account-header--no-bar
|
||||
.public-account-header__image
|
||||
= image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url || asset_pack_path('media/images/preview.png'), alt: @instance_presenter.title, class: 'parallax'
|
||||
|
||||
.column-1
|
||||
.landing-page__call-to-action{ dir: 'ltr' }
|
||||
.row
|
||||
.row__information-board
|
||||
.information-board__section
|
||||
%span= t 'about.user_count_before'
|
||||
%strong= friendly_number_to_human @instance_presenter.user_count
|
||||
%span= t 'about.user_count_after', count: @instance_presenter.user_count
|
||||
.information-board__section
|
||||
%span= t 'about.status_count_before'
|
||||
%strong= friendly_number_to_human @instance_presenter.status_count
|
||||
%span= t 'about.status_count_after', count: @instance_presenter.status_count
|
||||
.row__mascot
|
||||
.landing-page__mascot
|
||||
= image_tag @instance_presenter.mascot&.file&.url || asset_pack_path('media/images/elephant_ui_plane.svg'), alt: ''
|
||||
|
||||
.column-2
|
||||
.contact-widget
|
||||
%h4= t 'about.administered_by'
|
||||
|
||||
= account_link_to(@instance_presenter.contact.account)
|
||||
|
||||
- if @instance_presenter.contact.email.present?
|
||||
%h4
|
||||
= succeed ':' do
|
||||
= t 'about.contact'
|
||||
|
||||
= mail_to @instance_presenter.contact.email, nil, title: @instance_presenter.contact.email
|
||||
|
||||
.column-3
|
||||
= render 'application/flashes'
|
||||
|
||||
- if @contents.blank? && @rules.empty? && (!display_blocks? || @blocks&.empty?)
|
||||
= nothing_here
|
||||
- else
|
||||
.box-widget
|
||||
.rich-formatting
|
||||
- unless @rules.empty?
|
||||
%h2#rules= t('about.rules')
|
||||
|
||||
%p= t('about.rules_html')
|
||||
|
||||
%ol.rules-list
|
||||
- @rules.each do |rule|
|
||||
%li
|
||||
.rules-list__text= rule.text
|
||||
|
||||
= @contents.html_safe
|
||||
|
||||
- if display_blocks? && !@blocks.empty?
|
||||
%h2#unavailable-content= t('about.unavailable_content')
|
||||
|
||||
%p= t('about.unavailable_content_html')
|
||||
|
||||
- if (blocks = @blocks.select(&:reject_media?)) && !blocks.empty?
|
||||
%h3= t('about.unavailable_content_description.rejecting_media_title')
|
||||
%p= t('about.unavailable_content_description.rejecting_media')
|
||||
= render partial: 'domain_blocks', locals: { domain_blocks: blocks }
|
||||
- if (blocks = @blocks.select(&:silence?)) && !blocks.empty?
|
||||
%h3= t('about.unavailable_content_description.silenced_title')
|
||||
%p= t('about.unavailable_content_description.silenced')
|
||||
= render partial: 'domain_blocks', locals: { domain_blocks: blocks }
|
||||
- if (blocks = @blocks.select(&:suspend?)) && !blocks.empty?
|
||||
%h3= t('about.unavailable_content_description.suspended_title')
|
||||
%p= t('about.unavailable_content_description.suspended')
|
||||
= render partial: 'domain_blocks', locals: { domain_blocks: blocks }
|
||||
|
||||
.column-4
|
||||
%ul.table-of-contents
|
||||
- unless @rules.empty?
|
||||
%li= link_to t('about.rules'), '#rules'
|
||||
|
||||
- @table_of_contents.each do |item|
|
||||
%li
|
||||
= link_to item.title, "##{item.anchor}"
|
||||
|
||||
- unless item.children.empty?
|
||||
%ul
|
||||
- item.children.each do |sub_item|
|
||||
%li= link_to sub_item.title, "##{sub_item.anchor}"
|
||||
|
||||
- if display_blocks? && !@blocks.empty?
|
||||
%li= link_to t('about.unavailable_content'), '#unavailable-content'
|
@ -0,0 +1,4 @@
|
||||
- content_for :page_title do
|
||||
= t('about.title')
|
||||
|
||||
= render partial: 'shared/web_app'
|
Loading…
Reference in new issue