This commit is contained in:
mgabdev 2020-05-07 01:55:24 -04:00
parent a026d86b86
commit a390662e4f
29 changed files with 347 additions and 257 deletions

View File

@ -8,7 +8,7 @@ export default class CardView extends PureComponent {
const { children } = this.props const { children } = this.props
return ( return (
<div className={[_s.default, _s.boxShadowBlock, _s.bgPrimary, _s.overflowHidden, _s.radiusSmall].join(' ')}> <div title='cardview' className={[_s.default].join(' ')}>
{children} {children}
</div> </div>
) )

View File

@ -29,12 +29,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
} }
}, },
onOpenGroupOptions() { onOpenGroupOptions(targetRef, group) {
dispatch(openPopover('GROUP_OPTIONS', {
}, targetRef,
group,
openProfileOptionsPopover(props) { position: 'top',
dispatch(openPopover('GROUP_OPTIONS', props)) }))
}, },
}); });
@ -57,11 +57,18 @@ class GroupHeader extends ImmutablePureComponent {
this.props.onToggleMembership(group, relationships); this.props.onToggleMembership(group, relationships);
} }
handleOnOpenGroupOptions = () => {
this.props.onOpenGroupOptions(this.infoBtn, this.props.group)
}
setInfoBtn = (c) => {
this.infoBtn = c;
}
render() { render() {
const { const {
group, group,
intl, intl,
onOpenGroupOptions,
relationships, relationships,
} = this.props } = this.props
@ -131,7 +138,8 @@ class GroupHeader extends ImmutablePureComponent {
backgroundColor='tertiary' backgroundColor='tertiary'
className={_s.mr5} className={_s.mr5}
icon='ellipsis' icon='ellipsis'
onClick={onOpenGroupOptions} onClick={this.handleOnOpenGroupOptions}
buttonRef={this.setInfoBtn}
/> />
</div> </div>
</div> </div>

View File

@ -1,68 +0,0 @@
import { injectIntl, defineMessages } from 'react-intl'
import { muteAccount } from '../../actions/accounts'
const messages = defineMessages({
muteMessage: { id: 'confirmations.mute.message', defaultMessage: 'Are you sure you want to mute {name}?' },
cancel: { id: 'confirmation_modal.cancel', defaultMessage: 'Cancel' },
confirm: { id: 'confirmations.mute.confirm', defaultMessage: 'Mute' },
})
const mapStateToProps = (state) => ({
isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']),
account: state.getIn(['mutes', 'new', 'account']),
})
const mapDispatchToProps = (dispatch) => ({
onConfirm(account, notifications) {
dispatch(muteAccount(account.get('id'), notifications))
},
})
export default
@connect(mapStateToProps, mapDispatchToProps)
@injectIntl
class UnfollowModal extends PureComponent {
static propTypes = {
isSubmitting: PropTypes.bool.isRequired,
account: PropTypes.object.isRequired,
onConfirm: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
}
componentDidMount() {
this.button.focus()
}
handleClick = () => {
this.props.onClose()
this.props.onConfirm(this.props.account, this.props.notifications)
}
handleCancel = () => {
this.props.onClose()
}
render() {
const { account, intl } = this.props
// , {
// message: <FormattedMessage id='confirmations.unfollow.message' defaultMessage='Are you sure you want to unfollow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
// confirm: intl.formatMessage(messages.unfollowConfirm),
// onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
// }));
return (
<ConfirmationModal
title={`Mute @${account.get('acct')}`}
message={<FormattedMessage id='confirmations.mute.message' defaultMessage='Are you sure you want to mute @{name}?' values={{ name: account.get('acct') }} />}
confirm={<FormattedMessage id='mute' defaultMessage='Mute' />}
onConfirm={() => {
// dispatch(blockDomain(domain))
// dispatch(blockDomain(domain))
}}
/>
)
}
}

View File

@ -1,31 +1,36 @@
import { defineMessages, injectIntl } from 'react-intl' import { defineMessages, injectIntl } from 'react-intl'
import ImmutablePureComponent from 'react-immutable-pure-component'
import ModalLayout from './modal_layout' import ModalLayout from './modal_layout'
import GroupCreate from '../../features/group_create' import GroupMembers from '../../features/group_members'
const messages = defineMessages({ const messages = defineMessages({
title: { id: 'create_group', defaultMessage: 'Create group' }, title: { id: 'group_members', defaultMessage: 'Group members' },
}) })
export default export default
@injectIntl @injectIntl
class GroupMembersModal extends ImmutablePureComponent { class GroupMembersModal extends PureComponent {
static propTypes = { static propTypes = {
groupId: PropTypes.string.isRequired,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
} }
render() { render() {
const { intl, onClose } = this.props const {
intl,
onClose,
groupId,
} = this.props
return ( return (
<ModalLayout <ModalLayout
title={intl.formatMessage(messages.title)} title={intl.formatMessage(messages.title)}
width={440} width={440}
onClose={onClose} onClose={onClose}
noPadding
> >
<GroupCreate onCloseModal={onClose} /> <GroupMembers groupId={groupId} onCloseModal={onClose} />
</ModalLayout> </ModalLayout>
) )
} }

View File

@ -0,0 +1,37 @@
import { defineMessages, injectIntl } from 'react-intl'
import ModalLayout from './modal_layout'
import GroupRemovedAccounts from '../../features/group_removed_accounts'
const messages = defineMessages({
title: { id: 'group_removed', defaultMessage: 'Removed accounts' },
})
export default
@injectIntl
class GroupRemovedAccountsModal extends PureComponent {
static propTypes = {
groupId: PropTypes.string.isRequired,
intl: PropTypes.object.isRequired,
onClose: PropTypes.func.isRequired,
}
render() {
const {
intl,
onClose,
groupId,
} = this.props
return (
<ModalLayout
title={intl.formatMessage(messages.title)}
width={440}
onClose={onClose}
noPadding
>
<GroupRemovedAccounts groupId={groupId} onCloseModal={onClose} />
</ModalLayout>
)
}
}

View File

@ -3,6 +3,9 @@ import { injectIntl, FormattedMessage, defineMessages } from 'react-intl'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
import { openModal } from '../../actions/modal' import { openModal } from '../../actions/modal'
import { cancelReplyCompose } from '../../actions/compose' import { cancelReplyCompose } from '../../actions/compose'
import { BREAKPOINT_EXTRA_SMALL } from '../../constants'
import Responsive from '../../features/ui/util/responsive_component'
import CardView from '../card_view'
const messages = defineMessages({ const messages = defineMessages({
confirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, confirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
@ -145,7 +148,14 @@ class ModalBase extends PureComponent {
onClick={this.handleOnClose} onClick={this.handleOnClose}
className={[_s.default, _s.posFixed, _s.alignItemsCenter, _s.justifyContentCenter, _s.z4, _s.width100PC, _s.height100PC, _s.top0, _s.rightAuto, _s.bottomAuto, _s.left0].join(' ')} className={[_s.default, _s.posFixed, _s.alignItemsCenter, _s.justifyContentCenter, _s.z4, _s.width100PC, _s.height100PC, _s.top0, _s.rightAuto, _s.bottomAuto, _s.left0].join(' ')}
> >
<Responsive min={BREAKPOINT_EXTRA_SMALL}>
{children} {children}
</Responsive>
<Responsive max={BREAKPOINT_EXTRA_SMALL}>
<CardView>
{children}
</CardView>
</Responsive>
</div> </div>
</Fragment> </Fragment>
} }

View File

@ -1,3 +1,4 @@
import { Fragment } from 'react'
import { closeModal } from '../../actions/modal' import { closeModal } from '../../actions/modal'
import { cancelReplyCompose } from '../../actions/compose' import { cancelReplyCompose } from '../../actions/compose'
import Bundle from '../../features/ui/util/bundle' import Bundle from '../../features/ui/util/bundle'
@ -17,8 +18,8 @@ import {
MODAL_GIF_PICKER, MODAL_GIF_PICKER,
MODAL_GROUP_CREATE, MODAL_GROUP_CREATE,
MODAL_GROUP_DELETE, MODAL_GROUP_DELETE,
MODAL_GROUP_EDITOR,
MODAL_GROUP_MEMBERS, MODAL_GROUP_MEMBERS,
MODAL_GROUP_REMOVED_ACCOUNTS,
MODAL_HASHTAG_TIMELINE_SETTINGS, MODAL_HASHTAG_TIMELINE_SETTINGS,
MODAL_HOME_TIMELINE_SETTINGS, MODAL_HOME_TIMELINE_SETTINGS,
MODAL_HOTKEYS, MODAL_HOTKEYS,
@ -51,8 +52,8 @@ import {
GifPickerModal, GifPickerModal,
GroupCreateModal, GroupCreateModal,
GroupDeleteModal, GroupDeleteModal,
GroupEditorModal,
GroupMembersModal, GroupMembersModal,
GroupRemovedAccountsModal,
HashtagTimelineSettingsModal, HashtagTimelineSettingsModal,
HomeTimelineSettingsModal, HomeTimelineSettingsModal,
HotkeysModal, HotkeysModal,
@ -86,8 +87,8 @@ MODAL_COMPONENTS[MODAL_EMBED] = EmbedModal
MODAL_COMPONENTS[MODAL_GIF_PICKER] = GifPickerModal MODAL_COMPONENTS[MODAL_GIF_PICKER] = GifPickerModal
MODAL_COMPONENTS[MODAL_GROUP_CREATE] = GroupCreateModal MODAL_COMPONENTS[MODAL_GROUP_CREATE] = GroupCreateModal
MODAL_COMPONENTS[MODAL_GROUP_DELETE] = GroupDeleteModal MODAL_COMPONENTS[MODAL_GROUP_DELETE] = GroupDeleteModal
MODAL_COMPONENTS[MODAL_GROUP_EDITOR] = GroupEditorModal
MODAL_COMPONENTS[MODAL_GROUP_MEMBERS] = GroupMembersModal MODAL_COMPONENTS[MODAL_GROUP_MEMBERS] = GroupMembersModal
MODAL_COMPONENTS[MODAL_GROUP_REMOVED_ACCOUNTS] = GroupRemovedAccountsModal
MODAL_COMPONENTS[MODAL_HASHTAG_TIMELINE_SETTINGS] = HashtagTimelineSettingsModal MODAL_COMPONENTS[MODAL_HASHTAG_TIMELINE_SETTINGS] = HashtagTimelineSettingsModal
MODAL_COMPONENTS[MODAL_HOME_TIMELINE_SETTINGS] = HomeTimelineSettingsModal MODAL_COMPONENTS[MODAL_HOME_TIMELINE_SETTINGS] = HomeTimelineSettingsModal
MODAL_COMPONENTS[MODAL_HOTKEYS] = HotkeysModal MODAL_COMPONENTS[MODAL_HOTKEYS] = HotkeysModal
@ -159,8 +160,6 @@ class ModalRoot extends PureComponent {
const { type, props } = this.props const { type, props } = this.props
const visible = !!type const visible = !!type
// : todo : init card view if mobile
return ( return (
<ModalBase onClose={this.onClickClose} type={type}> <ModalBase onClose={this.onClickClose} type={type}>
{ {

View File

@ -61,7 +61,7 @@ class NavigationBar extends ImmutablePureComponent {
return ( return (
<div className={[_s.default, _s.z4, _s.height53PX, _s.width100PC].join(' ')}> <div className={[_s.default, _s.z4, _s.height53PX, _s.width100PC].join(' ')}>
<div className={[_s.default, _s.height53PX, _s.bgBrand, _s.alignItemsCenter, _s.z3, _s.top0, _s.right0, _s.left0, _s.posFixed].join(' ')} > <div className={[_s.default, _s.height53PX, _s.bgNavigation, _s.alignItemsCenter, _s.z3, _s.top0, _s.right0, _s.left0, _s.posFixed].join(' ')} >
<div className={[_s.default, _s.flexRow, _s.width1255PX].join(' ')}> <div className={[_s.default, _s.flexRow, _s.width1255PX].join(' ')}>
@ -71,8 +71,16 @@ class NavigationBar extends ImmutablePureComponent {
<div className={[_s.default, _s.flexRow].join(' ')}> <div className={[_s.default, _s.flexRow].join(' ')}>
<h1 className={[_s.default, _s.mr15].join(' ')}> <h1 className={[_s.default, _s.mr15].join(' ')}>
<Button to='/' isText title='Gab' aria-label='Gab' className={[_s.default, _s.justifyContentCenter, _s.noSelect, _s.noUnderline, _s.height53PX, _s.cursorPointer, _s.px10, _s.mr15].join(' ')}> <Button
<Icon id='gab-logo' className={_s.fillWhite} /> to='/'
isText
title='Gab'
aria-label='Gab'
color='none'
backgroundColor='none'
className={[_s.default, _s.justifyContentCenter, _s.noSelect, _s.noUnderline, _s.height53PX, _s.cursorPointer, _s.px10, _s.mr15].join(' ')}
>
<Icon id='gab-logo' className={_s.fillNavigationBrand} />
</Button> </Button>
</h1> </h1>
@ -131,7 +139,7 @@ class NavigationBar extends ImmutablePureComponent {
className={[_s.height53PX, _s.bgTransparent, _s.mr5, _s.cursorPointer, _s.outlineNone, _s.default, _s.justifyContentCenter].join(' ')} className={[_s.height53PX, _s.bgTransparent, _s.mr5, _s.cursorPointer, _s.outlineNone, _s.default, _s.justifyContentCenter].join(' ')}
icon='arrow-left' icon='arrow-left'
iconSize='32px' iconSize='32px'
iconClassName={[_s.mr5, _s.fillPrimary].join(' ')} iconClassName={[_s.mr5, _s.fillNavigation].join(' ')}
onClick={this.handleBackClick} onClick={this.handleBackClick}
/> />
} }
@ -139,7 +147,9 @@ class NavigationBar extends ImmutablePureComponent {
<div className={[_s.default, _s.height53PX, _s.justifyContentCenter, _s.mlAuto, _s.mrAuto].join(' ')}> <div className={[_s.default, _s.height53PX, _s.justifyContentCenter, _s.mlAuto, _s.mrAuto].join(' ')}>
<Heading size='h1'> <Heading size='h1'>
<span className={_s.colorNavigation}>
{title} {title}
</span>
</Heading> </Heading>
</div> </div>
@ -157,8 +167,8 @@ class NavigationBar extends ImmutablePureComponent {
key={`action-btn-${i}`} key={`action-btn-${i}`}
className={[_s.ml5, _s.height53PX, _s.justifyContentCenter, _s.px5].join(' ')} className={[_s.ml5, _s.height53PX, _s.justifyContentCenter, _s.px5].join(' ')}
icon={action.icon} icon={action.icon}
iconClassName={_s.fillPrimary} iconClassName={_s.fillNavigation}
iconSize='14px' iconSize='18px'
/> />
)) ))
} }
@ -181,7 +191,7 @@ class NavigationBarButtonDivider extends PureComponent {
render() { render() {
return ( return (
<div className={[_s.default, _s.height20PX, _s.width1PX, _s.mr10, _s.ml10, _s.bgBrandDark].join(' ')} /> <div className={[_s.default, _s.height20PX, _s.width1PX, _s.mr10, _s.ml10, _s.bgNavigationBlend].join(' ')} />
) )
} }
@ -218,18 +228,18 @@ class NavigationBarButton extends PureComponent {
cursorPointer: 1, cursorPointer: 1,
bgTransparent: 1, bgTransparent: 1,
noUnderline: 1, noUnderline: 1,
colorNavigation: 1,
px10: !!title, px10: !!title,
px5: !title, px5: !title,
colorWhite: !!title, colorWhite: !!title,
fs13PX: !!title, fs13PX: !!title,
fontWeightNormal: !!title, fontWeightNormal: !!title,
textUppercase: !!title, textUppercase: !!title,
bgBrandDark_onHover: !!title,
}) })
const iconClasses = CX({ const iconClasses = CX({
fillWhite: !!title || active, fillNavigation: !!title || active,
fillBrandDark: !title, fillNavigationBlend: !title,
mr10: !!title, mr10: !!title,
}) })
@ -240,7 +250,6 @@ class NavigationBarButton extends PureComponent {
to={to} to={to}
href={href} href={href}
attrTitle={attrTitle} attrTitle={attrTitle}
color='white'
className={classes} className={classes}
noClasses noClasses
> >

View File

@ -2,11 +2,12 @@ import { Fragment } from 'react'
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl' import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'
import ImmutablePureComponent from 'react-immutable-pure-component' import ImmutablePureComponent from 'react-immutable-pure-component'
import ImmutablePropTypes from 'react-immutable-proptypes' import ImmutablePropTypes from 'react-immutable-proptypes'
import { openModal } from '../../actions/modal'
import { MODAL_GROUP_MEMBERS } from '../../constants'
import { shortNumberFormat } from '../../utils/numbers' import { shortNumberFormat } from '../../utils/numbers'
import PanelLayout from './panel_layout' import PanelLayout from './panel_layout'
import Button from '../button' import Button from '../button'
import Divider from '../divider' import Divider from '../divider'
import Heading from '../heading'
import Icon from '../icon' import Icon from '../icon'
import Text from '../text' import Text from '../text'
import RelativeTimestamp from '../relative_timestamp' import RelativeTimestamp from '../relative_timestamp'
@ -16,20 +17,31 @@ const messages = defineMessages({
members: { id: 'members', defaultMessage: 'Members' }, members: { id: 'members', defaultMessage: 'Members' },
}) })
const mapDispatchToProps = (dispatch) => ({
onOpenGroupMembersModal(groupId) {
console.log("onOpenGroupMembersModal:", groupId)
dispatch(openModal(MODAL_GROUP_MEMBERS, { groupId }))
},
})
export default export default
@injectIntl @injectIntl
@connect(null, mapDispatchToProps)
class GroupInfoPanel extends ImmutablePureComponent { class GroupInfoPanel extends ImmutablePureComponent {
static propTypes = { static propTypes = {
group: ImmutablePropTypes.list.isRequired, group: ImmutablePropTypes.map.isRequired,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
onOpenGroupMembersModal: PropTypes.func.isRequired,
}
handleOnOpenGroupMembersModal = () => {
this.props.onOpenGroupMembersModal(this.props.group.get('id'))
} }
render() { render() {
const { intl, group } = this.props const { intl, group } = this.props
console.log("group:", group)
return ( return (
<PanelLayout title={intl.formatMessage(messages.title)}> <PanelLayout title={intl.formatMessage(messages.title)}>
{ {
@ -53,10 +65,10 @@ class GroupInfoPanel extends ImmutablePureComponent {
</div> </div>
<Button <Button
isText isText
to={`/groups/${group.get('id')}/members`}
color='brand' color='brand'
backgroundColor='none' backgroundColor='none'
className={_s.mlAuto} className={_s.mlAuto}
onClick={this.handleOnOpenGroupMembersModal}
> >
<Text color='inherit' weight='medium' size='normal' className={_s.underline_onHover}> <Text color='inherit' weight='medium' size='normal' className={_s.underline_onHover}>
{shortNumberFormat(group.get('member_count'))} {shortNumberFormat(group.get('member_count'))}

View File

@ -65,8 +65,8 @@ class WhoToFollowPanel extends ImmutablePureComponent {
<PanelLayout <PanelLayout
noPadding noPadding
title={intl.formatMessage(messages.title)} title={intl.formatMessage(messages.title)}
footerButtonTitle={intl.formatMessage(messages.show_more)} // footerButtonTitle={intl.formatMessage(messages.show_more)}
footerButtonTo='/explore' // footerButtonTo='/explore'
> >
<div className={_s.default}> <div className={_s.default}>
{ {

View File

@ -1,47 +1,41 @@
import ImmutablePureComponent from 'react-immutable-pure-component' import ImmutablePureComponent from 'react-immutable-pure-component'
import ImmutablePropTypes from 'react-immutable-proptypes' import ImmutablePropTypes from 'react-immutable-proptypes'
import { defineMessages, injectIntl } from 'react-intl' import { defineMessages, injectIntl } from 'react-intl'
import { quoteCompose } from '../../actions/compose' import {
import { repost, unrepost } from '../../actions/interactions' MODAL_GROUP_CREATE,
MODAL_GROUP_MEMBERS,
MODAL_GROUP_REMOVED_ACCOUNTS,
} from '../../constants'
import { openModal } from '../../actions/modal' import { openModal } from '../../actions/modal'
import { boostModal, me } from '../../initial_state' import { closePopover } from '../../actions/popover'
import { me } from '../../initial_state'
import PopoverLayout from './popover_layout' import PopoverLayout from './popover_layout'
import List from '../list' import List from '../list'
const messages = defineMessages({ const messages = defineMessages({
repost: { id: 'repost', defaultMessage: 'Repost' }, groupMembers: { id: 'group_members', defaultMessage: 'Group members' },
repostWithComment: { id: 'repost_with_comment', defaultMessage: 'Repost with comment' }, removedMembers: { id: 'group_removed_members', defaultMessage: 'Removed accounts' },
editGroup: { id: 'edit_group', defaultMessage: 'Edit group' },
}); });
const mapDispatchToProps = (dispatch, { intl }) => ({ const mapDispatchToProps = (dispatch) => ({
onQuote (status, router) {
if (!me) return dispatch(openModal('UNAUTHORIZED'))
dispatch((_, getState) => { onOpenEditGroup(group) {
const state = getState(); dispatch(closePopover())
if (state.getIn(['compose', 'text']).trim().length !== 0) { dispatch(openModal(MODAL_GROUP_CREATE, { group }))
dispatch(openModal('CONFIRM', {
message: intl.formatMessage(messages.quoteMessage),
confirm: intl.formatMessage(messages.quoteConfirm),
onConfirm: () => dispatch(quoteCompose(status, router)),
}));
} else {
dispatch(quoteCompose(status, router));
}
});
}, },
onRepost (status) { onOpenRemovedMembers(groupId) {
if (!me) return dispatch(openModal('UNAUTHORIZED')) dispatch(closePopover())
dispatch(openModal(MODAL_GROUP_REMOVED_ACCOUNTS, { groupId }))
if (status.get('reblogged')) {
dispatch(unrepost(status));
} else {
dispatch(repost(status));
}
}, },
});
onOpenGroupMembers(groupId) {
dispatch(closePopover())
dispatch(openModal(MODAL_GROUP_MEMBERS, { groupId }))
},
});
export default export default
@injectIntl @injectIntl
@ -50,19 +44,24 @@ class GroupOptionsPopover extends ImmutablePureComponent {
static defaultProps = { static defaultProps = {
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
status: ImmutablePropTypes.map.isRequired, group: ImmutablePropTypes.map.isRequired,
onQuote: PropTypes.func.isRequired, onOpenEditGroup: PropTypes.func.isRequired,
onRepost: PropTypes.func.isRequired, onOpenRemovedMembers: PropTypes.func.isRequired,
onOpenGroupMembers: PropTypes.func.isRequired,
} }
updateOnProps = ['status'] updateOnProps = ['group']
handleOnRepost = () => {
handleEditGroup = () => {
this.props.onOpenEditGroup(this.props.group)
} }
handleOnQuote = () => { handleOnOpenRemovedMembers = () => {
this.props.onOpenRemovedMembers(this.props.group.get('id'))
}
handleOnOpenGroupMembers = () => {
this.props.onOpenGroupMembers(this.props.group.get('id'))
} }
render() { render() {
@ -71,22 +70,28 @@ class GroupOptionsPopover extends ImmutablePureComponent {
const listItems = [ const listItems = [
{ {
hideArrow: true, hideArrow: true,
icon: 'repost', icon: 'group',
title: intl.formatMessage(messages.repost), title: intl.formatMessage(messages.groupMembers),
onClick: this.handleOnRepost, onClick: this.handleOnOpenGroupMembers,
},
{
hideArrow: true,
icon: 'block',
title: intl.formatMessage(messages.removedMembers),
onClick: this.handleOnOpenRemovedMembers,
}, },
{ {
hideArrow: true, hideArrow: true,
icon: 'pencil', icon: 'pencil',
title: intl.formatMessage(messages.repostWithComment), title: intl.formatMessage(messages.editGroup),
onClick: this.handleBlockDomain, onClick: this.handleEditGroup,
} }
] ]
return ( return (
<PopoverLayout> <PopoverLayout width={210}>
<List <List
scrollKey='repost_options' scrollKey='group_options'
items={listItems} items={listItems}
size='large' size='large'
/> />

View File

@ -3,6 +3,7 @@ import {
POPOVER_DATE_PICKER, POPOVER_DATE_PICKER,
POPOVER_EMOJI_PICKER, POPOVER_EMOJI_PICKER,
POPOVER_GROUP_INFO, POPOVER_GROUP_INFO,
POPOVER_GROUP_OPTIONS,
POPOVER_PROFILE_OPTIONS, POPOVER_PROFILE_OPTIONS,
POPOVER_REPOST_OPTIONS, POPOVER_REPOST_OPTIONS,
POPOVER_SEARCH, POPOVER_SEARCH,
@ -17,6 +18,7 @@ import {
DatePickerPopover, DatePickerPopover,
EmojiPickerPopover, EmojiPickerPopover,
GroupInfoPopover, GroupInfoPopover,
GroupOptionsPopover,
ProfileOptionsPopover, ProfileOptionsPopover,
RepostOptionsPopover, RepostOptionsPopover,
SearchPopover, SearchPopover,
@ -34,6 +36,7 @@ POPOVER_COMPONENTS[POPOVER_CONTENT_WARNING] = ContentWarningPopover
POPOVER_COMPONENTS[POPOVER_DATE_PICKER] = DatePickerPopover POPOVER_COMPONENTS[POPOVER_DATE_PICKER] = DatePickerPopover
POPOVER_COMPONENTS[POPOVER_EMOJI_PICKER] = EmojiPickerPopover POPOVER_COMPONENTS[POPOVER_EMOJI_PICKER] = EmojiPickerPopover
POPOVER_COMPONENTS[POPOVER_GROUP_INFO] = GroupInfoPopover POPOVER_COMPONENTS[POPOVER_GROUP_INFO] = GroupInfoPopover
POPOVER_COMPONENTS[POPOVER_GROUP_OPTIONS] = GroupOptionsPopover
POPOVER_COMPONENTS[POPOVER_PROFILE_OPTIONS] = ProfileOptionsPopover POPOVER_COMPONENTS[POPOVER_PROFILE_OPTIONS] = ProfileOptionsPopover
POPOVER_COMPONENTS[POPOVER_REPOST_OPTIONS] = RepostOptionsPopover POPOVER_COMPONENTS[POPOVER_REPOST_OPTIONS] = RepostOptionsPopover
POPOVER_COMPONENTS[POPOVER_SEARCH] = SearchPopover POPOVER_COMPONENTS[POPOVER_SEARCH] = SearchPopover

View File

@ -4,17 +4,11 @@ import Icon from './icon'
export default class PullToRefresher extends PureComponent { export default class PullToRefresher extends PureComponent {
static propTypes = {
children: PropTypes.any,
}
render() { render() {
const { children } = this.props
return ( return (
<Responsive max={BREAKPOINT_EXTRA_SMALL}> <Responsive max={BREAKPOINT_EXTRA_SMALL}>
<div className={[_s.default, _s.posAbs, _s.left0, _s.right0, _s.topNeg60PX].join(' ')}> <div className={[_s.default, _s.alignItemsCenter, _s.posAbs, _s.left0, _s.right0, _s.topNeg80PX].join(' ')}>
<Icon id='loading' size='20px' /> <Icon id='loading' size='24px' />
</div> </div>
</Responsive> </Responsive>
) )

View File

@ -128,6 +128,10 @@ export default class ScrollableList extends PureComponent {
const { innerHeight } = this.window; const { innerHeight } = this.window;
const offset = scrollHeight - scrollTop - innerHeight; const offset = scrollHeight - scrollTop - innerHeight;
if (scrollTop < -60 && this.props.onReload) {
// reload
}
if (600 > offset && this.props.onLoadMore && this.props.hasMore && !this.props.isLoading) { if (600 > offset && this.props.onLoadMore && this.props.hasMore && !this.props.isLoading) {
this.props.onLoadMore(); this.props.onLoadMore();
} }

View File

@ -141,21 +141,22 @@ export default class StatusCard extends ImmutablePureComponent {
const horizontal = (card.get('width') > card.get('height') && (card.get('width') + 100 >= width)) || card.get('type') !== 'link' || embedded const horizontal = (card.get('width') > card.get('height') && (card.get('width') + 100 >= width)) || card.get('type') !== 'link' || embedded
const interactive = card.get('type') !== 'link' const interactive = card.get('type') !== 'link'
const cardTitle = `${card.get('title')}`.trim()
const title = interactive ? const title = interactive ?
( (
<a <a
className={[_s.default, _s.displayFlex, _s.text, _s.noUnderline, _s.overflowWrapBreakWord, _s.colorPrimary, _s.fs15PX, _s.fontWeightMedium].join(' ')} className={[_s.default, _s.displayFlex, _s.text, _s.noUnderline, _s.overflowWrapBreakWord, _s.colorPrimary, _s.fs15PX, _s.fontWeightMedium].join(' ')}
href={card.get('url')} href={card.get('url')}
title={card.get('title')} title={cardTitle}
rel={DEFAULT_REL} rel={DEFAULT_REL}
target='_blank' target='_blank'
> >
{card.get('title')} {cardTitle}
</a> </a>
) )
: ( : (
<span className={[_s.default, _s.displayFlex, _s.text, _s.overflowWrapBreakWord, _s.colorPrimary, _s.fs15PX, _s.fontWeightMedium].join(' ')}> <span className={[_s.default, _s.displayFlex, _s.text, _s.overflowWrapBreakWord, _s.colorPrimary, _s.fs15PX, _s.fontWeightMedium].join(' ')}>
{card.get('title')} {cardTitle}
</span> </span>
) )

View File

@ -22,6 +22,7 @@ export const POPOVER_CONTENT_WARNING = 'CONTENT_WARNING'
export const POPOVER_DATE_PICKER = 'DATE_PICKER' export const POPOVER_DATE_PICKER = 'DATE_PICKER'
export const POPOVER_EMOJI_PICKER = 'EMOJI_PICKER' export const POPOVER_EMOJI_PICKER = 'EMOJI_PICKER'
export const POPOVER_GROUP_INFO = 'GROUP_INFO' export const POPOVER_GROUP_INFO = 'GROUP_INFO'
export const POPOVER_GROUP_OPTIONS = 'GROUP_OPTIONS'
export const POPOVER_PROFILE_OPTIONS = 'PROFILE_OPTIONS' export const POPOVER_PROFILE_OPTIONS = 'PROFILE_OPTIONS'
export const POPOVER_REPOST_OPTIONS = 'REPOST_OPTIONS' export const POPOVER_REPOST_OPTIONS = 'REPOST_OPTIONS'
export const POPOVER_SEARCH = 'SEARCH' export const POPOVER_SEARCH = 'SEARCH'
@ -44,8 +45,8 @@ export const MODAL_EMBED = 'EMBED'
export const MODAL_GIF_PICKER = 'GIF_PICKER' export const MODAL_GIF_PICKER = 'GIF_PICKER'
export const MODAL_GROUP_CREATE = 'GROUP_CREATE' export const MODAL_GROUP_CREATE = 'GROUP_CREATE'
export const MODAL_GROUP_DELETE = 'GROUP_DELETE' export const MODAL_GROUP_DELETE = 'GROUP_DELETE'
export const MODAL_GROUP_EDITOR = 'GROUP_EDITOR'
export const MODAL_GROUP_MEMBERS = 'GROUP_MEMBERS' export const MODAL_GROUP_MEMBERS = 'GROUP_MEMBERS'
export const MODAL_GROUP_REMOVED_ACCOUNTS = 'GROUP_REMOVED_ACCOUNTS'
export const MODAL_HASHTAG_TIMELINE_SETTINGS = 'HASHTAG_TIMELINE_SETTINGS' export const MODAL_HASHTAG_TIMELINE_SETTINGS = 'HASHTAG_TIMELINE_SETTINGS'
export const MODAL_HOME_TIMELINE_SETTINGS = 'HOME_TIMELINE_SETTINGS' export const MODAL_HOME_TIMELINE_SETTINGS = 'HOME_TIMELINE_SETTINGS'
export const MODAL_HOTKEYS = 'HOTKEYS' export const MODAL_HOTKEYS = 'HOTKEYS'

View File

@ -17,8 +17,6 @@ const mapStateToProps = (state, { account, commentsOnly = false }) => {
const path = commentsOnly ? `${accountId}:comments_only` : accountId const path = commentsOnly ? `${accountId}:comments_only` : accountId
console.log("commentsOnly, path:", commentsOnly, path)
return { return {
accountId, accountId,
statusIds: state.getIn(['timelines', `account:${path}`, 'items'], emptyList), statusIds: state.getIn(['timelines', `account:${path}`, 'items'], emptyList),

View File

@ -1,66 +1,80 @@
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component'
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes'
import debounce from 'lodash.debounce' import debounce from 'lodash.debounce'
import { import {
fetchMembers, fetchMembers,
expandMembers, expandMembers,
updateRole, updateRole,
createRemovedAccount, createRemovedAccount,
} from '../actions/groups'; } from '../actions/groups'
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl'
import Account from '../components/account'; import Account from '../components/account'
import ScrollableList from '../components/scrollable_list'; import ScrollableList from '../components/scrollable_list'
const mapStateToProps = (state, { params: { id } }) => ({ const mapStateToProps = (state, { groupId }) => ({
group: state.getIn(['groups', id]), group: state.getIn(['groups', groupId]),
relationships: state.getIn(['group_relationships', id]), relationships: state.getIn(['group_relationships', groupId]),
accountIds: state.getIn(['user_lists', 'groups', id, 'items']), accountIds: state.getIn(['user_lists', 'groups', groupId, 'items']),
hasMore: !!state.getIn(['user_lists', 'groups', id, 'next']), hasMore: !!state.getIn(['user_lists', 'groups', groupId, 'next']),
}); })
const mapDispatchToProps = (dispatch) => ({
onFetchMembers(groupId) {
dispatch(fetchMembers(groupId))
},
onExpandMembers(groupId) {
dispatch(expandMembers(groupId))
},
})
export default export default
@connect(mapStateToProps) @connect(mapStateToProps, mapDispatchToProps)
class GroupMembers extends ImmutablePureComponent { class GroupMembers extends ImmutablePureComponent {
static propTypes = { static propTypes = {
params: PropTypes.object.isRequired, groupId: PropTypes.string.isRequired,
dispatch: PropTypes.func.isRequired,
accountIds: ImmutablePropTypes.list, accountIds: ImmutablePropTypes.list,
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
}; onExpandMembers: PropTypes.func.isRequired,
onFetchMembers: PropTypes.func.isRequired,
}
componentWillMount() { componentWillMount() {
const { params: { id } } = this.props; const { groupId } = this.props
this.props.dispatch(fetchMembers(id)); this.props.onFetchMembers(groupId)
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if (nextProps.params.id !== this.props.params.id) { if (nextProps.groupId !== this.props.groupId) {
this.props.dispatch(fetchMembers(nextProps.params.id)); this.props.onFetchMembers(nextProps.groupId)
} }
} }
handleLoadMore = debounce(() => { handleLoadMore = debounce(() => {
this.props.dispatch(expandMembers(this.props.params.id)); this.props.onExpandMembers(this.props.groupId)
}, 300, { leading: true }); }, 300, { leading: true })
render() { render() {
const { accountIds, hasMore, group, relationships, dispatch } = this.props; const {
accountIds,
if (!group || !accountIds || !relationships) { hasMore,
return <LoadingIndicator /> group,
} relationships,
dispatch,
} = this.props
return ( return (
<ScrollableList <ScrollableList
scrollKey='members' scrollKey='group-members'
hasMore={hasMore} hasMore={hasMore}
showLoading={(!group || !accountIds || !relationships)}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
emptyMessage={<FormattedMessage id='group.members.empty' defaultMessage='This group does not has any members.' />} emptyMessage={<FormattedMessage id='group.members.empty' defaultMessage='This group does not has any members.' />}
> >
{accountIds.map(id => { {
let menu = []; accountIds && accountIds.map((id) => {
let menu = []
if (relationships.get('admin')) { if (relationships.get('admin')) {
menu = [ menu = [
@ -70,17 +84,18 @@ class GroupMembers extends ImmutablePureComponent {
} }
return ( return (
<div className="group-account-wrapper" key={id}> <Account
<Account id={id} actionIcon="none" onActionClick={() => true} /> compact
{ /* key={id}
menu.length > 0 && <DropdownMenuContainer items={menu} icon='ellipsis-h' size={18} direction='right' /> id={id}
*/ actionIcon='ellipsis'
onActionClick={() => true}
/>
)
})
} }
</div>
);
})}
</ScrollableList> </ScrollableList>
); )
} }
} }

View File

@ -1,26 +1,25 @@
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component'
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes'
import debounce from 'lodash.debounce' import debounce from 'lodash.debounce'
import ColumnIndicator from '../components/column_indicator';
import { import {
fetchRemovedAccounts, fetchRemovedAccounts,
expandRemovedAccounts, expandRemovedAccounts,
removeRemovedAccount, removeRemovedAccount,
} from '../actions/groups'; } from '../actions/groups'
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl'
import Account from '../components/account'; import Account from '../components/account'
import ScrollableList from '../components/scrollable_list'; import ScrollableList from '../components/scrollable_list'
import { defineMessages, injectIntl } from 'react-intl'; import { defineMessages, injectIntl } from 'react-intl'
const messages = defineMessages({ const messages = defineMessages({
remove: { id: 'groups.removed_accounts', defaultMessage: 'Allow joining' }, remove: { id: 'groups.removed_accounts', defaultMessage: 'Allow joining' },
}); })
const mapStateToProps = (state, { params: { id } }) => ({ const mapStateToProps = (state, { groupId }) => ({
group: state.getIn(['groups', id]), group: state.getIn(['groups', groupId]),
accountIds: state.getIn(['user_lists', 'groups_removed_accounts', id, 'items']), accountIds: state.getIn(['user_lists', 'groups_removed_accounts', groupId, 'items']),
hasMore: !!state.getIn(['user_lists', 'groups_removed_accounts', id, 'next']), hasMore: !!state.getIn(['user_lists', 'groups_removed_accounts', groupId, 'next']),
}); })
export default export default
@connect(mapStateToProps) @connect(mapStateToProps)
@ -28,49 +27,50 @@ export default
class GroupRemovedAccounts extends ImmutablePureComponent { class GroupRemovedAccounts extends ImmutablePureComponent {
static propTypes = { static propTypes = {
params: PropTypes.object.isRequired, groupId: PropTypes.string.isRequired,
dispatch: PropTypes.func.isRequired, dispatch: PropTypes.func.isRequired,
accountIds: ImmutablePropTypes.list, accountIds: ImmutablePropTypes.list,
hasMore: PropTypes.bool, hasMore: PropTypes.bool,
}; }
componentWillMount() { componentWillMount() {
const { params: { id } } = this.props; const { groupId } = this.props
this.props.dispatch(fetchRemovedAccounts(id)); this.props.dispatch(fetchRemovedAccounts(groupId))
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if (nextProps.params.id !== this.props.params.id) { if (nextProps.groupId !== this.props.groupId) {
this.props.dispatch(fetchRemovedAccounts(nextProps.params.id)); this.props.dispatch(fetchRemovedAccounts(nextProps.groupId))
} }
} }
handleLoadMore = debounce(() => { handleLoadMore = debounce(() => {
this.props.dispatch(expandRemovedAccounts(this.props.params.id)); this.props.dispatch(expandRemovedAccounts(this.props.groupId))
}, 300, { leading: true }); }, 300, { leading: true })
render() { render() {
const { accountIds, hasMore, group, intl } = this.props; const { accountIds, hasMore, group, intl } = this.props
if (!group || !accountIds) {
return <ColumnIndicator type='loading' />
}
return ( return (
<ScrollableList <ScrollableList
scrollKey='removed_accounts' scrollKey='removed_accounts'
hasMore={hasMore} hasMore={hasMore}
showLoading={(!group || !accountIds)}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
emptyMessage={<FormattedMessage id='group.removed_accounts.empty' defaultMessage='This group does not has any removed accounts.' />} emptyMessage={<FormattedMessage id='group.removed_accounts.empty' defaultMessage='This group does not has any removed accounts.' />}
> >
{accountIds.map(id => (<Account {
accountIds && accountIds.map((id) => (
<Account
key={id} key={id}
id={id} id={id}
actionIcon='remove' actionIcon='subtract'
onActionClick={() => this.props.dispatch(removeRemovedAccount(group.get('id'), id))} onActionClick={() => this.props.dispatch(removeRemovedAccount(group.get('id'), id))}
actionTitle={intl.formatMessage(messages.remove)} actionTitle={intl.formatMessage(messages.remove)}
/>))} />
))
}
</ScrollableList> </ScrollableList>
) )
} }

View File

@ -229,7 +229,7 @@ class ListEdit extends ImmutablePureComponent {
key={`remove-from-list-${accountId}`} key={`remove-from-list-${accountId}`}
id={accountId} id={accountId}
onActionClick={() => this.handleAddOrRemoveFromList(accountId)} onActionClick={() => this.handleAddOrRemoveFromList(accountId)}
actionIcon={'subtract'} actionIcon='subtract'
/> />
)) ))
} }

View File

@ -153,8 +153,8 @@ class SwitchingArea extends PureComponent {
<WrappedRoute path='/groups/browse/admin' exact page={GroupsPage} component={GroupsCollection} content={children} componentParams={{ activeTab: 'admin' }} /> <WrappedRoute path='/groups/browse/admin' exact page={GroupsPage} component={GroupsCollection} content={children} componentParams={{ activeTab: 'admin' }} />
<WrappedRoute path='/groups/create' page={ModalPage} component={GroupCreate} content={children} componentParams={{ title: 'Create Group' }} /> <WrappedRoute path='/groups/create' page={ModalPage} component={GroupCreate} content={children} componentParams={{ title: 'Create Group' }} />
<WrappedRoute path='/groups/:id/members' page={GroupPage} component={GroupMembers} content={children} /> { /* <WrappedRoute path='/groups/:id/members' page={GroupPage} component={GroupMembers} content={children} />
<WrappedRoute path='/groups/:id/removed-accounts' page={GroupPage} component={GroupRemovedAccounts} content={children} /> <WrappedRoute path='/groups/:id/removed-accounts' page={GroupPage} component={GroupRemovedAccounts} content={children} /> */}
<WrappedRoute path='/groups/:id/edit' page={ModalPage} component={GroupCreate} content={children} componentParams={{ title: 'Edit Group' }} /> <WrappedRoute path='/groups/:id/edit' page={ModalPage} component={GroupCreate} content={children} componentParams={{ title: 'Edit Group' }} />
<WrappedRoute path='/groups/:id' page={GroupPage} component={GroupTimeline} content={children} /> <WrappedRoute path='/groups/:id' page={GroupPage} component={GroupTimeline} content={children} />
@ -208,11 +208,12 @@ class SwitchingArea extends PureComponent {
<Redirect from='/@:username/posts/:statusId' to='/:username/posts/:statusId' exact /> <Redirect from='/@:username/posts/:statusId' to='/:username/posts/:statusId' exact />
<WrappedRoute path='/:username/posts/:statusId' publicRoute exact page={BasicPage} component={StatusFeature} content={children} componentParams={{ title: 'Status' }} /> <WrappedRoute path='/:username/posts/:statusId' publicRoute exact page={BasicPage} component={StatusFeature} content={children} componentParams={{ title: 'Status' }} />
{ /*
<Redirect from='/@:username/posts/:statusId/reposts' to='/:username/posts/:statusId/reposts' /> <Redirect from='/@:username/posts/:statusId/reposts' to='/:username/posts/:statusId/reposts' />
<WrappedRoute path='/:username/posts/:statusId/reposts' page={BasicPage} component={StatusReposts} content={children} componentParams={{ title: 'Reposts' }} /> <WrappedRoute path='/:username/posts/:statusId/reposts' page={BasicPage} component={StatusReposts} content={children} componentParams={{ title: 'Reposts' }} />
<Redirect from='/@:username/posts/:statusId/likes' to='/:username/posts/:statusId/likes' /> <Redirect from='/@:username/posts/:statusId/likes' to='/:username/posts/:statusId/likes' />
<WrappedRoute path='/:username/posts/:statusId/likes' page={BasicPage} component={StatusLikes} content={children} componentParams={{ title: 'Likes' }} /> <WrappedRoute path='/:username/posts/:statusId/likes' page={BasicPage} component={StatusLikes} content={children} componentParams={{ title: 'Likes' }} /> */ }
<WrappedRoute page={ErrorPage} component={GenericNotFound} content={children} /> <WrappedRoute page={ErrorPage} component={GenericNotFound} content={children} />
</Switch> </Switch>

View File

@ -29,9 +29,10 @@ export function GroupsCollection() { return import(/* webpackChunkName: "feature
export function GroupCreate() { return import(/* webpackChunkName: "features/group_create" */'../../group_create') } export function GroupCreate() { return import(/* webpackChunkName: "features/group_create" */'../../group_create') }
export function GroupCreateModal() { return import(/* webpackChunkName: "components/group_create_modal" */'../../../components/modal/group_create_modal') } export function GroupCreateModal() { return import(/* webpackChunkName: "components/group_create_modal" */'../../../components/modal/group_create_modal') }
export function GroupDeleteModal() { return import(/* webpackChunkName: "components/group_delete_modal" */'../../../components/modal/group_delete_modal') } export function GroupDeleteModal() { return import(/* webpackChunkName: "components/group_delete_modal" */'../../../components/modal/group_delete_modal') }
export function GroupEditorModal() { return import(/* webpackChunkName: "components/group_editor_modal" */'../../../components/modal/group_editor_modal') } export function GroupRemovedAccountsModal() { return import(/* webpackChunkName: "components/group_removed_accounts_modal" */'../../../components/modal/group_removed_accounts_modal') }
export function GroupMembersModal() { return import(/* webpackChunkName: "components/group_members_modal" */'../../../components/modal/group_members_modal') } export function GroupMembersModal() { return import(/* webpackChunkName: "components/group_members_modal" */'../../../components/modal/group_members_modal') }
export function GroupInfoPopover() { return import(/* webpackChunkName: "components/group_info_popover" */'../../../components/popover/group_info_popover') } export function GroupInfoPopover() { return import(/* webpackChunkName: "components/group_info_popover" */'../../../components/popover/group_info_popover') }
export function GroupOptionsPopover() { return import(/* webpackChunkName: "components/group_options_popover" */'../../../components/popover/group_options_popover') }
export function GroupMembers() { return import(/* webpackChunkName: "features/group_members" */'../../group_members') } export function GroupMembers() { return import(/* webpackChunkName: "features/group_members" */'../../group_members') }
export function GroupRemovedAccounts() { return import(/* webpackChunkName: "features/group_removed_accounts" */'../../group_removed_accounts') } export function GroupRemovedAccounts() { return import(/* webpackChunkName: "features/group_removed_accounts" */'../../group_removed_accounts') }
export function GroupTimeline() { return import(/* webpackChunkName: "features/group_timeline" */'../../group_timeline') } export function GroupTimeline() { return import(/* webpackChunkName: "features/group_timeline" */'../../group_timeline') }

View File

@ -7,6 +7,7 @@ export default class DefaultLayout extends PureComponent {
children: PropTypes.node.isRequired, children: PropTypes.node.isRequired,
layout: PropTypes.object, layout: PropTypes.object,
showBackBtn: PropTypes.bool, showBackBtn: PropTypes.bool,
noComposeButton: PropTypes.bool,
tabs: PropTypes.array, tabs: PropTypes.array,
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
} }
@ -19,6 +20,7 @@ export default class DefaultLayout extends PureComponent {
showBackBtn, showBackBtn,
tabs, tabs,
title, title,
noComposeButton,
} = this.props } = this.props
return ( return (
@ -28,6 +30,7 @@ export default class DefaultLayout extends PureComponent {
showBackBtn={showBackBtn} showBackBtn={showBackBtn}
tabs={tabs} tabs={tabs}
title={title} title={title}
noComposeButton={noComposeButton}
> >
{children} {children}
</Layout> </Layout>

View File

@ -17,6 +17,7 @@ export default class BasicPage extends PureComponent {
return ( return (
<DefaultLayout <DefaultLayout
noComposeButton
showBackBtn showBackBtn
title={title} title={title}
layout={( layout={(

View File

@ -33,7 +33,7 @@ class GroupPage extends ImmutablePureComponent {
static propTypes = { static propTypes = {
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
group: ImmutablePropTypes.map, group: ImmutablePropTypes.map,
chilren: PropTypes.node.isRequired, children: PropTypes.node.isRequired,
relationships: ImmutablePropTypes.map, relationships: ImmutablePropTypes.map,
fetchGroup: PropTypes.func.isRequired, fetchGroup: PropTypes.func.isRequired,
} }

View File

@ -77,6 +77,10 @@ class HomePage extends PureComponent {
icon: 'ellipsis', icon: 'ellipsis',
onClick: onOpenHomePageSettingsModal, onClick: onOpenHomePageSettingsModal,
}, },
{
icon: 'search',
onClick: onOpenHomePageSettingsModal,
},
]} ]}
layout={( layout={(
<Fragment> <Fragment>

View File

@ -1,8 +1,11 @@
import { Fragment } from 'react' import { Fragment } from 'react'
import { defineMessages, injectIntl } from 'react-intl' import { defineMessages, injectIntl } from 'react-intl'
import { BREAKPOINT_EXTRA_SMALL } from '../constants'
import Responsive from '../features/ui/util/responsive_component'
import PageTitle from '../features/ui/util/page_title' import PageTitle from '../features/ui/util/page_title'
import LinkFooter from '../components/link_footer' import LinkFooter from '../components/link_footer'
import SearchFilterPanel from '../components/panel/search_filter_panel' import SearchFilterPanel from '../components/panel/search_filter_panel'
import Search from '../components/search'
import Layout from '../layouts/layout' import Layout from '../layouts/layout'
const messages = defineMessages({ const messages = defineMessages({
@ -59,6 +62,11 @@ class SearchPage extends PureComponent {
)} )}
> >
<PageTitle path={title} /> <PageTitle path={title} />
<Responsive max={BREAKPOINT_EXTRA_SMALL}>
<Search />
</Responsive>
{children} {children}
</Layout> </Layout>
) )

View File

@ -19,11 +19,8 @@ const initialState = ImmutableMap({
home: ImmutableMap({ home: ImmutableMap({
shows: ImmutableMap({ shows: ImmutableMap({
photos: true,
polls: true,
reply: true, reply: true,
repost: true, repost: true,
videos: true,
}), }),
}), }),

View File

@ -36,6 +36,12 @@
--text_color_tertiary: #777; --text_color_tertiary: #777;
--border_color_secondary: #ececed; --border_color_secondary: #ececed;
/* Navigation bar. Only themes. Non-editable */
--navigation_background: var(--color_brand);
--navigation_blend: var(--color_brand-dark);
--navigation_primary: var(--color_white);
--navigation_brand: var(--color_white);
} }
:root[no-circle] { :root[no-circle] {
@ -59,6 +65,12 @@
--text_color_tertiary: #656565 !important; --text_color_tertiary: #656565 !important;
--border_color_secondary: #424141 !important; --border_color_secondary: #424141 !important;
/* Navigation bar. Only themes. Non-editable */
--navigation_background: #000 !important;
--navigation_blend: var(--text_color_secondary) !important;
--navigation_primary: var(--text_color_primary) !important;
--navigation_brand: var(--color_brand) !important;
} }
:root[theme='black'] { :root[theme='black'] {
@ -74,6 +86,12 @@
--text_color_tertiary: #656565 !important; --text_color_tertiary: #656565 !important;
--border_color_secondary: #212020 !important; --border_color_secondary: #212020 !important;
/* Navigation bar. Only themes. Non-editable */
--navigation_background: #000 !important;
--navigation_blend: var(--text_color_secondary) !important;
--navigation_primary: var(--text_color_primary) !important;
--navigation_brand: var(--color_brand) !important;
} }
html, html,
@ -386,7 +404,7 @@ body {
/* */ /* */
.topNeg60PX { top: -60px; } .topNeg80PX { top: -80px; }
.top0 { top: 0; } .top0 { top: 0; }
.top80PX { top: 80px; } .top80PX { top: 80px; }
.top60PC { top: 60%; } .top60PC { top: 60%; }
@ -850,6 +868,30 @@ body {
padding-bottom: env(safe-area-inset-bottom, 0); padding-bottom: env(safe-area-inset-bottom, 0);
} }
.bgNavigation {
background-color: var(--navigation_background);
}
.bgNavigationBlend {
background-color: var(--navigation_blend);
}
.fillNavigation {
fill: var(--navigation_primary);
}
.fillNavigationBlend {
fill: var(--navigation_blend);
}
.colorNavigation {
color: var(--navigation_primary);
}
.fillNavigationBrand {
fill: var(--navigation_brand);
}
/** /**
* Rich Text Editor * Rich Text Editor
*/ */