From 662a49dc3f06749936cedd7349092bbe622f0bc6 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 25 Jun 2020 01:33:01 +0200 Subject: Fix various issues around OpenGraph representation of media (#14133) - Fix audio attachments not being represented in OpenGraph tags - Fix audio being represented as "1 image" in OpenGraph descriptions - Fix video metadata being overwritten by paperclip-av-transcoder - Fix embedded player not using Mastodon's UI - Fix audio/video progress bars not moving smoothly - Fix audio/video buffered bars not displaying correctly --- app/views/accounts/_og.html.haml | 4 ++-- app/views/media/player.html.haml | 18 ++++++++++++++++-- app/views/statuses/_detailed_status.html.haml | 2 +- app/views/statuses/_og_image.html.haml | 17 +++++++++++++++-- app/views/statuses/_simple_status.html.haml | 2 +- 5 files changed, 35 insertions(+), 8 deletions(-) (limited to 'app/views') diff --git a/app/views/accounts/_og.html.haml b/app/views/accounts/_og.html.haml index 839576372..6350d7ed0 100644 --- a/app/views/accounts/_og.html.haml +++ b/app/views/accounts/_og.html.haml @@ -7,7 +7,7 @@ = opengraph 'og:title', yield(:page_title).strip = opengraph 'og:description', description = opengraph 'og:image', full_asset_url(account.avatar.url(:original)) -= opengraph 'og:image:width', '120' -= opengraph 'og:image:height', '120' += opengraph 'og:image:width', '400' += opengraph 'og:image:height', '400' = opengraph 'twitter:card', 'summary' = opengraph 'profile:username', acct(account)[1..-1] diff --git a/app/views/media/player.html.haml b/app/views/media/player.html.haml index ea868b3f6..3d308ee69 100644 --- a/app/views/media/player.html.haml +++ b/app/views/media/player.html.haml @@ -1,2 +1,16 @@ -%video{ poster: @media_attachment.file.url(:small), preload: 'auto', autoplay: 'autoplay', muted: 'muted', loop: 'loop', controls: 'controls', style: "width: #{@media_attachment.file.meta.dig('original', 'width')}px; height: #{@media_attachment.file.meta.dig('original', 'height')}px" } - %source{ src: @media_attachment.file.url(:original), type: @media_attachment.file_content_type } +- content_for :header_tags do + = render_initial_state + = javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous' + +- if @media_attachment.video? + = react_component :video, src: @media_attachment.file.url(:original), preview: @media_attachment.file.url(:small), blurhash: @media_attachment.blurhash, width: 670, height: 380, editable: true, detailed: true, inline: true, alt: @media_attachment.description do + %video{ controls: 'controls' } + %source{ src: @media_attachment.file.url(:original) } +- elsif @media_attachment.gifv? + = react_component :media_gallery, height: 380, standalone: true, autoplay: true, media: [ActiveModelSerializers::SerializableResource.new(@media_attachment, serializer: REST::MediaAttachmentSerializer).as_json] do + %video{ autoplay: 'autoplay', muted: 'muted', loop: 'loop' } + %source{ src: @media_attachment.file.url(:original) } +- elsif @media_attachment.audio? + = react_component :audio, src: @media_attachment.file.url(:original), poster: full_asset_url(@media_attachment.account.avatar_static_url), width: 670, height: 380, fullscreen: true, alt: @media_attachment.description, duration: @media_attachment.file.meta.dig(:original, :duration) do + %audio{ controls: 'controls' } + %source{ src: @media_attachment.file.url(:original) } diff --git a/app/views/statuses/_detailed_status.html.haml b/app/views/statuses/_detailed_status.html.haml index 8e409846a..c23733053 100644 --- a/app/views/statuses/_detailed_status.html.haml +++ b/app/views/statuses/_detailed_status.html.haml @@ -33,7 +33,7 @@ = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - elsif status.media_attachments.first.audio? - audio = status.media_attachments.first - = react_component :audio, src: audio.file.url(:original), height: 130, alt: audio.description, preload: true, duration: audio.file.meta.dig(:original, :duration) do + = react_component :audio, src: audio.file.url(:original), poster: full_asset_url(status.account.avatar_static_url), width: 670, height: 380, alt: audio.description, duration: audio.file.meta.dig(:original, :duration) do = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - else = react_component :media_gallery, height: 380, sensitive: status.sensitive?, standalone: true, autoplay: autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do diff --git a/app/views/statuses/_og_image.html.haml b/app/views/statuses/_og_image.html.haml index 67f9274b6..c8b6147ef 100644 --- a/app/views/statuses/_og_image.html.haml +++ b/app/views/statuses/_og_image.html.haml @@ -27,12 +27,25 @@ = opengraph 'og:video:height', media.file.meta.dig('original', 'height') = opengraph 'twitter:player:width', media.file.meta.dig('original', 'width') = opengraph 'twitter:player:height', media.file.meta.dig('original', 'height') + - elsif media.audio? + - player_card = true + = opengraph 'og:image', full_asset_url(account.avatar.url(:original)) + = opengraph 'og:image:width', '400' + = opengraph 'og:image:height','400' + = opengraph 'og:audio', full_asset_url(media.file.url(:original)) + = opengraph 'og:audio:secure_url', full_asset_url(media.file.url(:original)) + = opengraph 'og:audio:type', media.file_content_type + = opengraph 'twitter:player', medium_player_url(media) + = opengraph 'twitter:player:stream', full_asset_url(media.file.url(:original)) + = opengraph 'twitter:player:stream:content_type', media.file_content_type + = opengraph 'twitter:player:width', '670' + = opengraph 'twitter:player:height', '380' - if player_card = opengraph 'twitter:card', 'player' - else = opengraph 'twitter:card', 'summary_large_image' - else = opengraph 'og:image', full_asset_url(account.avatar.url(:original)) - = opengraph 'og:image:width', '120' - = opengraph 'og:image:height','120' + = opengraph 'og:image:width', '400' + = opengraph 'og:image:height','400' = opengraph 'twitter:card', 'summary' diff --git a/app/views/statuses/_simple_status.html.haml b/app/views/statuses/_simple_status.html.haml index da7caf166..d5950658a 100644 --- a/app/views/statuses/_simple_status.html.haml +++ b/app/views/statuses/_simple_status.html.haml @@ -37,7 +37,7 @@ = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - elsif status.media_attachments.first.audio? - audio = status.media_attachments.first - = react_component :audio, src: audio.file.url(:original), height: 110, alt: audio.description, duration: audio.file.meta.dig(:original, :duration) do + = react_component :audio, src: audio.file.url(:original), poster: full_asset_url(status.account.avatar_static_url), width: 610, height: 343, alt: audio.description, duration: audio.file.meta.dig(:original, :duration) do = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } - else = react_component :media_gallery, height: 343, sensitive: status.sensitive?, autoplay: autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do -- cgit From 418f0a33e9bcd8a1a2384b426bb3cc59b712ef98 Mon Sep 17 00:00:00 2001 From: Takeshi Umeda Date: Fri, 26 Jun 2020 05:43:59 +0900 Subject: Add a visibility icon to status (#14123) * Add a visibility icon to status * Change to using the icon element * Fix RTL * Add a public globe --- app/helpers/application_helper.rb | 12 ++++ app/javascript/mastodon/components/status.js | 19 ++++++- .../features/status/components/detailed_status.js | 66 ++++++++++++++-------- app/javascript/styles/mastodon/components.scss | 9 ++- app/javascript/styles/mastodon/rtl.scss | 1 + app/views/statuses/_detailed_status.html.haml | 15 ++--- app/views/statuses/_simple_status.html.haml | 4 +- 7 files changed, 90 insertions(+), 36 deletions(-) (limited to 'app/views') diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 2c03bd1d5..716df0bac 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -77,6 +77,18 @@ module ApplicationHelper content_tag(:i, nil, attributes.merge(class: class_names.join(' '))) end + def visibility_icon(status) + if status.public_visibility? + fa_icon('globe', title: I18n.t('statuses.visibilities.public')) + elsif status.unlisted_visibility? + fa_icon('unlock', title: I18n.t('statuses.visibilities.unlisted')) + elsif status.private_visibility? || status.limited_visibility? + fa_icon('lock', title: I18n.t('statuses.visibilities.private')) + elsif status.direct_visibility? + fa_icon('envelope', title: I18n.t('statuses.visibilities.direct')) + end + end + def custom_emoji_tag(custom_emoji, animate = true) if animate image_tag(custom_emoji.image.url, class: 'emojione', alt: ":#{custom_emoji.shortcode}:") diff --git a/app/javascript/mastodon/components/status.js b/app/javascript/mastodon/components/status.js index 5f42534ba..2dc961936 100644 --- a/app/javascript/mastodon/components/status.js +++ b/app/javascript/mastodon/components/status.js @@ -10,7 +10,7 @@ import StatusContent from './status_content'; import StatusActionBar from './status_action_bar'; import AttachmentList from './attachment_list'; import Card from '../features/status/components/card'; -import { injectIntl, FormattedMessage } from 'react-intl'; +import { injectIntl, defineMessages, FormattedMessage } from 'react-intl'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { MediaGallery, Video, Audio } from '../features/ui/util/async-components'; import { HotKeys } from 'react-hotkeys'; @@ -51,6 +51,13 @@ export const defaultMediaVisibility = (status) => { return (displayMedia !== 'hide_all' && !status.get('sensitive') || displayMedia === 'show_all'); }; +const messages = defineMessages({ + public_short: { id: 'privacy.public.short', defaultMessage: 'Public' }, + unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' }, + private_short: { id: 'privacy.private.short', defaultMessage: 'Followers-only' }, + direct_short: { id: 'privacy.direct.short', defaultMessage: 'Direct' }, +}); + export default @injectIntl class Status extends ImmutablePureComponent { @@ -416,6 +423,15 @@ class Status extends ImmutablePureComponent { statusAvatar = ; } + const visibilityIconInfo = { + 'public': { icon: 'globe', text: intl.formatMessage(messages.public_short) }, + 'unlisted': { icon: 'unlock', text: intl.formatMessage(messages.unlisted_short) }, + 'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) }, + 'direct': { icon: 'envelope', text: intl.formatMessage(messages.direct_short) }, + }; + + const visibilityIcon = visibilityIconInfo[status.get('visibility')]; + return (
@@ -425,6 +441,7 @@ class Status extends ImmutablePureComponent {
+
diff --git a/app/javascript/mastodon/features/status/components/detailed_status.js b/app/javascript/mastodon/features/status/components/detailed_status.js index 72d15ddf7..935e4207e 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.js +++ b/app/javascript/mastodon/features/status/components/detailed_status.js @@ -6,7 +6,7 @@ import DisplayName from '../../../components/display_name'; import StatusContent from '../../../components/status_content'; import MediaGallery from '../../../components/media_gallery'; import { Link } from 'react-router-dom'; -import { FormattedDate } from 'react-intl'; +import { injectIntl, defineMessages, FormattedDate } from 'react-intl'; import Card from './card'; import ImmutablePureComponent from 'react-immutable-pure-component'; import Video from '../../video'; @@ -16,7 +16,15 @@ import classNames from 'classnames'; import Icon from 'mastodon/components/icon'; import AnimatedNumber from 'mastodon/components/animated_number'; -export default class DetailedStatus extends ImmutablePureComponent { +const messages = defineMessages({ + public_short: { id: 'privacy.public.short', defaultMessage: 'Public' }, + unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' }, + private_short: { id: 'privacy.private.short', defaultMessage: 'Followers-only' }, + direct_short: { id: 'privacy.direct.short', defaultMessage: 'Direct' }, +}); + +export default @injectIntl +class DetailedStatus extends ImmutablePureComponent { static contextTypes = { router: PropTypes.object, @@ -92,7 +100,7 @@ export default class DetailedStatus extends ImmutablePureComponent { render () { const status = (this.props.status && this.props.status.get('reblog')) ? this.props.status.get('reblog') : this.props.status; const outerStyle = { boxSizing: 'border-box' }; - const { compact } = this.props; + const { intl, compact } = this.props; if (!status) { return null; @@ -157,34 +165,44 @@ export default class DetailedStatus extends ImmutablePureComponent { } if (status.get('application')) { - applicationLink = · {status.getIn(['application', 'name'])}; + applicationLink = · {status.getIn(['application', 'name'])}; } - if (status.get('visibility') === 'direct') { - reblogIcon = 'envelope'; - } else if (status.get('visibility') === 'private') { - reblogIcon = 'lock'; - } + const visibilityIconInfo = { + 'public': { icon: 'globe', text: intl.formatMessage(messages.public_short) }, + 'unlisted': { icon: 'unlock', text: intl.formatMessage(messages.unlisted_short) }, + 'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) }, + 'direct': { icon: 'envelope', text: intl.formatMessage(messages.direct_short) }, + }; + + const visibilityIcon = visibilityIconInfo[status.get('visibility')]; + const visibilityLink = · ; if (['private', 'direct'].includes(status.get('visibility'))) { - reblogLink = ; + reblogLink = ''; } else if (this.context.router) { reblogLink = ( - - - - - - + + · + + + + + + + ); } else { reblogLink = ( - - - - - - + + · + + + + + + + ); } @@ -210,7 +228,7 @@ export default class DetailedStatus extends ImmutablePureComponent { return (
-
+
@@ -223,7 +241,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
- {applicationLink} · {reblogLink} · {favouriteLink} + {visibilityLink}{applicationLink}{reblogLink} · {favouriteLink}
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 2ff9073db..e3da780ef 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -1019,7 +1019,8 @@ } &.light { - .status__relative-time { + .status__relative-time, + .status__visibility-icon { color: $light-text-color; } @@ -1065,12 +1066,18 @@ } .status__relative-time, +.status__visibility-icon, .notification__relative_time { color: $dark-text-color; float: right; font-size: 14px; } +.status__visibility-icon { + margin-left: 4px; + margin-right: 4px; +} + .status__display-name { color: $dark-text-color; } diff --git a/app/javascript/styles/mastodon/rtl.scss b/app/javascript/styles/mastodon/rtl.scss index ecd166253..fbf26e30b 100644 --- a/app/javascript/styles/mastodon/rtl.scss +++ b/app/javascript/styles/mastodon/rtl.scss @@ -158,6 +158,7 @@ body.rtl { } .status__relative-time, + .status__visibility-icon, .activity-stream .status.light .status__header .status__meta { float: left; } diff --git a/app/views/statuses/_detailed_status.html.haml b/app/views/statuses/_detailed_status.html.haml index c23733053..684dd08d1 100644 --- a/app/views/statuses/_detailed_status.html.haml +++ b/app/views/statuses/_detailed_status.html.haml @@ -1,4 +1,4 @@ -.detailed-status.detailed-status--flex +.detailed-status.detailed-status--flex{ class: "detailed-status-#{status.visibility}" } .p-author.h-card = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'detailed-status__display-name u-url', target: stream_link_target, rel: 'noopener' do .detailed-status__display-avatar @@ -47,6 +47,9 @@ = link_to ActivityPub::TagManager.instance.url_for(status), class: 'detailed-status__datetime u-url u-uid', target: stream_link_target, rel: 'noopener noreferrer' do %time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at) · + %span.detailed-status__visibility-icon + = visibility_icon status + · - if status.application && @account.user&.setting_show_application - if status.application.website.blank? %strong.detailed-status__application= status.application.name @@ -61,18 +64,12 @@ %span.detailed-status__reblogs>= number_to_human status.replies_count, strip_insignificant_zeros: true = " " · - - if status.direct_visibility? - %span.detailed-status__link< - = fa_icon('envelope') - - elsif status.private_visibility? || status.limited_visibility? - %span.detailed-status__link< - = fa_icon('lock') - - else + - if status.public_visibility? || status.unlisted_visibility? = link_to remote_interaction_path(status, type: :reblog), class: 'modal-button detailed-status__link' do = fa_icon('retweet') %span.detailed-status__reblogs>= number_to_human status.reblogs_count, strip_insignificant_zeros: true = " " - · + · = link_to remote_interaction_path(status, type: :favourite), class: 'modal-button detailed-status__link' do = fa_icon('star') %span.detailed-status__favorites>= number_to_human status.favourites_count, strip_insignificant_zeros: true diff --git a/app/views/statuses/_simple_status.html.haml b/app/views/statuses/_simple_status.html.haml index d5950658a..06dc5ff93 100644 --- a/app/views/statuses/_simple_status.html.haml +++ b/app/views/statuses/_simple_status.html.haml @@ -1,8 +1,10 @@ -.status +.status{ class: "status-#{status.visibility}" } .status__info = link_to ActivityPub::TagManager.instance.url_for(status), class: 'status__relative-time u-url u-uid', target: stream_link_target, rel: 'noopener noreferrer' do %time.time-ago{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at) %data.dt-published{ value: status.created_at.to_time.iso8601 } + %span.status__visibility-icon + = visibility_icon status .p-author.h-card = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener noreferrer' do -- cgit From 08cf81f8c1b445eba9972214869c376fe6097efb Mon Sep 17 00:00:00 2001 From: Mélanie Chauvel Date: Fri, 26 Jun 2020 00:36:30 +0200 Subject: Improve appearence consistency of settings pages (#13938) * Fix header button changing header size in settings pages * Make form buttons look more like a part of the form in settings pages - Put buttons closer, using same distance as between inputs - Make buton font size a bit smaller to blend a bit more - Add the class button to button tags for consisent styling --- app/javascript/styles/mastodon/admin.scss | 18 +++++++++++++----- app/views/admin/accounts/index.html.haml | 2 +- app/views/admin/custom_emojis/index.html.haml | 2 +- app/views/admin/instances/index.html.haml | 2 +- app/views/admin/reports/index.html.haml | 2 +- app/views/admin/tags/index.html.haml | 2 +- 6 files changed, 18 insertions(+), 10 deletions(-) (limited to 'app/views') diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss index 4edee730d..25ebc19b0 100644 --- a/app/javascript/styles/mastodon/admin.scss +++ b/app/javascript/styles/mastodon/admin.scss @@ -171,9 +171,7 @@ $content-width: 840px; } .content { - padding: 20px 15px; - padding-top: 60px; - padding-left: 25px; + padding: 55px 15px 20px 25px; @media screen and (max-width: $no-columns-breakpoint) { max-width: none; @@ -184,7 +182,7 @@ $content-width: 840px; &-heading { display: flex; - padding-bottom: 40px; + padding-bottom: 36px; border-bottom: 1px solid lighten($ui-base-color, 8%); margin: -15px -15px 40px 0; @@ -215,7 +213,7 @@ $content-width: 840px; h2 { color: $secondary-text-color; font-size: 24px; - line-height: 28px; + line-height: 36px; font-weight: 400; @media screen and (max-width: $no-columns-breakpoint) { @@ -512,6 +510,16 @@ body, max-width: 100%; } +.simple_form { + .actions { + margin-top: 15px; + } + + .button { + font-size: 15px; + } +} + .batch-form-box { display: flex; flex-wrap: wrap; diff --git a/app/views/admin/accounts/index.html.haml b/app/views/admin/accounts/index.html.haml index 7592161c9..8eac226e0 100644 --- a/app/views/admin/accounts/index.html.haml +++ b/app/views/admin/accounts/index.html.haml @@ -38,7 +38,7 @@ = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.accounts.#{key}") .actions - %button= t('admin.accounts.search') + %button.button= t('admin.accounts.search') = link_to t('admin.accounts.reset'), admin_accounts_path, class: 'button negative' .table-wrapper diff --git a/app/views/admin/custom_emojis/index.html.haml b/app/views/admin/custom_emojis/index.html.haml index c96a1ce00..1cbc36f97 100644 --- a/app/views/admin/custom_emojis/index.html.haml +++ b/app/views/admin/custom_emojis/index.html.haml @@ -34,7 +34,7 @@ = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.custom_emojis.#{key}") .actions - %button= t('admin.accounts.search') + %button.button= t('admin.accounts.search') = link_to t('admin.accounts.reset'), admin_custom_emojis_path, class: 'button negative' = form_for(@form, url: batch_admin_custom_emojis_path) do |f| diff --git a/app/views/admin/instances/index.html.haml b/app/views/admin/instances/index.html.haml index a73b8dc92..696ba3c7f 100644 --- a/app/views/admin/instances/index.html.haml +++ b/app/views/admin/instances/index.html.haml @@ -27,7 +27,7 @@ = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.instances.#{key}") .actions - %button= t('admin.accounts.search') + %button.button= t('admin.accounts.search') = link_to t('admin.accounts.reset'), admin_instances_path, class: 'button negative' %hr.spacer/ diff --git a/app/views/admin/reports/index.html.haml b/app/views/admin/reports/index.html.haml index 2149fcc46..bb441380e 100644 --- a/app/views/admin/reports/index.html.haml +++ b/app/views/admin/reports/index.html.haml @@ -18,7 +18,7 @@ = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.reports.#{key}") .actions - %button= t('admin.accounts.search') + %button.button= t('admin.accounts.search') = link_to t('admin.accounts.reset'), admin_reports_path, class: 'button negative' - @reports.group_by(&:target_account_id).each do |target_account_id, reports| diff --git a/app/views/admin/tags/index.html.haml b/app/views/admin/tags/index.html.haml index 2acdaa8fa..f888a311d 100644 --- a/app/views/admin/tags/index.html.haml +++ b/app/views/admin/tags/index.html.haml @@ -36,7 +36,7 @@ = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.tags.#{key}") .actions - %button= t('admin.accounts.search') + %button.button= t('admin.accounts.search') = link_to t('admin.accounts.reset'), admin_tags_path, class: 'button negative' %hr.spacer/ -- cgit