forked from fedi/mastodon
Add published date and author to news on the explore screen in web UI (#26155)
This commit is contained in:
parent
4299208487
commit
f826a95f6e
|
@ -1,10 +1,13 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { PureComponent } from 'react';
|
import { PureComponent } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { Blurhash } from 'mastodon/components/blurhash';
|
import { Blurhash } from 'mastodon/components/blurhash';
|
||||||
import { accountsCountRenderer } from 'mastodon/components/hashtag';
|
import { accountsCountRenderer } from 'mastodon/components/hashtag';
|
||||||
|
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
|
||||||
import { ShortNumber } from 'mastodon/components/short_number';
|
import { ShortNumber } from 'mastodon/components/short_number';
|
||||||
import { Skeleton } from 'mastodon/components/skeleton';
|
import { Skeleton } from 'mastodon/components/skeleton';
|
||||||
|
|
||||||
|
@ -15,9 +18,12 @@ export default class Story extends PureComponent {
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
lang: PropTypes.string,
|
lang: PropTypes.string,
|
||||||
publisher: PropTypes.string,
|
publisher: PropTypes.string,
|
||||||
|
publishedAt: PropTypes.string,
|
||||||
|
author: PropTypes.string,
|
||||||
sharedTimes: PropTypes.number,
|
sharedTimes: PropTypes.number,
|
||||||
thumbnail: PropTypes.string,
|
thumbnail: PropTypes.string,
|
||||||
blurhash: PropTypes.string,
|
blurhash: PropTypes.string,
|
||||||
|
expanded: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
|
@ -27,16 +33,16 @@ export default class Story extends PureComponent {
|
||||||
handleImageLoad = () => this.setState({ thumbnailLoaded: true });
|
handleImageLoad = () => this.setState({ thumbnailLoaded: true });
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { url, title, lang, publisher, sharedTimes, thumbnail, blurhash } = this.props;
|
const { expanded, url, title, lang, publisher, author, publishedAt, sharedTimes, thumbnail, blurhash } = this.props;
|
||||||
|
|
||||||
const { thumbnailLoaded } = this.state;
|
const { thumbnailLoaded } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a className='story' href={url} target='blank' rel='noopener'>
|
<a className={classNames('story', { expanded })} href={url} target='blank' rel='noopener'>
|
||||||
<div className='story__details'>
|
<div className='story__details'>
|
||||||
<div className='story__details__publisher' lang={lang}>{publisher ? publisher : <Skeleton width={50} />}</div>
|
<div className='story__details__publisher'>{publisher ? <span lang={lang}>{publisher}</span> : <Skeleton width={50} />}{publishedAt && <> · <RelativeTimestamp timestamp={publishedAt} /></>}</div>
|
||||||
<div className='story__details__title' lang={lang}>{title ? title : <Skeleton />}</div>
|
<div className='story__details__title' lang={lang}>{title ? title : <Skeleton />}</div>
|
||||||
<div className='story__details__shared'>{typeof sharedTimes === 'number' ? <ShortNumber value={sharedTimes} renderer={accountsCountRenderer} /> : <Skeleton width={100} />}</div>
|
<div className='story__details__shared'>{author && <><FormattedMessage id='link_preview.author' defaultMessage='By {name}' values={{ name: <strong>{author}</strong> }} /> · </>}{typeof sharedTimes === 'number' ? <ShortNumber value={sharedTimes} renderer={accountsCountRenderer} /> : <Skeleton width={100} />}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='story__thumbnail'>
|
<div className='story__thumbnail'>
|
||||||
|
|
|
@ -55,13 +55,16 @@ class Links extends PureComponent {
|
||||||
<div className='explore__links'>
|
<div className='explore__links'>
|
||||||
{banner}
|
{banner}
|
||||||
|
|
||||||
{isLoading ? (<LoadingIndicator />) : links.map(link => (
|
{isLoading ? (<LoadingIndicator />) : links.map((link, i) => (
|
||||||
<Story
|
<Story
|
||||||
key={link.get('id')}
|
key={link.get('id')}
|
||||||
|
expanded={i === 0}
|
||||||
lang={link.get('language')}
|
lang={link.get('language')}
|
||||||
url={link.get('url')}
|
url={link.get('url')}
|
||||||
title={link.get('title')}
|
title={link.get('title')}
|
||||||
publisher={link.get('provider_name')}
|
publisher={link.get('provider_name')}
|
||||||
|
publishedAt={link.get('published_at')}
|
||||||
|
author={link.get('author_name')}
|
||||||
sharedTimes={link.getIn(['history', 0, 'accounts']) * 1 + link.getIn(['history', 1, 'accounts']) * 1}
|
sharedTimes={link.getIn(['history', 0, 'accounts']) * 1 + link.getIn(['history', 1, 'accounts']) * 1}
|
||||||
thumbnail={link.get('image')}
|
thumbnail={link.get('image')}
|
||||||
blurhash={link.get('blurhash')}
|
blurhash={link.get('blurhash')}
|
||||||
|
|
|
@ -8164,8 +8164,9 @@ noscript {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: $primary-text-color;
|
color: $primary-text-color;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
padding: 15px 0;
|
padding: 15px;
|
||||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
||||||
|
gap: 15px;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
|
@ -8174,33 +8175,40 @@ noscript {
|
||||||
&:hover,
|
&:hover,
|
||||||
&:active,
|
&:active,
|
||||||
&:focus {
|
&:focus {
|
||||||
background-color: lighten($ui-base-color, 4%);
|
color: $highlight-text-color;
|
||||||
|
|
||||||
|
.story__details__publisher,
|
||||||
|
.story__details__shared {
|
||||||
|
color: $highlight-text-color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__details {
|
&__details {
|
||||||
padding: 0 15px;
|
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
|
||||||
&__publisher {
|
&__publisher {
|
||||||
color: $darker-text-color;
|
color: $darker-text-color;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__title {
|
&__title {
|
||||||
font-size: 19px;
|
font-size: 19px;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__shared {
|
&__shared {
|
||||||
color: $darker-text-color;
|
color: $darker-text-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__thumbnail {
|
&__thumbnail {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
margin: 0 15px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 120px;
|
width: 120px;
|
||||||
height: 120px;
|
height: 120px;
|
||||||
|
@ -8211,7 +8219,7 @@ noscript {
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
border-radius: 4px;
|
border-radius: 8px;
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -8220,7 +8228,7 @@ noscript {
|
||||||
}
|
}
|
||||||
|
|
||||||
&__preview {
|
&__preview {
|
||||||
border-radius: 4px;
|
border-radius: 8px;
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -8236,6 +8244,23 @@ noscript {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.expanded {
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.story__thumbnail {
|
||||||
|
order: 1;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
aspect-ratio: 1.91 / 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.story__details {
|
||||||
|
order: 2;
|
||||||
|
width: 100%;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.server-banner {
|
.server-banner {
|
||||||
|
|
Loading…
Reference in a new issue