Uodated popover components mobile design

• Updated:
- popover components mobile design with cancel button at the bottom

• Added:
-CommentSortingOptionsPopover subtitles for options for more clarity
This commit is contained in:
mgabdev 2020-07-06 15:13:44 -05:00
parent 4fbd606a44
commit 7e3d4d009d
10 changed files with 216 additions and 83 deletions

View File

@ -11,8 +11,15 @@ import List from '../list'
const messages = defineMessages({ const messages = defineMessages({
oldest: { id: 'comment_sort.oldest', defaultMessage: 'Oldest' }, oldest: { id: 'comment_sort.oldest', defaultMessage: 'Oldest' },
oldestSubtitle: { id: 'comment_sort.oldest.subtitle', defaultMessage: 'Show all comments, with the oldest comments first.' },
newest: { id: 'comment_sort.newest', defaultMessage: 'Recent' }, newest: { id: 'comment_sort.newest', defaultMessage: 'Recent' },
newestSubtitle: { id: 'comment_sort.newest.subtitle', defaultMessage: 'Show all comments, with the newest comments first.' },
top: { id: 'comment_sort.top', defaultMessage: 'Most Liked' }, top: { id: 'comment_sort.top', defaultMessage: 'Most Liked' },
topSubtitle: { id: 'comment_sort.top.subtitle', defaultMessage: 'Show all comments, with the most liked top-level comments first.' },
})
const mapStateToProps = (state) => ({
commentSorting: state.getIn(['settings', 'commentSorting']),
}) })
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
@ -21,48 +28,71 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(saveSettings()) dispatch(saveSettings())
dispatch(closePopover()) dispatch(closePopover())
}, },
onClosePopover: () => dispatch(closePopover()),
}) })
export default export default
@injectIntl @injectIntl
@connect(null, mapDispatchToProps) @connect(mapStateToProps, mapDispatchToProps)
class CommentSortingOptionsPopover extends PureComponent { class CommentSortingOptionsPopover extends PureComponent {
static propTypes = { static propTypes = {
commentSorting: PropTypes.string.isRequired,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
onSetCommentSortingSetting: PropTypes.func.isRequired,
isXS: PropTypes.bool, isXS: PropTypes.bool,
onClosePopover: PropTypes.func.isRequired,
onSetCommentSortingSetting: PropTypes.func.isRequired,
} }
handleOnClick = (type) => { handleOnClick = (type) => {
this.props.onSetCommentSortingSetting(type) this.props.onSetCommentSortingSetting(type)
} }
render() { handleOnClosePopover = () => {
const { intl, isXS } = this.props this.props.onClosePopover()
}
return ( render() {
<PopoverLayout width={180} isXS={isXS}> const {
<List commentSorting,
size='large' intl,
scrollKey='comment_sorting_options' isXS,
items={[ } = this.props
const items = [
{ {
hideArrow: true, hideArrow: true,
isActive: commentSorting === COMMENT_SORTING_TYPE_NEWEST,
title: intl.formatMessage(messages.newest), title: intl.formatMessage(messages.newest),
subtitle: intl.formatMessage(messages.newestSubtitle),
onClick: () => this.handleOnClick(COMMENT_SORTING_TYPE_NEWEST), onClick: () => this.handleOnClick(COMMENT_SORTING_TYPE_NEWEST),
}, },
{ {
hideArrow: true, hideArrow: true,
isActive: commentSorting === COMMENT_SORTING_TYPE_OLDEST,
title: intl.formatMessage(messages.oldest), title: intl.formatMessage(messages.oldest),
subtitle: intl.formatMessage(messages.oldestSubtitle),
onClick: () => this.handleOnClick(COMMENT_SORTING_TYPE_OLDEST), onClick: () => this.handleOnClick(COMMENT_SORTING_TYPE_OLDEST),
}, },
{ {
hideArrow: true, hideArrow: true,
isActive: commentSorting === COMMENT_SORTING_TYPE_TOP,
title: intl.formatMessage(messages.top), title: intl.formatMessage(messages.top),
subtitle: intl.formatMessage(messages.topSubtitle),
onClick: () => this.handleOnClick(COMMENT_SORTING_TYPE_TOP), onClick: () => this.handleOnClick(COMMENT_SORTING_TYPE_TOP),
}, },
]} ]
return (
<PopoverLayout
width={180}
isXS={isXS}
onClose={this.handleOnClosePopover}
>
<List
size='large'
scrollKey='comment_sorting_options'
items={items}
small small
/> />
</PopoverLayout> </PopoverLayout>

View File

@ -5,10 +5,7 @@ import { changeScheduledAt } from '../../actions/compose'
import { openModal } from '../../actions/modal' import { openModal } from '../../actions/modal'
import { closePopover } from '../../actions/popover' import { closePopover } from '../../actions/popover'
import { me } from '../../initial_state' import { me } from '../../initial_state'
import { import { MODAL_PRO_UPGRADE } from '../../constants'
MODAL_PRO_UPGRADE,
} from '../../constants'
import { isMobile } from '../../utils/is_mobile'
import PopoverLayout from './popover_layout' import PopoverLayout from './popover_layout'
import Button from '../button' import Button from '../button'
import Text from '../text' import Text from '../text'
@ -33,6 +30,8 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(closePopover()) dispatch(closePopover())
} }
}, },
onClosePopover: () => dispatch(closePopover())
}) })
export default export default
@ -46,6 +45,7 @@ class DatePickerPopover extends PureComponent {
position: PropTypes.string, position: PropTypes.string,
small: PropTypes.bool, small: PropTypes.bool,
isXS: PropTypes.bool, isXS: PropTypes.bool,
onClosePopover: PropTypes.func.isRequired,
} }
handleSetDate = (date) => { handleSetDate = (date) => {
@ -56,13 +56,20 @@ class DatePickerPopover extends PureComponent {
this.props.setScheduledAt(null, this.props.isPro) this.props.setScheduledAt(null, this.props.isPro)
} }
handleOnClosePopover = () => {
this.props.onClosePopover()
}
render() { render() {
const { date, isPro, isXS } = this.props const { date, isPro, isXS } = this.props
const datePickerDisabled = !isPro const datePickerDisabled = !isPro
return ( return (
<PopoverLayout width={331} isXS={isXS}> <PopoverLayout
width={360}
isXS={isXS}
onClose={this.handleOnClosePopover}
>
<div className={[_s.default, _s.bgSubtle].join(' ')}> <div className={[_s.default, _s.bgSubtle].join(' ')}>
<DatePicker <DatePicker
inline inline

View File

@ -278,7 +278,11 @@ class EmojiPickerPopover extends ImmutablePureComponent {
const { loading } = this.state const { loading } = this.state
return ( return (
<PopoverLayout width={340} isXS={isXS}> <PopoverLayout
width={340}
isXS={isXS}
onClose={this.onHideDropdown}
>
<EmojiPickerMenu <EmojiPickerMenu
customEmojis={customEmojis} customEmojis={customEmojis}
loading={loading} loading={loading}

View File

@ -15,6 +15,7 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(closePopover()) dispatch(closePopover())
dispatch(createRemovedAccount(groupId, accountId)) dispatch(createRemovedAccount(groupId, accountId))
}, },
onClosePopover:() => dispatch(closePopover()),
}) })
export default export default
@ -25,8 +26,9 @@ class GroupMemberOptionsPopover extends PureComponent {
accountId: PropTypes.string.isRequired, accountId: PropTypes.string.isRequired,
groupId: PropTypes.string.isRequired, groupId: PropTypes.string.isRequired,
isXS: PropTypes.bool, isXS: PropTypes.bool,
onUpdateRole: PropTypes.func.isRequired, onClosePopover: PropTypes.func.isRequired,
onCreateRemovedAccount: PropTypes.func.isRequired, onCreateRemovedAccount: PropTypes.func.isRequired,
onUpdateRole: PropTypes.func.isRequired,
} }
handleOnRemoveFromGroup = () => { handleOnRemoveFromGroup = () => {
@ -37,6 +39,10 @@ class GroupMemberOptionsPopover extends PureComponent {
this.props.onUpdateRole(this.props.groupId, this.props.accountId, 'admin') this.props.onUpdateRole(this.props.groupId, this.props.accountId, 'admin')
} }
handleOnClosePopover = () => {
this.props.onClosePopover()
}
render() { render() {
const { isXS } = this.props const { isXS } = this.props
@ -56,7 +62,11 @@ class GroupMemberOptionsPopover extends PureComponent {
] ]
return ( return (
<PopoverLayout width={210} isXS={isXS}> <PopoverLayout
width={210}
isXS={isXS}
onClose={this.handleOnClosePopover}
>
<List <List
scrollKey='group_options' scrollKey='group_options'
items={listItems} items={listItems}

View File

@ -35,6 +35,8 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(openModal(MODAL_GROUP_MEMBERS, { groupId })) dispatch(openModal(MODAL_GROUP_MEMBERS, { groupId }))
}, },
onClosePopover: () => dispatch(closePopover())
}); });
export default export default
@ -43,12 +45,13 @@ export default
class GroupOptionsPopover extends ImmutablePureComponent { class GroupOptionsPopover extends ImmutablePureComponent {
static defaultProps = { static defaultProps = {
intl: PropTypes.object.isRequired,
group: ImmutablePropTypes.map.isRequired, group: ImmutablePropTypes.map.isRequired,
onOpenEditGroup: PropTypes.func.isRequired, intl: PropTypes.object.isRequired,
onOpenRemovedMembers: PropTypes.func.isRequired,
onOpenGroupMembers: PropTypes.func.isRequired,
isXS: PropTypes.bool, isXS: PropTypes.bool,
onClosePopover: PropTypes.func.isRequired,
onOpenEditGroup: PropTypes.func.isRequired,
onOpenGroupMembers: PropTypes.func.isRequired,
onOpenRemovedMembers: PropTypes.func.isRequired,
} }
updateOnProps = ['group'] updateOnProps = ['group']
@ -65,6 +68,10 @@ class GroupOptionsPopover extends ImmutablePureComponent {
this.props.onOpenGroupMembers(this.props.group.get('id')) this.props.onOpenGroupMembers(this.props.group.get('id'))
} }
handleOnClosePopover = () => {
this.props.onClosePopover()
}
render() { render() {
const { intl, isXS } = this.props const { intl, isXS } = this.props
@ -90,7 +97,11 @@ class GroupOptionsPopover extends ImmutablePureComponent {
] ]
return ( return (
<PopoverLayout width={210} isXS={isXS}> <PopoverLayout
width={210}
isXS={isXS}
onClose={this.handleOnClosePopover}
>
<List <List
scrollKey='group_options' scrollKey='group_options'
items={listItems} items={listItems}

View File

@ -1,5 +1,7 @@
import Block from '../block' import Block from '../block'
import Button from '../button'
import Heading from '../heading' import Heading from '../heading'
import Text from '../text'
export default class PopoverLayout extends PureComponent { export default class PopoverLayout extends PureComponent {
@ -8,12 +10,17 @@ export default class PopoverLayout extends PureComponent {
width: PropTypes.number, width: PropTypes.number,
isXS: PropTypes.bool, isXS: PropTypes.bool,
title: PropTypes.string, title: PropTypes.string,
onClose: PropTypes.func,
} }
static defaultProps = { static defaultProps = {
width: 250, width: 250,
} }
handleOnClose = () => {
this.props.onClose()
}
render() { render() {
const { const {
children, children,
@ -22,21 +29,36 @@ export default class PopoverLayout extends PureComponent {
title, title,
} = this.props } = this.props
console.log("popoverlayout props:", this.props)
if (isXS) { if (isXS) {
return ( return (
<div className={[_s.default, _s.bgPrimary, _s.modal, _s.topRightRadiusSmall, _s.topLeftRadiusSmall].join(' ')}> <div className={[_s.default, _s.modal, _s.px10, _s.pb10].join(' ')}>
<div className={[_s.default, _s.bgPrimary, _s.radiusSmall, _s.overflowHidden, _s.mb10].join(' ')}>
{ {
!!title && !!title &&
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.justifyContentCenter, _s.borderBottom1PX, _s.borderColorSecondary, _s.height53PX, _s.px15].join(' ')}> <div className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.justifyContentCenter, _s.borderBottom1PX, _s.borderColorSecondary, _s.height53PX, _s.px15].join(' ')}>
<Heading size='h2'> <Heading size='2'>
{title} {title}
</Heading> </Heading>
</div> </div>
} }
<div className={[_s.default, _s.heightMax80VH, _s.topRightRadiusSmall, _s.topLeftRadiusSmall, _s.overflowYScroll].join(' ')}> <div className={[_s.default, _s.heightMax80VH, _s.radiusSmall, _s.overflowYScroll].join(' ')}>
{children} {children}
</div> </div>
</div> </div>
<Button
backgroundColor='primary'
color='primary'
onClick={this.handleOnClose}
radiusSmall
>
<Text color='inherit' size='large' align='center'>
Cancel
</Text>
</Button>
</div>
) )
} }

View File

@ -124,6 +124,8 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
})); }));
}, },
onClosePopover: () => dispatch(closePopover()),
}); });
@ -261,12 +263,20 @@ class ProfileOptionsPopover extends PureComponent {
// : todo : // : todo :
} }
handleOnClosePopover = () => {
this.props.onClosePopover()
}
render() { render() {
const { isXS } = this.props const { isXS } = this.props
const listItems = this.makeMenu() const listItems = this.makeMenu()
return ( return (
<PopoverLayout width={250} isXS={isXS}> <PopoverLayout
width={250}
isXS={isXS}
onClose={this.handleOnClosePopover}
>
<List <List
scrollKey='profile_options' scrollKey='profile_options'
items={listItems} items={listItems}

View File

@ -298,6 +298,10 @@ class StatusOptionsPopover extends ImmutablePureComponent {
} }
document.body.removeChild(textarea); document.body.removeChild(textarea);
this.handleClosePopover()
}
handleClosePopover = () => {
this.props.onClosePopover() this.props.onClosePopover()
} }
@ -383,35 +387,10 @@ class StatusOptionsPopover extends ImmutablePureComponent {
title: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), title: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }),
onClick: this.handleReport, onClick: this.handleReport,
}) })
if (withGroupAdmin) {
menu.push({
icon: 'trash',
hideArrow: true,
title: intl.formatMessage(messages.group_remove_account),
onClick: this.handleGroupRemoveAccount,
})
menu.push({
icon: 'trash',
hideArrow: true,
title: intl.formatMessage(messages.group_remove_post),
onClick: this.handleGroupRemovePost,
})
}
if (isStaff) {
menu.push({
title: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }),
href: `/admin/accounts/${status.getIn(['account', 'id'])}`
})
menu.push({
title: intl.formatMessage(messages.admin_status),
href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}`
})
}
} }
} }
menu.push(null)
menu.push({ menu.push({
icon: 'copy', icon: 'copy',
hideArrow: true, hideArrow: true,
@ -431,8 +410,40 @@ class StatusOptionsPopover extends ImmutablePureComponent {
onClick: this.handleOnOpenEmbedModal, onClick: this.handleOnOpenEmbedModal,
}) })
if (withGroupAdmin) {
menu.push(null)
menu.push({
icon: 'trash',
hideArrow: true,
title: intl.formatMessage(messages.group_remove_account),
onClick: this.handleGroupRemoveAccount,
})
menu.push({
icon: 'trash',
hideArrow: true,
title: intl.formatMessage(messages.group_remove_post),
onClick: this.handleGroupRemovePost,
})
}
if (isStaff) {
menu.push(null)
menu.push({
title: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }),
href: `/admin/accounts/${status.getIn(['account', 'id'])}`
})
menu.push({
title: intl.formatMessage(messages.admin_status),
href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}`
})
}
return ( return (
<PopoverLayout isXS={isXS}> <PopoverLayout
isXS={isXS}
onClose={this.handleClosePopover}
>
<List <List
size='large' size='large'
scrollKey='profile_options' scrollKey='profile_options'

View File

@ -24,12 +24,11 @@ const mapStateToProps = (state) => ({
}) })
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
onChange (value) { onChange (value) {
dispatch(changeComposeVisibility(value)) dispatch(changeComposeVisibility(value))
dispatch(closePopover()) dispatch(closePopover())
}, },
onClosePopover: () => dispatch(closePopover()),
}) })
export default export default
@ -38,16 +37,21 @@ export default
class StatusVisibilityDropdown extends PureComponent { class StatusVisibilityDropdown extends PureComponent {
static propTypes = { static propTypes = {
value: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
isXS: PropTypes.bool, isXS: PropTypes.bool,
onChange: PropTypes.func.isRequired,
onClosePopover: PropTypes.func.isRequired,
value: PropTypes.string.isRequired,
} }
handleChange = (value) => { handleChange = (value) => {
this.props.onChange(value) this.props.onChange(value)
} }
handleOnClosePopover = () => {
this.props.onClosePopover()
}
render () { render () {
const { intl, value, isXS } = this.props const { intl, value, isXS } = this.props
@ -73,7 +77,11 @@ class StatusVisibilityDropdown extends PureComponent {
] ]
return ( return (
<PopoverLayout width={300} isXS={isXS}> <PopoverLayout
width={300}
isXS={isXS}
onClose={this.handleOnClosePopover}
>
<div className={[_s.default].join(' ')}> <div className={[_s.default].join(' ')}>
{ {
options.map((option, i) => { options.map((option, i) => {

View File

@ -2,6 +2,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component' import ImmutablePureComponent from 'react-immutable-pure-component'
import { defineMessages, injectIntl } from 'react-intl' import { defineMessages, injectIntl } from 'react-intl'
import { closePopover } from '../../actions/popover' import { closePopover } from '../../actions/popover'
import { CX } from '../../constants'
import PopoverLayout from './popover_layout' import PopoverLayout from './popover_layout'
import Button from '../button' import Button from '../button'
import Text from '../text' import Text from '../text'
@ -67,9 +68,21 @@ class VideoStatsPopover extends ImmutablePureComponent {
'bitrate', 'bitrate',
] ]
const containerClasses = CX({
default: 1,
bgBlack: !isXS,
bgPrimary: !isXS,
px10: 1,
py10: 1,
})
return ( return (
<PopoverLayout isXS={isXS} width={320}> <PopoverLayout
<div className={[_s.default, _s.bgBlack, _s.px10, _s.py10].join(' ')}> isXS={isXS}
width={320}
onClose={this.handleOnClosePopover}
>
<div className={containerClasses}>
<Button <Button
icon='close' icon='close'
iconSize='8px' iconSize='8px'
@ -85,6 +98,7 @@ class VideoStatsPopover extends ImmutablePureComponent {
key={`video-stat-${key}`} key={`video-stat-${key}`}
title={intl.formatMessage(messages[key])} title={intl.formatMessage(messages[key])}
value={meta.get(key)} value={meta.get(key)}
isXS={isXS}
/> />
)) ))
} }
@ -94,6 +108,7 @@ class VideoStatsPopover extends ImmutablePureComponent {
key={`video-stat-o-${key}`} key={`video-stat-o-${key}`}
title={intl.formatMessage(messages[`original_${key}`])} title={intl.formatMessage(messages[`original_${key}`])}
value={meta.getIn(['original', key])} value={meta.getIn(['original', key])}
isXS={isXS}
/> />
)) ))
} }
@ -108,21 +123,26 @@ class VideoStatsPopover extends ImmutablePureComponent {
class VideoStatLine extends PureComponent { class VideoStatLine extends PureComponent {
static propTypes = { static propTypes = {
isXS: PropTypes.bool.isRequired,
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
value: PropTypes.string.isRequired, value: PropTypes.string.isRequired,
} }
render() { render() {
const { title, value } = this.props const { isXS, title, value } = this.props
const color = isXS ? 'primary' : 'white'
return ( return (
<div className={[_s.default, _s.flexRow, _s.pt2].join(' ')}> <div className={[_s.default, _s.flexRow, _s.pt2].join(' ')}>
<div className={[_s.default, _s.width115PX, _s.alignItemsEnd, _s.mr5].join(' ')}> <div className={[_s.default, _s.width115PX, _s.alignItemsEnd, _s.mr5].join(' ')}>
<Text size='extraSmall' weight='medium' color='white'> <Text size='extraSmall' weight='medium' color={color}>
{title} {title}
</Text> </Text>
</div> </div>
<Text size='extraSmall' color='white'>{value}</Text> <Text size='extraSmall' color={color}>
{value}
</Text>
</div> </div>
) )
} }