gab-social/app/javascript/gabsocial/components/media_item.js

157 lines
4.3 KiB
JavaScript
Raw Normal View History

2020-03-04 22:26:01 +00:00
import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component'
import { NavLink } from 'react-router-dom'
import { decode } from 'blurhash'
import { autoPlayGif, displayMedia } from '../initial_state'
2020-03-07 04:53:28 +00:00
import classNames from 'classnames/bind'
2020-03-04 22:26:01 +00:00
import Icon from './icon'
import Image from './image'
import Text from './text'
2020-03-07 04:53:28 +00:00
const cx = classNames.bind(_s)
2020-03-04 22:26:01 +00:00
export default class MediaItem extends ImmutablePureComponent {
static propTypes = {
attachment: ImmutablePropTypes.map.isRequired,
2020-03-07 04:53:28 +00:00
small: PropTypes.bool
2020-03-04 22:26:01 +00:00
}
state = {
visible: displayMedia !== 'hide_all' && !this.props.attachment.getIn(['status', 'sensitive']) || displayMedia === 'show_all',
loaded: false,
}
componentDidMount() {
if (this.props.attachment.get('blurhash')) {
this._decode()
}
}
componentDidUpdate(prevProps) {
if (prevProps.attachment.get('blurhash') !== this.props.attachment.get('blurhash') && this.props.attachment.get('blurhash')) {
this._decode()
}
}
_decode() {
const hash = this.props.attachment.get('blurhash')
const pixels = decode(hash, 160, 160)
if (pixels && this.canvas) {
const ctx = this.canvas.getContext('2d')
const imageData = new ImageData(pixels, 160, 160)
ctx.putImageData(imageData, 0, 0)
}
}
setCanvasRef = c => {
this.canvas = c
}
handleImageLoad = () => {
this.setState({ loaded: true })
}
hoverToPlay() {
return !autoPlayGif && ['gifv', 'video'].indexOf(this.props.attachment.get('type')) !== -1
}
render() {
2020-03-07 04:53:28 +00:00
const { attachment, small } = this.props
2020-03-04 22:26:01 +00:00
const { visible, loaded } = this.state
const status = attachment.get('status')
const title = status.get('spoiler_text') || attachment.get('description')
const attachmentType = attachment.get('type')
let badge = null
if (attachmentType === 'video') {
const duration = attachment.getIn(['meta', 'duration'])
badge = (duration / 60).toFixed(2)
} else if (attachmentType === 'gifv') {
badge = 'GIF'
}
2020-03-07 04:53:28 +00:00
const containerClasses = cx({
default: 1,
positionAbsolute: 1,
top0: 1,
height100PC: 1,
width100PC: 1,
paddingVertical5PX: !small,
paddingHorizontal5PX: !small,
})
const linkClasses = cx({
default: 1,
width100PC: 1,
height100PC: 1,
overflowHidden: 1,
border1PX: 1,
borderColorSecondary: !small,
borderColorWhite: small,
})
2020-03-04 22:26:01 +00:00
return (
<div className={[_s.default, _s.width25PC, _s.paddingTop25PC].join(' ')}>
2020-03-07 04:53:28 +00:00
<div className={containerClasses}>
2020-03-04 22:26:01 +00:00
<NavLink
to={status.get('url')} /* : todo : */
title={title}
2020-03-07 04:53:28 +00:00
className={linkClasses}
2020-03-04 22:26:01 +00:00
>
{
(!loaded || !visible) &&
<canvas
height='100%'
width='100%'
ref={this.setCanvasRef}
className={[_s.default, _s.width100PC, _s.height100PC, _s.z2].join(' ')}
/>
}
{
visible &&
<Image
height='100%'
src={attachment.get('preview_url')}
alt={attachment.get('description')}
title={attachment.get('description')}
onLoad={this.handleImageLoad}
className={_s.z1}
/>
}
<div className={[_s.default, _s.alignItemsCenter, _s.justifyContentCenter, _s.height100PC, _s.width100PC, _s.z3, _s.positionAbsolute].join(' ')}>
{
!visible &&
<Icon
id='hidden'
width='22px'
height='22px'
className={[_s.fillColorWhite].join('')}
/>
}
{
!!badge &&
<div className={[_s.default, _s.positionAbsolute, _s.radiusSmall, _s.backgroundColorOpaque, _s.paddingHorizontal5PX, _s.paddingVertical5PX, _s.marginRight5PX, _s.marginVertical5PX, _s.bottom0, _s.right0].join(' ')}>
<Text size='extraSmall' color='white'>
{badge}
</Text>
</div>
}
</div>
</NavLink>
</div>
</div>
)
}
}