mirror of
https://github.com/mastodon/mastodon
synced 2025-01-08 02:43:06 +09:00
cca41ea544
* fix(classnames): Status icon style classnames Take out inline css and put into classnames for the following components: account, avatar, icon button, status action bar, notification. * fix(status): Move styles from inline to classes for statuses Move styles to classnames in components.scss for the following components: display name media gallery status status content video player * fix(classnames): Add classnames to rest of components Take out inline styles and apply them to classnames in the sass for the following components: button column back button slim column back button collapsable column dropdown menu loading indicator status list * fix(classnames): Remove all non-dynamic inline styles Components affected: autosuggested permalink action bar header character counter compose form emoji dropdown privacy dropdown reply indicator upload form account auth followers getting started column settings mutes settings reblogs status checkbox report action bar status card boost modal media modal video modal * fix(permalink): Do not lose classname * fix(tests): Add space back in display name * fix(status__wrapper): Remove duplicate css name Remove incorrect style attribute. Remove style attribute all together. Cursor defaults to "auto" when not specified as 'default'. * fix(nl): do not lose translations
196 lines
5.2 KiB
JavaScript
196 lines
5.2 KiB
JavaScript
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
import PropTypes from 'prop-types';
|
|
import IconButton from './icon_button';
|
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|
import { isIOS } from '../is_mobile';
|
|
|
|
const messages = defineMessages({
|
|
toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Toggle visibility' }
|
|
});
|
|
|
|
class Item extends React.PureComponent {
|
|
constructor (props, context) {
|
|
super(props, context);
|
|
this.handleClick = this.handleClick.bind(this);
|
|
}
|
|
|
|
handleClick (e) {
|
|
const { index, onClick } = this.props;
|
|
|
|
if (e.button === 0) {
|
|
e.preventDefault();
|
|
onClick(index);
|
|
}
|
|
|
|
e.stopPropagation();
|
|
}
|
|
|
|
render () {
|
|
const { attachment, index, size } = this.props;
|
|
|
|
let width = 50;
|
|
let height = 100;
|
|
let top = 'auto';
|
|
let left = 'auto';
|
|
let bottom = 'auto';
|
|
let right = 'auto';
|
|
|
|
if (size === 1) {
|
|
width = 100;
|
|
}
|
|
|
|
if (size === 4 || (size === 3 && index > 0)) {
|
|
height = 50;
|
|
}
|
|
|
|
if (size === 2) {
|
|
if (index === 0) {
|
|
right = '2px';
|
|
} else {
|
|
left = '2px';
|
|
}
|
|
} else if (size === 3) {
|
|
if (index === 0) {
|
|
right = '2px';
|
|
} else if (index > 0) {
|
|
left = '2px';
|
|
}
|
|
|
|
if (index === 1) {
|
|
bottom = '2px';
|
|
} else if (index > 1) {
|
|
top = '2px';
|
|
}
|
|
} else if (size === 4) {
|
|
if (index === 0 || index === 2) {
|
|
right = '2px';
|
|
}
|
|
|
|
if (index === 1 || index === 3) {
|
|
left = '2px';
|
|
}
|
|
|
|
if (index < 2) {
|
|
bottom = '2px';
|
|
} else {
|
|
top = '2px';
|
|
}
|
|
}
|
|
|
|
let thumbnail = '';
|
|
|
|
if (attachment.get('type') === 'image') {
|
|
thumbnail = (
|
|
<a
|
|
className='media-gallery__item-thumbnail'
|
|
href={attachment.get('remote_url') || attachment.get('url')}
|
|
onClick={this.handleClick}
|
|
target='_blank'
|
|
style={{ background: `url(${attachment.get('preview_url')}) no-repeat center`}}
|
|
/>
|
|
);
|
|
} else if (attachment.get('type') === 'gifv') {
|
|
const autoPlay = !isIOS() && this.props.autoPlayGif;
|
|
|
|
thumbnail = (
|
|
<div className={`media-gallery__gifv ${autoPlay ? 'autoplay' : ''}`}>
|
|
<video
|
|
className='media-gallery__item-gifv-thumbnail'
|
|
role='application'
|
|
src={attachment.get('url')}
|
|
onClick={this.handleClick}
|
|
autoPlay={autoPlay}
|
|
loop={true}
|
|
muted={true}
|
|
/>
|
|
|
|
<span className='media-gallery__gifv__label'>GIF</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className='media-gallery__item' key={attachment.get('id')} style={{ left: left, top: top, right: right, bottom: bottom, width: `${width}%`, height: `${height}%` }}>
|
|
{thumbnail}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
Item.propTypes = {
|
|
attachment: ImmutablePropTypes.map.isRequired,
|
|
index: PropTypes.number.isRequired,
|
|
size: PropTypes.number.isRequired,
|
|
onClick: PropTypes.func.isRequired,
|
|
autoPlayGif: PropTypes.bool.isRequired
|
|
};
|
|
|
|
class MediaGallery extends React.PureComponent {
|
|
|
|
constructor (props, context) {
|
|
super(props, context);
|
|
this.state = {
|
|
visible: !props.sensitive
|
|
};
|
|
this.handleOpen = this.handleOpen.bind(this);
|
|
this.handleClick = this.handleClick.bind(this);
|
|
}
|
|
|
|
handleOpen (e) {
|
|
this.setState({ visible: !this.state.visible });
|
|
}
|
|
|
|
handleClick (index) {
|
|
this.props.onOpenMedia(this.props.media, index);
|
|
}
|
|
|
|
render () {
|
|
const { media, intl, sensitive } = this.props;
|
|
|
|
let children;
|
|
|
|
if (!this.state.visible) {
|
|
let warning;
|
|
|
|
if (sensitive) {
|
|
warning = <FormattedMessage id='status.sensitive_warning' defaultMessage='Sensitive content' />;
|
|
} else {
|
|
warning = <FormattedMessage id='status.media_hidden' defaultMessage='Media hidden' />;
|
|
}
|
|
|
|
children = (
|
|
<div role='button' tabIndex='0' className='media-spoiler' onClick={this.handleOpen}>
|
|
<span className='media-spoiler__warning'>{warning}</span>
|
|
<span className='media-spoiler__trigger'><FormattedMessage id='status.sensitive_toggle' defaultMessage='Click to view' /></span>
|
|
</div>
|
|
);
|
|
} else {
|
|
const size = media.take(4).size;
|
|
children = media.take(4).map((attachment, i) => <Item key={attachment.get('id')} onClick={this.handleClick} attachment={attachment} autoPlayGif={this.props.autoPlayGif} index={i} size={size} />);
|
|
}
|
|
|
|
return (
|
|
<div className='media-gallery' style={{ height: `${this.props.height}px` }}>
|
|
<div className='spoiler-button' style={{ display: !this.state.visible ? 'none' : 'block' }}>
|
|
<IconButton title={intl.formatMessage(messages.toggle_visible)} icon={this.state.visible ? 'eye' : 'eye-slash'} overlay onClick={this.handleOpen} />
|
|
</div>
|
|
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
MediaGallery.propTypes = {
|
|
sensitive: PropTypes.bool,
|
|
media: ImmutablePropTypes.list.isRequired,
|
|
height: PropTypes.number.isRequired,
|
|
onOpenMedia: PropTypes.func.isRequired,
|
|
intl: PropTypes.object.isRequired,
|
|
autoPlayGif: PropTypes.bool.isRequired
|
|
};
|
|
|
|
export default injectIntl(MediaGallery);
|