@ -8,12 +8,12 @@ import classNames from 'classnames';
import Immutable from 'immutable' ;
import ImmutablePropTypes from 'react-immutable-proptypes' ;
import DescriptionIcon from '@/material-icons/400-24px/description-fill.svg?react' ;
import OpenInNewIcon from '@/material-icons/400-24px/open_in_new.svg?react' ;
import PlayArrowIcon from '@/material-icons/400-24px/play_arrow-fill.svg?react' ;
import { Blurhash } from 'flavours/glitch/components/blurhash' ;
import { Icon } from 'flavours/glitch/components/icon' ;
import { RelativeTimestamp } from 'flavours/glitch/components/relative_timestamp' ;
import { useBlurhash } from 'flavours/glitch/initial_state' ;
import { decode as decodeIDNA } from 'flavours/glitch/utils/idna' ;
@ -51,14 +51,9 @@ export default class Card extends PureComponent {
static propTypes = {
card : ImmutablePropTypes . map ,
onOpenMedia : PropTypes . func . isRequired ,
compact : PropTypes . bool ,
sensitive : PropTypes . bool ,
} ;
static defaultProps = {
compact : false ,
} ;
state = {
previewLoaded : false ,
embedded : false ,
@ -69,6 +64,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 } ) ;
}
@ -82,35 +78,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 => {
@ -128,21 +97,21 @@ 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 (
< div
ref = { this . setRef }
className = 'status-card__image status-card-video'
dangerouslySetInnerHTML = { content }
style = { { aspectRatio : ` ${ card . get ( 'width' ) } / ${ card . get ( 'height' ) } ` } }
style = { { aspectRatio : '16 / 9' } }
/ >
) ;
}
render ( ) {
const { card , compact } = this . props ;
const { card } = this . props ;
const { embedded , revealed } = this . state ;
if ( card === null ) {
@ -150,29 +119,37 @@ export default class Card extends PureComponent {
}
const provider = card . get ( 'provider_name' ) . length === 0 ? decodeIDNA ( getHostname ( card . get ( 'url' ) ) ) : card . get ( 'provider_name' ) ;
const horizontal = ( ! compact && card . get ( 'width' ) > card . get ( 'height' ) ) || card . get ( 'type' ) !== 'link' || embedded ;
const interactive = card . get ( 'type' ) !== 'link' ;
const className = classNames ( 'status-card' , { horizontal , compact , interactive } ) ;
const title = interactive ? < a className = 'status-card__title' href = { card . get ( 'url' ) } title = { card . get ( 'title' ) } rel = 'noopener noreferrer' target = '_blank' > < strong > { card . get ( 'title' ) } < / strong > < / a > : < strong className = 'status-card__title' title = { card . get ( 'title' ) } > { card . get ( 'title' ) } < / strong > ;
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 = (
< div className = 'status-card__content' lang = { language } >
{ title }
{ ! ( horizontal || compact ) && < p className = 'status-card__description' title = { card . get ( 'description' ) } > { card . get ( 'description' ) } < / p > }
< span className = 'status-card__host' > { provider } < / span >
< div className = 'status-card__content' >
< span className = 'status-card__host' >
< span lang = { language } > { provider } < / span >
{ card . get ( 'published_at' ) && < > · < RelativeTimestamp timestamp = { card . get ( 'published_at' ) } / > < / > }
< / span >
< strong className = 'status-card__title' title = { card . get ( 'title' ) } lang = { language } > { card . get ( 'title' ) } < / strong >
{ card . get ( 'author_name' ) . length > 0 ? < span className = 'status-card__author' > < FormattedMessage id = 'link_preview.author' defaultMessage = 'By {name}' values = { { name : < strong > { card . get ( 'author_name' ) } < / strong > } } / > < / span > : < span className = 'status-card__description' lang = { language } > { card . get ( 'description' ) } < / span > }
< / div >
) ;
const thumbnailStyle = {
visibility : revealed ? null : 'hidden' ,
visibility : revealed ? null : 'hidden' ,
} ;
if ( horizontal ) {
thumbnailStyle . aspectRatio = ( compact && ! embedded ) ? '16 / 9' : ` ${ 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 embed ;
let canvas = (
< Blurhash
className = { classNames ( 'status-card__image-preview' , {
@ -205,22 +182,16 @@ export default class Card extends PureComponent {
if ( embedded ) {
embed = this . renderVideo ( ) ;
} else {
let iconVariant = 'play' ;
if ( card . get ( 'type' ) === 'photo' ) {
iconVariant = 'search-plus' ;
}
embed = (
< div className = 'status-card__image' >
{ canvas }
{ thumbnail }
{ revealed ? (
< div className = 'status-card__actions' >
< div className = 'status-card__actions' onClick = { this . handleEmbedClick } role = 'none' >
< div >
< button type = 'button' onClick = { this . handleEmbedClick } > < Icon id = { iconVariant } icon = { PlayArrowIcon } / > < / button >
{horizontal && <a href = { card . get ( 'url' ) } target = '_blank' rel = 'noopener noreferrer' > < Icon id = 'external-link' icon = { OpenInNewIcon } / > < / a > }
< button type = 'button' onClick = { this . handleEmbedClick } > < Icon id = 'play' icon = { PlayArrowIcon } / > < / button >
<a href = { card . get ( 'url' ) } target = '_blank' rel = 'noopener noreferrer' > < Icon id = 'external-link' icon = { OpenInNewIcon } / > < / a >
< / div >
< / div >
) : spoilerButton }
@ -229,9 +200,9 @@ export default class Card extends PureComponent {
}
return (
< div className = { className } ref = { this . setRef } onClick = { revealed ? null : this . handleReveal } role = { revealed ? 'button' : null } >
< div className = { className s( 'status-card' , { expanded : largeImage } ) } ref = { this . setRef } onClick = { revealed ? null : this . handleReveal } role = { revealed ? 'button' : null } >
{ embed }
{! compact && description }
<a href = { card . get ( 'url' ) } target = '_blank' rel = 'noopener noreferrer' > { description } < / a >
< / div >
) ;
} else if ( card . get ( 'image' ) ) {
@ -250,7 +221,7 @@ export default class Card extends PureComponent {
}
return (
< a href = { card . get ( 'url' ) } className = { className } target = '_blank' rel = 'noopener noreferrer' ref = { this . setRef } >
< a href = { card . get ( 'url' ) } className = { className s( 'status-card' , { expanded : largeImage } ) } target = '_blank' rel = 'noopener noreferrer' ref = { this . setRef } >
{ embed }
{ description }
< / a >