The code powering m.abunchtell.com https://m.abunchtell.com
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.
 
 
 
 

104 lines
3.3 KiB

  1. import React, { PureComponent, Fragment } from 'react';
  2. import ReactDOM from 'react-dom';
  3. import PropTypes from 'prop-types';
  4. import { IntlProvider, addLocaleData } from 'react-intl';
  5. import { List as ImmutableList, fromJS } from 'immutable';
  6. import { getLocale } from 'mastodon/locales';
  7. import { getScrollbarWidth } from 'mastodon/utils/scrollbar';
  8. import MediaGallery from 'mastodon/components/media_gallery';
  9. import Poll from 'mastodon/components/poll';
  10. import Hashtag from 'mastodon/components/hashtag';
  11. import ModalRoot from 'mastodon/components/modal_root';
  12. import MediaModal from 'mastodon/features/ui/components/media_modal';
  13. import Video from 'mastodon/features/video';
  14. import Card from 'mastodon/features/status/components/card';
  15. import Audio from 'mastodon/features/audio';
  16. const { localeData, messages } = getLocale();
  17. addLocaleData(localeData);
  18. const MEDIA_COMPONENTS = { MediaGallery, Video, Card, Poll, Hashtag, Audio };
  19. export default class MediaContainer extends PureComponent {
  20. static propTypes = {
  21. locale: PropTypes.string.isRequired,
  22. components: PropTypes.object.isRequired,
  23. };
  24. state = {
  25. media: null,
  26. index: null,
  27. time: null,
  28. };
  29. handleOpenMedia = (media, index) => {
  30. document.body.classList.add('with-modals--active');
  31. document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
  32. this.setState({ media, index });
  33. }
  34. handleOpenVideo = (video, time) => {
  35. const media = ImmutableList([video]);
  36. document.body.classList.add('with-modals--active');
  37. document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
  38. this.setState({ media, time });
  39. }
  40. handleCloseMedia = () => {
  41. document.body.classList.remove('with-modals--active');
  42. document.documentElement.style.marginRight = 0;
  43. this.setState({ media: null, index: null, time: null });
  44. }
  45. render () {
  46. const { locale, components } = this.props;
  47. return (
  48. <IntlProvider locale={locale} messages={messages}>
  49. <Fragment>
  50. {[].map.call(components, (component, i) => {
  51. const componentName = component.getAttribute('data-component');
  52. const Component = MEDIA_COMPONENTS[componentName];
  53. const { media, card, poll, hashtag, ...props } = JSON.parse(component.getAttribute('data-props'));
  54. Object.assign(props, {
  55. ...(media ? { media: fromJS(media) } : {}),
  56. ...(card ? { card: fromJS(card) } : {}),
  57. ...(poll ? { poll: fromJS(poll) } : {}),
  58. ...(hashtag ? { hashtag: fromJS(hashtag) } : {}),
  59. ...(componentName === 'Video' ? {
  60. onOpenVideo: this.handleOpenVideo,
  61. } : {
  62. onOpenMedia: this.handleOpenMedia,
  63. }),
  64. });
  65. return ReactDOM.createPortal(
  66. <Component {...props} key={`media-${i}`} />,
  67. component,
  68. );
  69. })}
  70. <ModalRoot onClose={this.handleCloseMedia}>
  71. {this.state.media && (
  72. <MediaModal
  73. media={this.state.media}
  74. index={this.state.index || 0}
  75. time={this.state.time}
  76. onClose={this.handleCloseMedia}
  77. />
  78. )}
  79. </ModalRoot>
  80. </Fragment>
  81. </IntlProvider>
  82. );
  83. }
  84. }