From d4807a5e645b9363c7f8d6702186df4325bc5a97 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 30 Jul 2023 03:35:17 +0200 Subject: [PATCH] Change aspect ratios on link previews in web UI (#26250) --- .../features/status/components/card.jsx | 82 +++++++------------ .../styles/mastodon/components.scss | 76 +++++++++++++++-- 2 files changed, 97 insertions(+), 61 deletions(-) diff --git a/app/javascript/mastodon/features/status/components/card.jsx b/app/javascript/mastodon/features/status/components/card.jsx index 29a12c87b..6ac3c1d0f 100644 --- a/app/javascript/mastodon/features/status/components/card.jsx +++ b/app/javascript/mastodon/features/status/components/card.jsx @@ -5,7 +5,7 @@ import { PureComponent } from 'react'; import { FormattedMessage } from 'react-intl'; -import classnames from 'classnames'; +import classNames from 'classnames'; import Immutable from 'immutable'; import ImmutablePropTypes from 'react-immutable-proptypes'; @@ -71,6 +71,7 @@ export default class Card extends PureComponent { if (!Immutable.is(this.props.card, nextProps.card)) { this.setState({ embedded: false, previewLoaded: false }); } + if (this.props.sensitive !== nextProps.sensitive) { this.setState({ revealed: !nextProps.sensitive }); } @@ -84,35 +85,8 @@ export default class Card extends PureComponent { window.removeEventListener('resize', this.handleResize); } - handlePhotoClick = () => { - const { card, onOpenMedia } = this.props; - - onOpenMedia( - Immutable.fromJS([ - { - type: 'image', - url: card.get('embed_url'), - description: card.get('title'), - meta: { - original: { - width: card.get('width'), - height: card.get('height'), - }, - }, - }, - ]), - 0, - ); - }; - handleEmbedClick = () => { - const { card } = this.props; - - if (card.get('type') === 'photo') { - this.handlePhotoClick(); - } else { - this.setState({ embedded: true }); - } + this.setState({ embedded: true }); }; setRef = c => { @@ -130,15 +104,15 @@ export default class Card extends PureComponent { }; renderVideo () { - const { card } = this.props; - const content = { __html: addAutoPlay(card.get('html')) }; + const { card } = this.props; + const content = { __html: addAutoPlay(card.get('html')) }; return (
); } @@ -152,30 +126,40 @@ export default class Card extends PureComponent { } const provider = card.get('provider_name').length === 0 ? decodeIDNA(getHostname(card.get('url'))) : card.get('provider_name'); - const interactive = card.get('type') !== 'link'; + const interactive = card.get('type') === 'video'; const language = card.get('language') || ''; + const largeImage = (card.get('image')?.length > 0 && card.get('width') > card.get('height')) || interactive; const description = (
{provider} {card.get('published_at') && <> ยท } - + + {card.get('title')} - {card.get('author_name').length > 0 && {card.get('author_name')} }} />} + + {card.get('author_name').length > 0 ? {card.get('author_name')} }} /> : {card.get('description')}}
); const thumbnailStyle = { visibility: revealed ? null : 'hidden', - aspectRatio: `${card.get('width')} / ${card.get('height')}` }; + if (largeImage && card.get('type') === 'video') { + thumbnailStyle.aspectRatio = `16 / 9`; + } else if (largeImage) { + thumbnailStyle.aspectRatio = '1.91 / 1'; + } else { + thumbnailStyle.aspectRatio = 1; + } + let embed; let canvas = ( +
{spoilerButton}
); @@ -204,33 +188,25 @@ export default class Card extends PureComponent { if (embedded) { embed = this.renderVideo(); } else { - let iconVariant = 'play'; - - if (card.get('type') === 'photo') { - iconVariant = 'search-plus'; - } - embed = (
{canvas} {thumbnail} - {revealed && ( -
+ {revealed ? ( +
- +
- )} - - {!revealed && spoilerButton} + ) : spoilerButton}
); } return ( -
+
{embed} {description}
@@ -244,14 +220,14 @@ export default class Card extends PureComponent { ); } else { embed = ( -
+
); } return ( - + {embed} {description} diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index d16380de5..bc325edf6 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -3510,13 +3510,16 @@ button.icon-button.active i.fa-retweet { } .status-card { - display: block; + display: flex; + align-items: center; position: relative; font-size: 14px; color: $darker-text-color; margin-top: 14px; text-decoration: none; overflow: hidden; + border: 1px solid lighten($ui-base-color, 8%); + border-radius: 8px; &__actions { bottom: 0; @@ -3527,11 +3530,13 @@ button.icon-button.active i.fa-retweet { display: flex; justify-content: center; align-items: center; + cursor: pointer; & > div { background: rgba($base-shadow-color, 0.6); border-radius: 8px; padding: 12px 9px; + backdrop-filter: blur(10px) saturate(180%) contrast(75%) brightness(70%); flex: 0 0 auto; display: flex; justify-content: center; @@ -3572,7 +3577,8 @@ a.status-card { &:active { .status-card__title, .status-card__host, - .status-card__author { + .status-card__author, + .status-card__description { color: $highlight-text-color; } } @@ -3587,7 +3593,8 @@ a.status-card { &:active { .status-card__title, .status-card__host, - .status-card__author { + .status-card__author, + .status-card__description { color: $highlight-text-color; } } @@ -3620,19 +3627,30 @@ a.status-card { line-height: 24px; color: $primary-text-color; overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.status-card.expanded .status-card__title { + white-space: normal; + -webkit-line-clamp: 2; } .status-card__content { flex: 1 1 auto; overflow: hidden; - padding: 15px 0; - padding-bottom: 0; + padding: 15px; + box-sizing: border-box; + max-width: 100%; } .status-card__host { display: block; font-size: 14px; margin-bottom: 8px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .status-card__author { @@ -3640,17 +3658,33 @@ a.status-card { margin-top: 8px; font-size: 14px; color: $primary-text-color; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; strong { font-weight: 500; } } +.status-card__description { + display: block; + margin-top: 8px; + font-size: 14px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + .status-card__image { - width: 100%; + flex: 0 0 auto; + width: 120px; + aspect-ratio: 1; background: lighten($ui-base-color, 8%); position: relative; border-radius: 8px; + border-start-end-radius: 0; + border-end-end-radius: 0; & > .fa { font-size: 21px; @@ -3664,6 +3698,8 @@ a.status-card { .status-card__image-image { border-radius: 8px; + border-start-end-radius: 0; + border-end-end-radius: 0; display: block; margin: 0; width: 100%; @@ -3675,6 +3711,8 @@ a.status-card { .status-card__image-preview { border-radius: 8px; + border-start-end-radius: 0; + border-end-end-radius: 0; display: block; margin: 0; width: 100%; @@ -3691,6 +3729,28 @@ a.status-card { } } +.status-card.expanded { + flex-direction: column; + align-items: flex-start; +} + +.status-card.expanded .status-card__image { + width: 100%; + aspect-ratio: auto; +} + +.status-card.expanded .status-card__image, +.status-card.expanded .status-card__image-image, +.status-card.expanded .status-card__image-preview { + border-start-end-radius: 8px; + border-end-end-radius: 0; + border-end-start-radius: 0; +} + +.status-card.expanded > a { + width: 100%; +} + .load-more { display: block; color: $dark-text-color; @@ -4902,7 +4962,7 @@ a.status-card { width: 100%; background: $ui-base-color; border-radius: 0 0 4px 4px; - box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4); + box-shadow: var(--dropdown-shadow); z-index: 99; font-size: 13px; padding: 15px 5px; @@ -8218,7 +8278,7 @@ noscript { flex: 0 0 auto; position: relative; width: 120px; - height: 120px; + aspect-ratio: 1; .skeleton { width: 100%;