Progress
Albums almost done, group, chat moderation, photo, video page updates
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||
import { CX } from '../constants'
|
||||
import { openModal } from '../actions/modal'
|
||||
import {
|
||||
CX,
|
||||
MODAL_ALBUM_CREATE,
|
||||
} from '../constants'
|
||||
import Button from './button'
|
||||
import Icon from './icon'
|
||||
import Image from './image'
|
||||
@@ -10,19 +15,14 @@ import Text from './text'
|
||||
|
||||
class Album extends React.PureComponent {
|
||||
|
||||
handleOnClick = (e) => {
|
||||
//
|
||||
}
|
||||
|
||||
handleOnOpenAlbumCreation = () => {
|
||||
|
||||
handleOnOpenAlbumCreate = () => {
|
||||
this.props.openAlbumCreate()
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
album,
|
||||
isAddable,
|
||||
isDummy,
|
||||
} = this.props
|
||||
|
||||
const title = isAddable ? 'New album' : 'Album title'
|
||||
@@ -31,29 +31,26 @@ class Album extends React.PureComponent {
|
||||
|
||||
return (
|
||||
<div className={[_s.d, _s.minW162PX, _s.px5, _s.flex1].join(' ')}>
|
||||
{
|
||||
!isDummy &&
|
||||
<Button
|
||||
noClasses
|
||||
className={[_s.d, _s.noUnderline, _s.noOutline, _s.bgTransparent].join(' ')}
|
||||
to={to}
|
||||
onClick={isAddable ? this.handleOnOpenAlbumCreation : undefined}
|
||||
>
|
||||
<div className={[_s.d, _s.w100PC, _s.mt5, _s.mb10].join(' ')}>
|
||||
<div className={[_s.d, _s.w100PC, _s.pt100PC].join(' ')}>
|
||||
<div className={[_s.d, _s.posAbs, _s.top0, _s.w100PC, _s.right0, _s.bottom0, _s.left0].join(' ')}>
|
||||
<div className={[_s.d, _s.w100PC, _s.h100PC, _s.aiCenter, _s.jcCenter, _s.radiusSmall, _s.bgTertiary, _s.border1PX, _s.borderColorSecondary].join(' ')}>
|
||||
{ isAddable && <Icon id='add' size='20px' /> }
|
||||
</div>
|
||||
<Button
|
||||
noClasses
|
||||
className={[_s.d, _s.noUnderline, _s.cursorPointer, _s.outlineNone, _s.bgTransparent].join(' ')}
|
||||
to={to}
|
||||
onClick={isAddable ? this.handleOnOpenAlbumCreate : undefined}
|
||||
>
|
||||
<div className={[_s.d, _s.w100PC, _s.mt5, _s.mb10].join(' ')}>
|
||||
<div className={[_s.d, _s.w100PC, _s.pt100PC].join(' ')}>
|
||||
<div className={[_s.d, _s.posAbs, _s.top0, _s.w100PC, _s.right0, _s.bottom0, _s.left0].join(' ')}>
|
||||
<div className={[_s.d, _s.w100PC, _s.h100PC, _s.aiCenter, _s.jcCenter, _s.radiusSmall, _s.bgTertiary, _s.border1PX, _s.borderColorSecondary].join(' ')}>
|
||||
{ isAddable && <Icon id='add' size='20px' /> }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={[_s.d, _s.w100PC, _s.pt7, _s.mb15].join(' ')}>
|
||||
<Text weight='bold'>{title}</Text>
|
||||
{ !isAddable && <Text color='secondary' size='small' className={_s.mt5}>{subtitle}</Text> }
|
||||
</div>
|
||||
</Button>
|
||||
}
|
||||
</div>
|
||||
<div className={[_s.d, _s.w100PC, _s.pt7, _s.mb15].join(' ')}>
|
||||
<Text weight='bold'>{title}</Text>
|
||||
{ !isAddable && <Text color='secondary' size='small' className={_s.mt5}>{subtitle}</Text> }
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -63,7 +60,12 @@ class Album extends React.PureComponent {
|
||||
Album.propTypes = {
|
||||
album: ImmutablePropTypes.map,
|
||||
isAddable: PropTypes.bool,
|
||||
isDummy: PropTypes.bool,
|
||||
}
|
||||
|
||||
export default Album
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
openAlbumCreate() {
|
||||
dispatch(openModal(MODAL_ALBUM_CREATE))
|
||||
}
|
||||
})
|
||||
|
||||
export default connect(null, mapDispatchToProps)(Album)
|
||||
@@ -28,7 +28,7 @@ class DeckColumnHeader extends React.PureComponent {
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<div data-sort-header className={[_s.d, _s.w100PC, _s.flexRow, _s.aiCenter, _s.h60PX, _s.px15, _s.py10, _s.borderBottom1PX, _s.borderColorSecondary, _s.bgPrimary].join(' ')}>
|
||||
<div data-sort-header className={[_s.d, _s.w100PC, _s.overflowHidden, _s.flexRow, _s.aiCenter, _s.h60PX, _s.px15, _s.py10, _s.borderBottom1PX, _s.borderColorSecondary, _s.bgPrimary].join(' ')}>
|
||||
<div data-sort-header className={[_s.d, _s.flexRow, _s.mr15, _s.cursorEWResize].join(' ')}>
|
||||
<span className={[_s.d, _s.w1PX, _s.h24PX, _s.mr2, _s.bgSecondary].join(' ')} />
|
||||
<span className={[_s.d, _s.w1PX, _s.h24PX, _s.mr2, _s.bgSecondary].join(' ')} />
|
||||
@@ -36,7 +36,7 @@ class DeckColumnHeader extends React.PureComponent {
|
||||
</div>
|
||||
|
||||
{ !!icon && <Icon id={icon} className={[_s.cPrimary, _s.mr15].join(' ')} size='18px' /> }
|
||||
<div className={[_s.d, _s.flexRow, _s.aiEnd].join(' ')}>
|
||||
<div className={[_s.d, _s.flexRow, _s.aiEnd, _s.flexShrink1, _s.overflowHidden, _s.textOverflowEllipsis2].join(' ')}>
|
||||
{ !!title && <Text size='extraLarge' weight='medium'>{title}</Text> }
|
||||
{ !!subtitle && <Text className={_s.ml5} color='secondary'>{subtitle}</Text> }
|
||||
</div>
|
||||
|
||||
@@ -99,9 +99,6 @@ class GroupHeader extends ImmutablePureComponent {
|
||||
})
|
||||
}
|
||||
|
||||
// : todo :
|
||||
// {group.get('archived') && <Icon id='lock' title={intl.formatMessage(messages.group_archived)} />}
|
||||
|
||||
return (
|
||||
<div className={[_s.d, _s.z1, _s.w100PC, _s.mb15].join(' ')}>
|
||||
<Responsive max={BREAKPOINT_EXTRA_SMALL}>
|
||||
|
||||
@@ -14,23 +14,41 @@ class MediaItem extends ImmutablePureComponent {
|
||||
|
||||
state = {
|
||||
loaded: false,
|
||||
visible: displayMedia !== 'hide_all' && !this.props.attachment.getIn(['status', 'sensitive']) || displayMedia === 'show_all',
|
||||
visible: true,
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.attachment.get('blurhash')) {
|
||||
const { attachment } = this.props
|
||||
if (!attachment) return
|
||||
|
||||
if (attachment.get('blurhash')) {
|
||||
this._decode()
|
||||
}
|
||||
|
||||
this.setState({
|
||||
visible: displayMedia !== 'hide_all' && !this.props.attachment.getIn(['status', 'sensitive']) || displayMedia === 'show_all',
|
||||
})
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.attachment.get('blurhash') !== this.props.attachment.get('blurhash') && this.props.attachment.get('blurhash')) {
|
||||
const { attachment } = this.props
|
||||
const { prevAttachment } = prevProps
|
||||
|
||||
if (prevAttachment !== attachment) {
|
||||
this._decode()
|
||||
return
|
||||
}
|
||||
|
||||
if (prevAttachment.get('blurhash') !== attachment.get('blurhash') && attachment.get('blurhash')) {
|
||||
this._decode()
|
||||
}
|
||||
}
|
||||
|
||||
_decode() {
|
||||
const hash = this.props.attachment.get('blurhash')
|
||||
_decode = () => {
|
||||
const { attachment } = this.props
|
||||
if (!attachment) return
|
||||
|
||||
const hash = attachment.get('blurhash')
|
||||
const pixels = decode(hash, 160, 160)
|
||||
|
||||
if (pixels && this.canvas) {
|
||||
@@ -41,7 +59,7 @@ class MediaItem extends ImmutablePureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
setCanvasRef = c => {
|
||||
setCanvasRef = (c) => {
|
||||
this.canvas = c
|
||||
}
|
||||
|
||||
@@ -50,7 +68,10 @@ class MediaItem extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
hoverToPlay() {
|
||||
return !autoPlayGif && ['gifv', 'video'].indexOf(this.props.attachment.get('type')) !== -1
|
||||
const { attachment } = this.props
|
||||
if (!attachment) return
|
||||
|
||||
return !autoPlayGif && ['gifv', 'video'].indexOf(attachment.get('type')) !== -1
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -60,104 +81,152 @@ class MediaItem extends ImmutablePureComponent {
|
||||
isSmall,
|
||||
} = this.props
|
||||
const { visible, loaded } = this.state
|
||||
|
||||
|
||||
if (!attachment || !account) return null
|
||||
|
||||
const status = attachment.get('status')
|
||||
const title = status.get('spoiler_text') || attachment.get('description')
|
||||
|
||||
const attachmentType = attachment.get('type')
|
||||
const aspectRatio = attachment.getIn(['meta', 'aspect'])
|
||||
|
||||
const isVideo = attachmentType === 'video'
|
||||
let badge = null
|
||||
|
||||
if (attachmentType === 'video') {
|
||||
if (isVideo) {
|
||||
const duration = attachment.getIn(['meta', 'duration'])
|
||||
badge = (duration / 60).toFixed(2)
|
||||
} else if (attachmentType === 'gifv') {
|
||||
badge = 'GIF'
|
||||
}
|
||||
|
||||
const statusUrl = `/${account.getIn(['acct'])}/posts/${status.get('id')}`
|
||||
|
||||
const isSmallRatio = aspectRatio < 1
|
||||
const isSquare = aspectRatio === 1
|
||||
const containerClasses = CX({
|
||||
d: 1,
|
||||
posAbs: 1,
|
||||
top0: 1,
|
||||
h100PC: 1,
|
||||
// w100PC: 1,
|
||||
py2: !isSmall,
|
||||
px2: !isSmall,
|
||||
px5: 1,
|
||||
flex1: !isSmallRatio && !isSquare,
|
||||
minW198PX: !isVideo && !isSmallRatio && !isSquare,
|
||||
minW232PX: isVideo && !isSmallRatio && !isSquare,
|
||||
minW120PX: isSmallRatio,
|
||||
minW162PX: isSquare,
|
||||
})
|
||||
|
||||
const linkClasses = CX({
|
||||
const paddedContainerClasses = CX({
|
||||
d: 1,
|
||||
w100PC: 1,
|
||||
// h100PC: 1,
|
||||
overflowHidden: 1,
|
||||
border1PX: 1,
|
||||
borderColorPrimary: 1,
|
||||
h100PC: isSmallRatio || isSquare,
|
||||
pt100PC: isSmallRatio || isSquare || !isVideo,
|
||||
pt5625PC: isVideo && !isSmallRatio && !isSquare,
|
||||
})
|
||||
|
||||
const statusUrl = `/${account.getIn(['acct'])}/posts/${status.get('id')}`;
|
||||
|
||||
// : todo : fix dimensions to be like albums
|
||||
|
||||
return (
|
||||
<div className={[_s.d, _s.pt25PC].join(' ')}>
|
||||
<div className={containerClasses}>
|
||||
<NavLink
|
||||
to={statusUrl}
|
||||
title={title}
|
||||
className={linkClasses}
|
||||
>
|
||||
{
|
||||
(!loaded || !visible) &&
|
||||
<canvas
|
||||
height='100%'
|
||||
width='100%'
|
||||
ref={this.setCanvasRef}
|
||||
className={[_s.d, _s.w100PC, _s.h100PC, _s.z2].join(' ')}
|
||||
/>
|
||||
}
|
||||
<div className={containerClasses}>
|
||||
<NavLink
|
||||
className={[_s.d, _s.noUnderline, _s.outlineNone, _s.bgTransparent, _s.flexGrow1].join(' ')}
|
||||
to={statusUrl}
|
||||
title={title}
|
||||
>
|
||||
<div className={[_s.d, _s.mt5, _s.mb10, _s.flexGrow1].join(' ')}>
|
||||
<div className={paddedContainerClasses}>
|
||||
<div className={[_s.d, _s.posAbs, _s.top0, _s.right0, _s.left0, _s.bottom0].join(' ')}>
|
||||
<div className={[_s.d, _s.h100PC, _s.aiCenter, _s.jcCenter, _s.radiusSmall, _s.overflowHidden].join(' ')}>
|
||||
{
|
||||
(!loaded || !visible) &&
|
||||
<canvas
|
||||
height='100%'
|
||||
width='100%'
|
||||
ref={this.setCanvasRef}
|
||||
className={[_s.d, _s.w100PC, _s.h100PC, _s.z2].join(' ')}
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
visible &&
|
||||
<Image
|
||||
height='100%'
|
||||
width=''
|
||||
src={attachment.get('preview_url')}
|
||||
alt={attachment.get('description')}
|
||||
title={attachment.get('description')}
|
||||
onLoad={this.handleImageLoad}
|
||||
className={_s.z1}
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
visible &&
|
||||
<Image
|
||||
height='100%'
|
||||
width=''
|
||||
src={attachment.get('preview_url')}
|
||||
alt={attachment.get('description')}
|
||||
title={attachment.get('description')}
|
||||
onLoad={this.handleImageLoad}
|
||||
className={_s.z1}
|
||||
/>
|
||||
}
|
||||
|
||||
<div className={[_s.d, _s.aiCenter, _s.jcCenter, _s.h100PC, _s.w100PC, _s.z3, _s.posAbs].join(' ')}>
|
||||
{
|
||||
!visible &&
|
||||
<Icon
|
||||
id='hidden'
|
||||
size='22px'
|
||||
className={[_s.cWhite].join('')}
|
||||
/>
|
||||
}
|
||||
|
||||
{
|
||||
!!badge &&
|
||||
<div className={[_s.d, _s.posAbs, _s.radiusSmall, _s.bgBlackOpaque, _s.px5, _s.py5, _s.mr5, _s.mt5, _s.mb5, _s.bottom0, _s.right0].join(' ')}>
|
||||
<Text size='extraSmall' color='white'>
|
||||
{badge}
|
||||
</Text>
|
||||
{
|
||||
(!visible || !!badge) &&
|
||||
<div className={[_s.d, _s.aiCenter, _s.jcCenter, _s.h100PC, _s.w100PC, _s.z3, _s.posAbs].join(' ')}>
|
||||
{
|
||||
!visible &&
|
||||
<Icon
|
||||
id='hidden'
|
||||
size='22px'
|
||||
className={[_s.cWhite].join('')}
|
||||
/>
|
||||
}
|
||||
{
|
||||
!!badge &&
|
||||
<div className={[_s.d, _s.posAbs, _s.radiusSmall, _s.bgBlackOpaque, _s.px5, _s.py5, _s.mr5, _s.mt5, _s.mb5, _s.bottom0, _s.right0].join(' ')}>
|
||||
<Text size='extraSmall' color='white'>
|
||||
{badge}
|
||||
</Text>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</NavLink>
|
||||
</div>
|
||||
</div>
|
||||
</NavLink>
|
||||
</div>
|
||||
)
|
||||
|
||||
// return (
|
||||
// <div className={[_s.d, _s.pt25PC].join(' ')}>
|
||||
// <div className={containerClasses}>
|
||||
// <NavLink
|
||||
// to={statusUrl}
|
||||
// title={title}
|
||||
// className={linkClasses}
|
||||
// >
|
||||
// {
|
||||
// (!loaded || !visible) &&
|
||||
// <canvas
|
||||
// height='100%'
|
||||
// width='100%'
|
||||
// ref={this.setCanvasRef}
|
||||
// className={[_s.d, _s.w100PC, _s.h100PC, _s.z2].join(' ')}
|
||||
// />
|
||||
// }
|
||||
|
||||
// {
|
||||
// visible &&
|
||||
// <Image
|
||||
// height='100%'
|
||||
// width=''
|
||||
// src={attachment.get('preview_url')}
|
||||
// alt={attachment.get('description')}
|
||||
// title={attachment.get('description')}
|
||||
// onLoad={this.handleImageLoad}
|
||||
// className={_s.z1}
|
||||
// />
|
||||
// }
|
||||
|
||||
|
||||
// </NavLink>
|
||||
// </div>
|
||||
// </div>
|
||||
// )
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MediaItem.propTypes = {
|
||||
isDummy: PropTypes.bool.isRequired,
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
attachment: ImmutablePropTypes.map.isRequired,
|
||||
isSmall: PropTypes.bool,
|
||||
|
||||
@@ -1 +1,29 @@
|
||||
// : todo :
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import ModalLayout from './modal_layout'
|
||||
import AlbumCreate from '../../features/album_create'
|
||||
|
||||
class AlbumCreateModal extends React.PureComponent {
|
||||
|
||||
render() {
|
||||
const { onClose } = this.props
|
||||
|
||||
return (
|
||||
<ModalLayout
|
||||
title='Create Album'
|
||||
width={500}
|
||||
onClose={onClose}
|
||||
>
|
||||
<AlbumCreate isModal />
|
||||
</ModalLayout>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
AlbumCreateModal.propTypes = {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default AlbumCreateModal
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { defineMessages, injectIntl } from 'react-intl'
|
||||
import ModalLayout from './modal_layout'
|
||||
import BookmarkCollectionEdit from '../../features/bookmark_collection_edit'
|
||||
|
||||
class BookmarkCollectionEditModal extends React.PureComponent {
|
||||
|
||||
render() {
|
||||
const { onClose } = this.props
|
||||
|
||||
return (
|
||||
<ModalLayout
|
||||
title='Edit Bookmark Collection'
|
||||
width={500}
|
||||
onClose={onClose}
|
||||
>
|
||||
<BookmarkCollectionEdit isModal />
|
||||
</ModalLayout>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BookmarkCollectionEditModal.propTypes = {
|
||||
onClose: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default BookmarkCollectionEditModal
|
||||
@@ -39,12 +39,6 @@ class MediaGalleryPanel extends ImmutablePureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
// componentWillReceiveProps(nextProps) {
|
||||
// if (nextProps.accountId && nextProps.accountId !== this.props.accountId) {
|
||||
// this.props.dispatch(expandAccountMediaTimeline(nextProps.accountId, { limit: 8 }))
|
||||
// }
|
||||
// }
|
||||
|
||||
render() {
|
||||
const {
|
||||
account,
|
||||
|
||||
@@ -81,8 +81,6 @@ class StatusOptionsPopover extends ImmutablePureComponent {
|
||||
|
||||
handleGroupRemoveAccount = () => {
|
||||
const { status } = this.props
|
||||
|
||||
// : todo : check
|
||||
this.props.onGroupRemoveAccount(status.getIn(['group', 'id']), status.getIn(['account', 'id']))
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,19 @@ class DeckSidebar extends ImmutablePureComponent {
|
||||
|
||||
<div className={[_s.d].join(' ')}>
|
||||
|
||||
<Button
|
||||
to='/'
|
||||
isText
|
||||
title='Go home'
|
||||
aria-label='Go home'
|
||||
color='none'
|
||||
backgroundColor='none'
|
||||
className={[_s.d, _s.jcCenter, _s.noSelect, _s.noUnderline, _s.mt15, _s.mb15, _s.cursorPointer, _s.px10, _s.mr5].join(' ')}
|
||||
icon='back'
|
||||
iconSize='20px'
|
||||
iconClassName={_s.fillNavigationBrand}
|
||||
/>
|
||||
|
||||
<h1 className={[_s.d].join(' ')}>
|
||||
<Button
|
||||
to='/'
|
||||
|
||||
Reference in New Issue
Block a user