diff --git a/app/soapbox/features/ui/components/profile_media_panel.js b/app/soapbox/features/ui/components/profile_media_panel.js new file mode 100644 index 000000000..a48427574 --- /dev/null +++ b/app/soapbox/features/ui/components/profile_media_panel.js @@ -0,0 +1,85 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { FormattedMessage, injectIntl } from 'react-intl'; +import { connect } from 'react-redux'; +import { getAccountGallery } from 'soapbox/selectors'; +import { openModal } from 'soapbox/actions/modal'; +import { expandAccountMediaTimeline } from '../../../actions/timelines'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import MediaItem from '../../account_gallery/components/media_item'; +import Icon from 'soapbox/components/icon'; + +class ProfileMediaPanel extends ImmutablePureComponent { + + static propTypes = { + account: ImmutablePropTypes.map, + attachments: ImmutablePropTypes.list, + dispatch: PropTypes.func.isRequired, + }; + + state = { + width: 255, + }; + + handleOpenMedia = attachment => { + if (attachment.get('type') === 'video') { + this.props.dispatch(openModal('VIDEO', { media: attachment, status: attachment.get('status') })); + } else { + const media = attachment.getIn(['status', 'media_attachments']); + const index = media.findIndex(x => x.get('id') === attachment.get('id')); + + this.props.dispatch(openModal('MEDIA', { media, index, status: attachment.get('status'), account: attachment.get('account') })); + } + } + + componentDidMount() { + const { account } = this.props; + const accountId = account.get('id'); + this.props.dispatch(expandAccountMediaTimeline(accountId)); + } + + render() { + const { attachments } = this.props; + const { width } = this.state; + const nineAttachments = attachments.slice(0, 9); + + if (attachments.isEmpty()) { + return null; + } + + return ( +
+
+ + + + +
+
+
+ {nineAttachments.map((attachment, index) => ( + + ))} +
+
+
+ ); + }; + +}; + +const mapStateToProps = (state, { account }) => ({ + attachments: getAccountGallery(state, account.get('id')), +}); + +export default injectIntl( + connect(mapStateToProps, null, null, { + forwardRef: true, + } + )(ProfileMediaPanel)); diff --git a/app/soapbox/pages/profile_page.js b/app/soapbox/pages/profile_page.js index fad1ced8b..b2d3c8834 100644 --- a/app/soapbox/pages/profile_page.js +++ b/app/soapbox/pages/profile_page.js @@ -9,9 +9,11 @@ import WhoToFollowPanel from '../features/ui/components/who_to_follow_panel'; import LinkFooter from '../features/ui/components/link_footer'; import SignUpPanel from '../features/ui/components/sign_up_panel'; import ProfileInfoPanel from '../features/ui/components/profile_info_panel'; +import ProfileMediaPanel from '../features/ui/components/profile_media_panel'; import { acctFull } from 'soapbox/utils/accounts'; import { getFeatures } from 'soapbox/utils/features'; import { makeGetAccount } from '../selectors'; +import { debounce } from 'lodash'; const mapStateToProps = (state, { params: { username }, withReplies = false }) => { const accounts = state.getIn(['accounts']); @@ -48,9 +50,28 @@ class ProfilePage extends ImmutablePureComponent { features: PropTypes.object, }; + state = { + isSmallScreen: (window.innerWidth <= 1200), + } + + componentDidMount() { + window.addEventListener('resize', this.handleResize, { passive: true }); + } + + componentWillUnmount() { + window.removeEventListener('resize', this.handleResize); + } + + handleResize = debounce(() => { + this.setState({ isSmallScreen: (window.innerWidth <= 1200) }); + }, 5, { + trailing: true, + }); + render() { const { children, accountId, account, accountUsername, features } = this.props; const bg = account ? account.getIn(['customizations', 'background']) : undefined; + const { isSmallScreen } = this.state; return (
@@ -68,6 +89,7 @@ class ProfilePage extends ImmutablePureComponent {
+ {isSmallScreen && account && }
@@ -81,6 +103,7 @@ class ProfilePage extends ImmutablePureComponent {
{features.suggestions && } + {account && }
diff --git a/app/styles/application.scss b/app/styles/application.scss index 7c2cd14b8..2b4c52a83 100644 --- a/app/styles/application.scss +++ b/app/styles/application.scss @@ -65,6 +65,7 @@ @import 'components/theme-toggle'; @import 'components/trends'; @import 'components/wtf-panel'; +@import 'components/profile-media-panel'; @import 'components/profile-info-panel'; @import 'components/setting-toggle'; @import 'components/spoiler-button'; diff --git a/app/styles/components/profile-media-panel.scss b/app/styles/components/profile-media-panel.scss new file mode 100644 index 000000000..3089bf19a --- /dev/null +++ b/app/styles/components/profile-media-panel.scss @@ -0,0 +1,48 @@ +.media-panel { + @include standard-panel-shadow; + display: flex; + width: 100%; + border-radius: 10px; + flex-direction: column; + height: auto; + box-sizing: border-box; + background: var(--foreground-color); + + &:first-child { + margin-top: 0; + } + + &:not(:last-of-type) { + margin-bottom: 10px; + } + + .media-panel-header { + display: flex; + align-items: baseline; + margin-bottom: 10px; + padding: 15px 15px 0; + + &__icon { + margin-right: 10px; + } + + &__label { + flex: 1 1; + color: var(--primary-text-color); + font-size: 16px; + font-weight: bold; + line-height: 19px; + } + } + + &__content { + width: 100%; + padding: 8px 0; + } + + &__list { + padding: 0 5px; + display: flex; + flex-wrap: wrap; + } +}