You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
3.3 KiB

  1. // Package imports //
  2. import React from 'react';
  3. import ImmutablePropTypes from 'react-immutable-proptypes';
  4. import PropTypes from 'prop-types';
  5. // Mastodon imports //
  6. import { isIOS } from '../../../../mastodon/is_mobile';
  7. export default class StatusGalleryItem extends React.PureComponent {
  8. static propTypes = {
  9. attachment: ImmutablePropTypes.map.isRequired,
  10. index: PropTypes.number.isRequired,
  11. size: PropTypes.number.isRequired,
  12. letterbox: PropTypes.bool,
  13. onClick: PropTypes.func.isRequired,
  14. autoPlayGif: PropTypes.bool.isRequired,
  15. };
  16. handleClick = (e) => {
  17. const { index, onClick } = this.props;
  18. if (e.button === 0) {
  19. e.preventDefault();
  20. onClick(index);
  21. }
  22. e.stopPropagation();
  23. }
  24. render () {
  25. const { attachment, index, size, letterbox } = this.props;
  26. let width = 50;
  27. let height = 100;
  28. let top = 'auto';
  29. let left = 'auto';
  30. let bottom = 'auto';
  31. let right = 'auto';
  32. if (size === 1) {
  33. width = 100;
  34. }
  35. if (size === 4 || (size === 3 && index > 0)) {
  36. height = 50;
  37. }
  38. if (size === 2) {
  39. if (index === 0) {
  40. right = '2px';
  41. } else {
  42. left = '2px';
  43. }
  44. } else if (size === 3) {
  45. if (index === 0) {
  46. right = '2px';
  47. } else if (index > 0) {
  48. left = '2px';
  49. }
  50. if (index === 1) {
  51. bottom = '2px';
  52. } else if (index > 1) {
  53. top = '2px';
  54. }
  55. } else if (size === 4) {
  56. if (index === 0 || index === 2) {
  57. right = '2px';
  58. }
  59. if (index === 1 || index === 3) {
  60. left = '2px';
  61. }
  62. if (index < 2) {
  63. bottom = '2px';
  64. } else {
  65. top = '2px';
  66. }
  67. }
  68. let thumbnail = '';
  69. if (attachment.get('type') === 'image') {
  70. const previewUrl = attachment.get('preview_url');
  71. const previewWidth = attachment.getIn(['meta', 'small', 'width']);
  72. const originalUrl = attachment.get('url');
  73. const originalWidth = attachment.getIn(['meta', 'original', 'width']);
  74. const srcSet = `${originalUrl} ${originalWidth}w, ${previewUrl} ${previewWidth}w`;
  75. const sizes = `(min-width: 1025px) ${320 * (width / 100)}px, ${width}vw`;
  76. thumbnail = (
  77. <a
  78. className='media-gallery__item-thumbnail'
  79. href={attachment.get('remote_url') || originalUrl}
  80. onClick={this.handleClick}
  81. target='_blank'
  82. >
  83. <img className={letterbox ? 'letterbox' : ''} src={previewUrl} srcSet={srcSet} sizes={sizes} alt='' />
  84. </a>
  85. );
  86. } else if (attachment.get('type') === 'gifv') {
  87. const autoPlay = !isIOS() && this.props.autoPlayGif;
  88. thumbnail = (
  89. <div className={`media-gallery__gifv ${autoPlay ? 'autoplay' : ''}`}>
  90. <video
  91. className={`media-gallery__item-gifv-thumbnail${letterbox ? ' letterbox' : ''}`}
  92. role='application'
  93. src={attachment.get('url')}
  94. onClick={this.handleClick}
  95. autoPlay={autoPlay}
  96. loop
  97. muted
  98. />
  99. <span className='media-gallery__gifv__label'>GIF</span>
  100. </div>
  101. );
  102. }
  103. return (
  104. <div className='media-gallery__item' key={attachment.get('id')} style={{ left: left, top: top, right: right, bottom: bottom, width: `${width}%`, height: `${height}%` }}>
  105. {thumbnail}
  106. </div>
  107. );
  108. }
  109. }