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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,7 @@
import Block from '../block'
import Button from '../button'
import Heading from '../heading'
import Text from '../text'
export default class PopoverLayout extends PureComponent {
@ -8,12 +10,17 @@ export default class PopoverLayout extends PureComponent {
width: PropTypes.number,
isXS: PropTypes.bool,
title: PropTypes.string,
onClose: PropTypes.func,
}
static defaultProps = {
width: 250,
}
handleOnClose = () => {
this.props.onClose()
}
render() {
const {
children,
@ -22,20 +29,35 @@ export default class PopoverLayout extends PureComponent {
title,
} = this.props
console.log("popoverlayout props:", this.props)
if (isXS) {
return (
<div className={[_s.default, _s.bgPrimary, _s.modal, _s.topRightRadiusSmall, _s.topLeftRadiusSmall].join(' ')}>
{
!!title &&
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.justifyContentCenter, _s.borderBottom1PX, _s.borderColorSecondary, _s.height53PX, _s.px15].join(' ')}>
<Heading size='h2'>
{title}
</Heading>
<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 &&
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter, _s.justifyContentCenter, _s.borderBottom1PX, _s.borderColorSecondary, _s.height53PX, _s.px15].join(' ')}>
<Heading size='2'>
{title}
</Heading>
</div>
}
<div className={[_s.default, _s.heightMax80VH, _s.radiusSmall, _s.overflowYScroll].join(' ')}>
{children}
</div>
}
<div className={[_s.default, _s.heightMax80VH, _s.topRightRadiusSmall, _s.topLeftRadiusSmall, _s.overflowYScroll].join(' ')}>
{children}
</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 :
}
handleOnClosePopover = () => {
this.props.onClosePopover()
}
render() {
const { isXS } = this.props
const listItems = this.makeMenu()
return (
<PopoverLayout width={250} isXS={isXS}>
<PopoverLayout
width={250}
isXS={isXS}
onClose={this.handleOnClosePopover}
>
<List
scrollKey='profile_options'
items={listItems}

View File

@ -298,6 +298,10 @@ class StatusOptionsPopover extends ImmutablePureComponent {
}
document.body.removeChild(textarea);
this.handleClosePopover()
}
handleClosePopover = () => {
this.props.onClosePopover()
}
@ -383,35 +387,10 @@ class StatusOptionsPopover extends ImmutablePureComponent {
title: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }),
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({
icon: 'copy',
hideArrow: true,
@ -431,8 +410,40 @@ class StatusOptionsPopover extends ImmutablePureComponent {
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 (
<PopoverLayout isXS={isXS}>
<PopoverLayout
isXS={isXS}
onClose={this.handleClosePopover}
>
<List
size='large'
scrollKey='profile_options'

View File

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

View File

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