This commit is contained in:
mgabdev
2020-02-29 10:42:47 -05:00
parent 3ca4ffcc6b
commit c6aa4e08a1
190 changed files with 1156 additions and 1042 deletions

View File

@@ -1 +1 @@
export { default } from './media_item';
export { default } from './media_item'

View File

@@ -1 +1 @@
export { default } from './account_gallery';
export { default } from './account_gallery'

View File

@@ -1 +1 @@
export { default } from './header';
export { default } from './header'

View File

@@ -1 +1 @@
export { default } from './inner_header';
export { default } from './inner_header'

View File

@@ -1 +1 @@
export { default } from './moved_note';
export { default } from './moved_note'

View File

@@ -1 +1 @@
export { default } from './profile_info_panel';
export { default } from './profile_info_panel'

View File

@@ -1 +1 @@
export { default } from './account_timeline';
export { default } from './account_timeline'

View File

@@ -1 +1 @@
export { default } from './blocks';
export { default } from './blocks'

View File

@@ -1 +1 @@
export { default } from './column_settings';
export { default } from './column_settings'

View File

@@ -1 +1 @@
export { default } from './community_timeline';
export { default } from './community_timeline'

View File

@@ -1 +1 @@
export { default } from './action_bar';
export { default } from './action_bar'

View File

@@ -1 +1 @@
export { default } from './character_counter';
export { default } from './character_counter'

View File

@@ -1 +1 @@
export { default } from './compose_form';
export { default } from './compose_form'

View File

@@ -1 +1 @@
export { default } from './emoji_picker_dropdown';
export { default } from './emoji_picker_dropdown'

View File

@@ -1 +1 @@
export { default } from './navigation_bar';
export { default } from './navigation_bar'

View File

@@ -1 +1 @@
export { default } from './poll_form';
export { default } from './poll_form'

View File

@@ -1 +1 @@
export { default } from './reply_indicator';
export { default } from './reply_indicator'

View File

@@ -1 +1 @@
export { default } from './search_results';
export { default } from './search_results'

View File

@@ -1 +1 @@
export { default } from './upload';
export { default } from './upload'

View File

@@ -1 +1 @@
export { default } from './upload_form';
export { default } from './upload_form'

View File

@@ -1 +1 @@
export { default } from './upload_progress';
export { default } from './upload_progress'

View File

@@ -1 +1 @@
export { default } from './warning';
export { default } from './warning'

View File

@@ -1 +1 @@
export { default } from './compose';
export { default } from './compose'

View File

@@ -1 +1 @@
export { default } from './domain_blocks';
export { default } from './domain_blocks'

View File

@@ -2,7 +2,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { debounce } from 'lodash';
import { fetchFavoritedStatuses, expandFavoritedStatuses } from '../../actions/favourites';
import { fetchFavoritedStatuses, expandFavoritedStatuses } from '../../actions/favorites';
import { meUsername } from '../../initial_state';
import StatusList from '../../components/status_list';
import ColumnIndicator from '../../components/column_indicator';
@@ -10,15 +10,15 @@ import ColumnIndicator from '../../components/column_indicator';
const mapStateToProps = (state, { params: { username } }) => {
return {
isMyAccount: (username.toLowerCase() === meUsername.toLowerCase()),
statusIds: state.getIn(['status_lists', 'favourites', 'items']),
isLoading: state.getIn(['status_lists', 'favourites', 'isLoading'], true),
hasMore: !!state.getIn(['status_lists', 'favourites', 'next']),
statusIds: state.getIn(['status_lists', 'favorites', 'items']),
isLoading: state.getIn(['status_lists', 'favorites', 'isLoading'], true),
hasMore: !!state.getIn(['status_lists', 'favorites', 'next']),
};
};
export default
@connect(mapStateToProps)
class Favourites extends ImmutablePureComponent {
class Favorites extends ImmutablePureComponent {
static propTypes = {
dispatch: PropTypes.func.isRequired,
@@ -46,11 +46,11 @@ class Favourites extends ImmutablePureComponent {
return (
<StatusList
statusIds={statusIds}
scrollKey='favourited_statuses'
scrollKey='favorited_statuses'
hasMore={hasMore}
isLoading={isLoading}
onLoadMore={this.handleLoadMore}
emptyMessage={<FormattedMessage id='empty_column.favourited_statuses' defaultMessage="You don't have any favourite gabs yet. When you favourite one, it will show up here." />}
emptyMessage={<FormattedMessage id='empty_column.favorited_statuses' defaultMessage="You don't have any favorite gabs yet. When you favorite one, it will show up here." />}
/>
);
}

View File

@@ -0,0 +1 @@
export { default } from './favorited_statuses'

View File

@@ -1 +0,0 @@
export { default } from './favourited_statuses';

View File

@@ -1 +1 @@
export { default } from './account_authorize';
export { default } from './account_authorize'

View File

@@ -1 +1 @@
export { default } from './follow_requests';
export { default } from './follow_requests'

View File

@@ -1,34 +1,36 @@
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { debounce } from 'lodash';
import { FormattedMessage } from 'react-intl';
import ColumnIndicator from '../../components/column_indicator';
import ImmutablePureComponent from 'react-immutable-pure-component'
import ImmutablePropTypes from 'react-immutable-proptypes'
import { debounce } from 'lodash'
import { defineMessages, injectIntl } from 'react-intl'
import ColumnIndicator from '../../components/column_indicator'
import {
fetchAccount,
fetchFollowers,
expandFollowers,
fetchAccountByUsername,
} from '../../actions/accounts';
import { me } from '../../initial_state';
import AccountContainer from '../../containers/account_container';
import ScrollableList from '../../components/scrollable_list';
} from '../../actions/accounts'
import { me } from '../../initial_state'
import AccountContainer from '../../containers/account_container'
import ScrollableList from '../../components/scrollable_list'
import Block from '../../components/block'
import Heading from '../../components/heading'
const mapStateToProps = (state, { params: { username } }) => {
const accounts = state.getIn(['accounts']);
const accountFetchError = (state.getIn(['accounts', -1, 'username'], '').toLowerCase() == username.toLowerCase());
const accounts = state.getIn(['accounts'])
const accountFetchError = (state.getIn(['accounts', -1, 'username'], '').toLowerCase() == username.toLowerCase())
let accountId = -1;
let accountId = -1
if (accountFetchError) {
accountId = null;
accountId = null
} else {
let account = accounts.find(acct => username.toLowerCase() == acct.getIn(['acct'], '').toLowerCase());
accountId = account ? account.getIn(['id'], null) : -1;
let account = accounts.find(acct => username.toLowerCase() == acct.getIn(['acct'], '').toLowerCase())
accountId = account ? account.getIn(['id'], null) : -1
}
const isBlocked = state.getIn(['relationships', accountId, 'blocked_by'], false);
const isLocked = state.getIn(['accounts', accountId, 'locked'], false);
const isFollowing = state.getIn(['relationships', accountId, 'following'], false);
const unavailable = (me == accountId) ? false : (isBlocked || (isLocked && !isFollowing));
const isBlocked = state.getIn(['relationships', accountId, 'blocked_by'], false)
const isLocked = state.getIn(['accounts', accountId, 'locked'], false)
const isFollowing = state.getIn(['relationships', accountId, 'following'], false)
const unavailable = (me == accountId) ? false : (isBlocked || (isLocked && !isFollowing))
return {
accountId,
@@ -36,69 +38,93 @@ const mapStateToProps = (state, { params: { username } }) => {
isAccount: !!state.getIn(['accounts', accountId]),
accountIds: state.getIn(['user_lists', 'followers', accountId, 'items']),
hasMore: !!state.getIn(['user_lists', 'followers', accountId, 'next']),
};
};
}
}
const messages = defineMessages({
followers: { id: 'account.followers', defaultMessage: 'Followers' },
empty: { id: 'account.followers.empty', defaultMessage: 'No one follows this user yet.' },
unavailable: { id: 'empty_column.account_unavailable', defaultMessage: 'Profile unavailable' },
})
export default
@connect(mapStateToProps)
@injectIntl
class Followers extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
accountIds: ImmutablePropTypes.list,
hasMore: PropTypes.bool,
isAccount: PropTypes.bool,
unavailable: PropTypes.bool,
};
}
componentWillMount() {
const { params: { username }, accountId } = this.props;
const { params: { username }, accountId } = this.props
if (accountId && accountId !== -1) {
this.props.dispatch(fetchAccount(accountId));
this.props.dispatch(fetchFollowers(accountId));
this.props.dispatch(fetchAccount(accountId))
this.props.dispatch(fetchFollowers(accountId))
} else {
this.props.dispatch(fetchAccountByUsername(username));
this.props.dispatch(fetchAccountByUsername(username))
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.accountId && nextProps.accountId !== -1 && (nextProps.accountId !== this.props.accountId && nextProps.accountId)) {
this.props.dispatch(fetchAccount(nextProps.accountId));
this.props.dispatch(fetchFollowers(nextProps.accountId));
this.props.dispatch(fetchAccount(nextProps.accountId))
this.props.dispatch(fetchFollowers(nextProps.accountId))
}
}
handleLoadMore = debounce(() => {
if (this.props.accountId && this.props.accountId !== -1) {
this.props.dispatch(expandFollowers(this.props.accountId));
this.props.dispatch(expandFollowers(this.props.accountId))
}
}, 300, { leading: true });
}, 300, { leading: true })
render() {
const { accountIds, hasMore, isAccount, accountId, unavailable } = this.props;
const {
accountIds,
hasMore,
isAccount,
accountId,
unavailable,
intl
} = this.props
if (!isAccount && accountId !== -1) {
return (<ColumnIndicator type='missing' />);
return <ColumnIndicator type='missing' />
} else if (accountId === -1 || (!accountIds)) {
return (<ColumnIndicator type='loading' />);
return <ColumnIndicator type='loading' />
} else if (unavailable) {
return (<ColumnIndicator type='error' message={<FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />} />);
return <ColumnIndicator type='error' message={intl.formatMessage(messages.unavailable)} />
}
return (
<ScrollableList
scrollKey='followers'
hasMore={hasMore}
onLoadMore={this.handleLoadMore}
emptyMessage={<FormattedMessage id='account.followers.empty' defaultMessage='No one follows this user yet.' />}
>
{accountIds.map(id =>
<AccountContainer key={id} id={id} withNote={false} />
)}
</ScrollableList>
);
<Block>
<div className={[_s.default, _s.paddingHorizontal15PX, _s.paddingVertical10PX, _s.justifyContentCenter, _s.borderColorSecondary, _s.borderBottom1PX].join(' ')}>
<Heading size='h3'>
{intl.formatMessage(messages.followers)}
</Heading>
</div>
<div className={[_s.default, _s.paddingHorizontal15PX, _s.paddingVertical10PX].join(' ')}>
<ScrollableList
scrollKey='followers'
hasMore={hasMore}
onLoadMore={this.handleLoadMore}
emptyMessage={intl.formatMessage(messages.empty)}
>
{accountIds.map((id, i) => (
<AccountContainer key={id} id={id} withNote={false} compact />
))}
</ScrollableList>
</div>
</Block>
)
}
}

View File

@@ -1 +1 @@
export { default } from './followers';
export { default } from './followers'

View File

@@ -1,34 +1,36 @@
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { debounce } from 'lodash';
import { FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component'
import ImmutablePropTypes from 'react-immutable-proptypes'
import { debounce } from 'lodash'
import { defineMessages, injectIntl } from 'react-intl'
import {
fetchAccount,
fetchFollowing,
expandFollowing,
fetchAccountByUsername,
} from '../../actions/accounts';
import { me } from '../../initial_state';
import AccountContainer from '../../containers/account_container';
import ColumnIndicator from '../../components/column_indicator';
import ScrollableList from '../../components/scrollable_list';
} from '../../actions/accounts'
import { me } from '../../initial_state'
import AccountContainer from '../../containers/account_container'
import ColumnIndicator from '../../components/column_indicator'
import ScrollableList from '../../components/scrollable_list'
import Block from '../../components/block'
import Heading from '../../components/heading'
const mapStateToProps = (state, { params: { username } }) => {
const accounts = state.getIn(['accounts']);
const accountFetchError = (state.getIn(['accounts', -1, 'username'], '').toLowerCase() == username.toLowerCase());
const accounts = state.getIn(['accounts'])
const accountFetchError = (state.getIn(['accounts', -1, 'username'], '').toLowerCase() == username.toLowerCase())
let accountId = -1;
let accountId = -1
if (accountFetchError) {
accountId = null;
accountId = null
} else {
let account = accounts.find(acct => username.toLowerCase() == acct.getIn(['acct'], '').toLowerCase());
accountId = account ? account.getIn(['id'], null) : -1;
let account = accounts.find(acct => username.toLowerCase() == acct.getIn(['acct'], '').toLowerCase())
accountId = account ? account.getIn(['id'], null) : -1
}
const isBlocked = state.getIn(['relationships', accountId, 'blocked_by'], false);
const isLocked = state.getIn(['accounts', accountId, 'locked'], false);
const isFollowing = state.getIn(['relationships', accountId, 'following'], false);
const unavailable = (me == accountId) ? false : (isBlocked || (isLocked && !isFollowing));
const isBlocked = state.getIn(['relationships', accountId, 'blocked_by'], false)
const isLocked = state.getIn(['accounts', accountId, 'locked'], false)
const isFollowing = state.getIn(['relationships', accountId, 'following'], false)
const unavailable = (me == accountId) ? false : (isBlocked || (isLocked && !isFollowing))
return {
accountId,
@@ -36,71 +38,93 @@ const mapStateToProps = (state, { params: { username } }) => {
isAccount: !!state.getIn(['accounts', accountId]),
accountIds: state.getIn(['user_lists', 'following', accountId, 'items']),
hasMore: !!state.getIn(['user_lists', 'following', accountId, 'next']),
};
};
}
}
const messages = defineMessages({
follows: { id: 'account.follows', defaultMessage: 'Follows' },
empty: { id: 'account.follows.empty', defaultMessage: 'This user doesn\'t follow anyone yet.' },
unavailable: { id: 'empty_column.account_unavailable', defaultMessage: 'Profile unavailable' },
})
export default
@connect(mapStateToProps)
@injectIntl
class Following extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
accountIds: ImmutablePropTypes.list,
hasMore: PropTypes.bool,
isAccount: PropTypes.bool,
unavailable: PropTypes.bool,
};
}
componentWillMount () {
const { params: { username }, accountId } = this.props;
componentWillMount() {
const { params: { username }, accountId } = this.props
if (accountId && accountId !== -1) {
this.props.dispatch(fetchAccount(accountId));
this.props.dispatch(fetchFollowing(accountId));
this.props.dispatch(fetchAccount(accountId))
this.props.dispatch(fetchFollowing(accountId))
} else {
this.props.dispatch(fetchAccountByUsername(username));
this.props.dispatch(fetchAccountByUsername(username))
}
}
componentWillReceiveProps (nextProps) {
componentWillReceiveProps(nextProps) {
if (nextProps.accountId && nextProps.accountId !== -1 && (nextProps.accountId !== this.props.accountId && nextProps.accountId)) {
this.props.dispatch(fetchAccount(nextProps.accountId));
this.props.dispatch(fetchFollowing(nextProps.accountId));
this.props.dispatch(fetchAccount(nextProps.accountId))
this.props.dispatch(fetchFollowing(nextProps.accountId))
}
}
handleLoadMore = debounce(() => {
if (this.props.accountId && this.props.accountId !== -1) {
this.props.dispatch(expandFollowing(this.props.accountId));
this.props.dispatch(expandFollowing(this.props.accountId))
}
}, 300, { leading: true });
}, 300, { leading: true })
render () {
const { accountIds, hasMore, isAccount, accountId, unavailable } = this.props;
render() {
const {
accountIds,
hasMore,
isAccount,
accountId,
unavailable,
intl
} = this.props
if (!isAccount && accountId !== -1) {
return ( <ColumnIndicator type='missing' /> );
return <ColumnIndicator type='missing' />
} else if (accountId === -1 || (!accountIds)) {
return ( <ColumnIndicator type='loading' /> );
return <ColumnIndicator type='loading' />
} else if (unavailable) {
return (<ColumnIndicator type='error' message={<FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />} />);
return <ColumnIndicator type='error' message={intl.formatMessage(messages.unavailable)} />
}
return (
<ScrollableList
scrollKey='following'
hasMore={hasMore}
onLoadMore={this.handleLoadMore}
emptyMessage={<FormattedMessage id='account.follows.empty' defaultMessage="This user doesn't follow anyone yet." />}
>
{accountIds.map(id =>
<AccountContainer key={id} id={id} withNote={false} />
)}
</ScrollableList>
);
<Block>
<div className={[_s.default, _s.paddingHorizontal15PX, _s.paddingVertical10PX, _s.justifyContentCenter, _s.borderColorSecondary, _s.borderBottom1PX].join(' ')}>
<Heading size='h3'>
{intl.formatMessage(messages.follows)}
</Heading>
</div>
<div className={[_s.default, _s.paddingHorizontal15PX, _s.paddingVertical10PX].join(' ')}>
<ScrollableList
scrollKey='following'
hasMore={hasMore}
onLoadMore={this.handleLoadMore}
emptyMessage={intl.formatMessage(messages.empty)}
>
{accountIds.map((id, i) => (
<AccountContainer key={id} id={id} withNote={false} compact />
))}
</ScrollableList>
</div>
</Block>
)
}
}

View File

@@ -1 +1 @@
export { default } from './following';
export { default } from './following'

View File

@@ -1 +1 @@
export { default } from './generic_not_found';
export { default } from './generic_not_found'

View File

@@ -1,7 +1,9 @@
import { changeValue, submit, reset } from '../../../actions/group_editor';
import Icon from '../../../components/icon';
import { defineMessages, injectIntl } from 'react-intl';
import classNames from 'classnames';
import { defineMessages, injectIntl } from 'react-intl'
import { changeValue, submit, reset } from '../../actions/group_editor'
import Block from '../../components/block'
import Button from '../../components/button'
import Icon from '../../components/icon'
import Input from '../../components/icon'
const messages = defineMessages({
title: { id: 'groups.form.title', defaultMessage: 'Enter a new group title' },
@@ -9,14 +11,14 @@ const messages = defineMessages({
coverImage: { id: 'groups.form.coverImage', defaultMessage: 'Upload a banner image' },
coverImageChange: { id: 'groups.form.coverImageChange', defaultMessage: 'Banner image selected' },
create: { id: 'groups.form.create', defaultMessage: 'Create group' },
});
})
const mapStateToProps = state => ({
title: state.getIn(['group_editor', 'title']),
description: state.getIn(['group_editor', 'description']),
coverImage: state.getIn(['group_editor', 'coverImage']),
disabled: state.getIn(['group_editor', 'isSubmitting']),
});
})
const mapDispatchToProps = dispatch => ({
onTitleChange: value => dispatch(changeValue('title', value)),
@@ -24,7 +26,7 @@ const mapDispatchToProps = dispatch => ({
onCoverImageChange: value => dispatch(changeValue('coverImage', value)),
onSubmit: routerHistory => dispatch(submit(routerHistory)),
reset: () => dispatch(reset()),
});
})
export default
@connect(mapStateToProps, mapDispatchToProps)
@@ -43,69 +45,70 @@ class Create extends PureComponent {
intl: PropTypes.object.isRequired,
onTitleChange: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
};
}
componentWillMount() {
this.props.reset();
this.props.reset()
}
handleTitleChange = e => {
this.props.onTitleChange(e.target.value);
this.props.onTitleChange(e.target.value)
}
handleDescriptionChange = e => {
this.props.onDescriptionChange(e.target.value);
this.props.onDescriptionChange(e.target.value)
}
handleCoverImageChange = e => {
this.props.onCoverImageChange(e.target.files[0]);
this.props.onCoverImageChange(e.target.files[0])
}
handleSubmit = e => {
e.preventDefault();
this.props.onSubmit(this.context.router.history);
e.preventDefault()
this.props.onSubmit(this.context.router.history)
}
render () {
const { title, description, coverImage, disabled, intl } = this.props;
render() {
const { title, description, coverImage, disabled, intl } = this.props
return (
<form className='group-form' onSubmit={this.handleSubmit}>
<div>
<input
className='standard'
type='text'
value={title}
disabled={disabled}
onChange={this.handleTitleChange}
placeholder={intl.formatMessage(messages.title)}
/>
</div>
<div>
<textarea
className='standard'
type='text'
value={description}
disabled={disabled}
onChange={this.handleDescriptionChange}
placeholder={intl.formatMessage(messages.description)}
/>
</div>
<div>
<label htmlFor='group_cover_image' className={classNames('group-form__file-label', { 'group-form__file-label--selected': coverImage !== null })}>
{intl.formatMessage(coverImage === null ? messages.coverImage : messages.coverImageChange)}
</label>
<input
type='file'
className='group-form__file'
id='group_cover_image'
disabled={disabled}
onChange={this.handleCoverImageChange}
/>
<button className='button'>{intl.formatMessage(messages.create)}</button>
</div>
</form>
);
<Block>
<form className='group-form' onSubmit={this.handleSubmit}>
<div>
<Input
type='text'
value={title}
disabled={disabled}
onChange={this.handleTitleChange}
placeholder={intl.formatMessage(messages.title)}
/>
</div>
<div>
<textarea
className='standard'
type='text'
value={description}
disabled={disabled}
onChange={this.handleDescriptionChange}
placeholder={intl.formatMessage(messages.description)}
/>
</div>
<div>
<label htmlFor='group_cover_image' className='group-form__file-label--selected'>
{intl.formatMessage(coverImage === null ? messages.coverImage : messages.coverImageChange)}
</label>
<input
type='file'
className='group-form__file'
id='group_cover_image'
disabled={disabled}
onChange={this.handleCoverImageChange}
/>
<button className='button'>{intl.formatMessage(messages.create)}</button>
</div>
</form>
</Block>
)
}
}

View File

@@ -0,0 +1 @@
export { default } from './group_create'

View File

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

View File

@@ -0,0 +1 @@
export { default } from './group_members'

View File

@@ -1,15 +1,15 @@
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { debounce } from 'lodash';
import ColumnIndicator from '../../../components/column_indicator';
import ColumnIndicator from '../../components/column_indicator';
import {
fetchRemovedAccounts,
expandRemovedAccounts,
removeRemovedAccount,
} from '../../../actions/groups';
} from '../../actions/groups';
import { FormattedMessage } from 'react-intl';
import AccountContainer from '../../../containers/account_container';
import ScrollableList from '../../../components/scrollable_list';
import AccountContainer from '../../containers/account_container';
import ScrollableList from '../../components/scrollable_list';
import { defineMessages, injectIntl } from 'react-intl';
const messages = defineMessages({

View File

@@ -0,0 +1 @@
export { default } from './group_removed_accounts'

View File

@@ -1,105 +1,98 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { Link } from 'react-router-dom';
import classNames from 'classnames';
import { fetchGroups } from '../../../actions/groups';
import { openModal } from '../../../actions/modal';
import { me } from '../../../initial_state';
import GroupCard from './card';
import GroupCreate from '../create';
import ImmutablePureComponent from 'react-immutable-pure-component'
import ImmutablePropTypes from 'react-immutable-proptypes'
import { injectIntl, defineMessages } from 'react-intl'
import { Link } from 'react-router-dom'
import classNames from 'classnames'
import { connectGroupStream } from '../../actions/streaming'
import { expandGroupTimeline } from '../../actions/timelines'
import StatusListContainer from '../../containers/status_list_container'
// import ColumnSettingsContainer from './containers/column_settings_container'
import ColumnIndicator from '../../components/column_indicator'
const messages = defineMessages({
heading: { id: 'column.groups', defaultMessage: 'Groups' },
create: { id: 'groups.create', defaultMessage: 'Create group' },
tab_featured: { id: 'groups.tab_featured', defaultMessage: 'Featured' },
tab_member: { id: 'groups.tab_member', defaultMessage: 'Member' },
tab_admin: { id: 'groups.tab_admin', defaultMessage: 'Manage' },
});
tabLatest: { id: 'group.timeline.tab_latest', defaultMessage: 'Latest' },
show: { id: 'group.timeline.show_settings', defaultMessage: 'Show settings' },
hide: { id: 'group.timeline.hide_settings', defaultMessage: 'Hide settings' },
empty: { id: 'empty_column.group', defaultMessage: 'There is nothing in this group yet.\nWhen members of this group post new statuses, they will appear here.' },
})
const mapStateToProps = (state, { activeTab }) => ({
groupIds: state.getIn(['group_lists', activeTab]),
account: state.getIn(['accounts', me]),
});
const mapStateToProps = (state, props) => ({
group: state.getIn(['groups', props.params.id]),
relationships: state.getIn(['group_relationships', props.params.id]),
hasUnread: state.getIn(['timelines', `group:${props.params.id}`, 'unread']) > 0,
})
export default
@connect(mapStateToProps)
@injectIntl
class Groups extends ImmutablePureComponent {
static propTypes = {
params: PropTypes.object.isRequired,
activeTab: PropTypes.string.isRequired,
showCreateForm: PropTypes.bool,
dispatch: PropTypes.func.isRequired,
groups: ImmutablePropTypes.map,
groupIds: ImmutablePropTypes.list,
intl: PropTypes.object.isRequired,
};
class GroupTimeline extends ImmutablePureComponent {
componentWillMount () {
this.props.dispatch(fetchGroups(this.props.activeTab));
static contextTypes = {
router: PropTypes.object,
}
componentDidUpdate(oldProps) {
if (this.props.activeTab && this.props.activeTab !== oldProps.activeTab) {
this.props.dispatch(fetchGroups(this.props.activeTab));
static propTypes = {
params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
columnId: PropTypes.string,
hasUnread: PropTypes.bool,
group: PropTypes.oneOfType([ImmutablePropTypes.map, PropTypes.bool]),
relationships: ImmutablePropTypes.map,
intl: PropTypes.object.isRequired,
}
state = {
collapsed: true,
}
componentDidMount() {
const { dispatch } = this.props
const { id } = this.props.params
dispatch(expandGroupTimeline(id))
this.disconnect = dispatch(connectGroupStream(id))
}
componentWillUnmount() {
if (this.disconnect) {
this.disconnect()
this.disconnect = null
}
}
handleOpenProUpgradeModal = () => {
this.props.dispatch(openModal('PRO_UPGRADE'));
handleLoadMore = maxId => {
const { id } = this.props.params
this.props.dispatch(expandGroupTimeline(id, { maxId }))
}
renderHeader() {
const { intl, activeTab, account, onOpenProUpgradeModal } = this.props;
handleToggleClick = (e) => {
e.stopPropagation()
this.setState({ collapsed: !this.state.collapsed })
}
const isPro = account.get('is_pro');
render() {
const { columnId, group, relationships, account, intl } = this.props
const { collapsed } = this.state
const { id } = this.props.params
if (typeof group === 'undefined' || !relationships) {
return <ColumnIndicator type='loading' />
} else if (group === false) {
return <ColumnIndicator type='missing' />
}
return (
<div className="group-column-header">
<div className="group-column-header__cta">
{
account && isPro &&
<Link to="/groups/create" className="button standard-small">{intl.formatMessage(messages.create)}</Link>
}
{
account && !isPro &&
<button onClick={this.handleOpenProUpgradeModal} className="button standard-small">{intl.formatMessage(messages.create)}</button>
}
</div>
<div className="group-column-header__title">{intl.formatMessage(messages.heading)}</div>
<div className="column-header__wrapper">
<h1 className="column-header">
<Link to='/groups' className={classNames('btn grouped', {'active': 'featured' === activeTab})}>
{intl.formatMessage(messages.tab_featured)}
</Link>
<Link to='/groups/browse/member' className={classNames('btn grouped', {'active': 'member' === activeTab})}>
{intl.formatMessage(messages.tab_member)}
</Link>
<Link to='/groups/browse/admin' className={classNames('btn grouped', {'active': 'admin' === activeTab})}>
{intl.formatMessage(messages.tab_admin)}
</Link>
</h1>
</div>
</div>
);
<StatusListContainer
alwaysPrepend
scrollKey={`group_timeline-${columnId}`}
timelineId={`group:${id}`}
onLoadMore={this.handleLoadMore}
group={group}
withGroupAdmin={relationships && relationships.get('admin')}
emptyMessage={intl.formatMessage(messages.empty)}
/>
)
}
render () {
const { groupIds, showCreateForm } = this.props;
return (
<div>
{!showCreateForm && this.renderHeader()}
{showCreateForm && <GroupCreate /> }
<div className="group-card-list">
{groupIds.map(id => <GroupCard key={id} id={id} />)}
</div>
</div>
);
}
}
}

View File

@@ -1 +1 @@
export { default } from './group_timeline';
export { default } from './group_timeline'

View File

@@ -6,27 +6,27 @@ import ColumnIndicator from '../../../components/column_indicator';
import classNames from 'classnames';
const messages = defineMessages({
title: { id: 'groups.form.title', defaultMessage: 'Title' },
description: { id: 'groups.form.description', defaultMessage: 'Description' },
coverImage: { id: 'groups.form.coverImage', defaultMessage: 'Upload new banner image (optional)' },
coverImageChange: { id: 'groups.form.coverImageChange', defaultMessage: 'Banner image selected' },
update: { id: 'groups.form.update', defaultMessage: 'Update group' },
title: { id: 'groups.form.title', defaultMessage: 'Title' },
description: { id: 'groups.form.description', defaultMessage: 'Description' },
coverImage: { id: 'groups.form.coverImage', defaultMessage: 'Upload new banner image (optional)' },
coverImageChange: { id: 'groups.form.coverImageChange', defaultMessage: 'Banner image selected' },
update: { id: 'groups.form.update', defaultMessage: 'Update group' },
});
const mapStateToProps = (state, props) => ({
group: state.getIn(['groups', props.params.id]),
title: state.getIn(['group_editor', 'title']),
description: state.getIn(['group_editor', 'description']),
coverImage: state.getIn(['group_editor', 'coverImage']),
disabled: state.getIn(['group_editor', 'isSubmitting']),
group: state.getIn(['groups', props.params.id]),
title: state.getIn(['group_editor', 'title']),
description: state.getIn(['group_editor', 'description']),
coverImage: state.getIn(['group_editor', 'coverImage']),
disabled: state.getIn(['group_editor', 'isSubmitting']),
});
const mapDispatchToProps = dispatch => ({
onTitleChange: value => dispatch(changeValue('title', value)),
onDescriptionChange: value => dispatch(changeValue('description', value)),
onCoverImageChange: value => dispatch(changeValue('coverImage', value)),
onSubmit: routerHistory => dispatch(submit(routerHistory)),
setUp: group => dispatch(setUp(group)),
onTitleChange: value => dispatch(changeValue('title', value)),
onDescriptionChange: value => dispatch(changeValue('description', value)),
onCoverImageChange: value => dispatch(changeValue('coverImage', value)),
onSubmit: routerHistory => dispatch(submit(routerHistory)),
setUp: group => dispatch(setUp(group)),
});
export default
@@ -35,103 +35,103 @@ export default
class Edit extends ImmutablePureComponent {
static contextTypes = {
router: PropTypes.object,
router: PropTypes.object,
}
static propTypes = {
group: ImmutablePropTypes.map,
title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
coverImage: PropTypes.object,
disabled: PropTypes.bool,
intl: PropTypes.object.isRequired,
onTitleChange: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
group: ImmutablePropTypes.map,
title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
coverImage: PropTypes.object,
disabled: PropTypes.bool,
intl: PropTypes.object.isRequired,
onTitleChange: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
};
componentWillMount(nextProps) {
if (this.props.group) {
this.props.setUp(this.props.group);
}
if (this.props.group) {
this.props.setUp(this.props.group);
}
}
componentWillReceiveProps(nextProps) {
if (!this.props.group && nextProps.group) {
this.props.setUp(nextProps.group);
}
if (!this.props.group && nextProps.group) {
this.props.setUp(nextProps.group);
}
}
handleTitleChange = e => {
this.props.onTitleChange(e.target.value);
this.props.onTitleChange(e.target.value);
}
handleDescriptionChange = e => {
this.props.onDescriptionChange(e.target.value);
this.props.onDescriptionChange(e.target.value);
}
handleCoverImageChange = e => {
this.props.onCoverImageChange(e.target.files[0]);
this.props.onCoverImageChange(e.target.files[0]);
}
handleSubmit = e => {
e.preventDefault();
this.props.onSubmit(this.context.router.history);
e.preventDefault();
this.props.onSubmit(this.context.router.history);
}
handleClick = () => {
this.props.onSubmit(this.context.router.history);
this.props.onSubmit(this.context.router.history);
}
render () {
const { group, title, description, coverImage, disabled, intl } = this.props;
render() {
const { group, title, description, coverImage, disabled, intl } = this.props;
if (typeof group === 'undefined') {
return ( <ColumnIndicator type='loading' /> );
} else if (group === false) {
return (<ColumnIndicator type='missing' />);
}
if (typeof group === 'undefined') {
return <ColumnIndicator type='loading' />
} else if (group === false) {
return <ColumnIndicator type='missing' />
}
return (
<form className='group-form' onSubmit={this.handleSubmit}>
<div>
<input
className='standard'
type='text'
value={title}
disabled={disabled}
onChange={this.handleTitleChange}
placeholder={intl.formatMessage(messages.title)}
/>
</div>
return (
<form className='group-form' onSubmit={this.handleSubmit}>
<div>
<input
className='standard'
type='text'
value={title}
disabled={disabled}
onChange={this.handleTitleChange}
placeholder={intl.formatMessage(messages.title)}
/>
</div>
<div>
<textarea
className='standard'
type='text'
value={description}
disabled={disabled}
onChange={this.handleDescriptionChange}
placeholder={intl.formatMessage(messages.description)}
/>
</div>
<div>
<textarea
className='standard'
type='text'
value={description}
disabled={disabled}
onChange={this.handleDescriptionChange}
placeholder={intl.formatMessage(messages.description)}
/>
</div>
<div>
<label htmlFor='group_cover_image' className={classNames('group-form__file-label', { 'group-form__file-label--selected': coverImage !== null })}>
{intl.formatMessage(coverImage === null ? messages.coverImage : messages.coverImageChange)}
</label>
<div>
<label htmlFor='group_cover_image' className={classNames('group-form__file-label', { 'group-form__file-label--selected': coverImage !== null })}>
{intl.formatMessage(coverImage === null ? messages.coverImage : messages.coverImageChange)}
</label>
<input
type='file'
className='group-form__file'
id='group_cover_image'
disabled={disabled}
onChange={this.handleCoverImageChange}
/>
<input
type='file'
className='group-form__file'
id='group_cover_image'
disabled={disabled}
onChange={this.handleCoverImageChange}
/>
<button>{intl.formatMessage(messages.update)}</button>
</div>
</form>
);
<button>{intl.formatMessage(messages.update)}</button>
</div>
</form>
);
}
}

View File

@@ -1,53 +0,0 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { defineMessages, injectIntl } from 'react-intl';
import { Link } from 'react-router-dom';
import { shortNumberFormat } from '../../../utils/numbers';
const messages = defineMessages({
members: { id: 'groups.card.members', defaultMessage: 'Members' },
view: { id: 'groups.card.view', defaultMessage: 'View' },
join: { id: 'groups.card.join', defaultMessage: 'Join' },
role_member: { id: 'groups.card.roles.member', defaultMessage: 'You\'re a member' },
role_admin: { id: 'groups.card.roles.admin', defaultMessage: 'You\'re an admin' },
});
const mapStateToProps = (state, { id }) => ({
group: state.getIn(['groups', id]),
relationships: state.getIn(['group_relationships', id]),
});
export default
@connect(mapStateToProps)
@injectIntl
class GroupCard extends ImmutablePureComponent {
static propTypes = {
group: ImmutablePropTypes.map,
relationships: ImmutablePropTypes.map,
}
getRole() {
const { intl, relationships } = this.props;
if (!relationships) return null;
if (relationships.get('admin')) return intl.formatMessage(messages.role_admin);
if (relationships.get('member')) return intl.formatMessage(messages.role_member);
}
render() {
const { intl, group } = this.props;
const coverImageUrl = group.get('cover_image_url');
const role = this.getRole();
return (
<Link to={`/groups/${group.get('id')}`} className="group-card">
<div className="group-card__header">{coverImageUrl && <img alt="" src={coverImageUrl} />}</div>
<div className="group-card__content">
<div className="group-card__title">{group.get('title')}</div>
<div className="group-card__meta"><strong>{shortNumberFormat(group.get('member_count'))}</strong> {intl.formatMessage(messages.members)}{role && <span> · {role}</span>}</div>
<div className="group-card__description">{group.get('description')}</div>
</div>
</Link>
);
}
}

View File

@@ -1,105 +0,0 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { Link } from 'react-router-dom';
import classNames from 'classnames';
import { fetchGroups } from '../../../actions/groups';
import { openModal } from '../../../actions/modal';
import { me } from '../../../initial_state';
import GroupCard from './card';
import GroupCreate from '../create';
const messages = defineMessages({
heading: { id: 'column.groups', defaultMessage: 'Groups' },
create: { id: 'groups.create', defaultMessage: 'Create group' },
tab_featured: { id: 'groups.tab_featured', defaultMessage: 'Featured' },
tab_member: { id: 'groups.tab_member', defaultMessage: 'Member' },
tab_admin: { id: 'groups.tab_admin', defaultMessage: 'Manage' },
});
const mapStateToProps = (state, { activeTab }) => ({
groupIds: state.getIn(['group_lists', activeTab]),
account: state.getIn(['accounts', me]),
});
export default
@connect(mapStateToProps)
@injectIntl
class Groups extends ImmutablePureComponent {
static propTypes = {
params: PropTypes.object.isRequired,
activeTab: PropTypes.string.isRequired,
showCreateForm: PropTypes.bool,
dispatch: PropTypes.func.isRequired,
groups: ImmutablePropTypes.map,
groupIds: ImmutablePropTypes.list,
intl: PropTypes.object.isRequired,
};
componentWillMount () {
this.props.dispatch(fetchGroups(this.props.activeTab));
}
componentDidUpdate(oldProps) {
if (this.props.activeTab && this.props.activeTab !== oldProps.activeTab) {
this.props.dispatch(fetchGroups(this.props.activeTab));
}
}
handleOpenProUpgradeModal = () => {
this.props.dispatch(openModal('PRO_UPGRADE'));
}
renderHeader() {
const { intl, activeTab, account, onOpenProUpgradeModal } = this.props;
const isPro = account.get('is_pro');
return (
<div className="group-column-header">
<div className="group-column-header__cta">
{
account && isPro &&
<Link to="/groups/create" className="button standard-small">{intl.formatMessage(messages.create)}</Link>
}
{
account && !isPro &&
<button onClick={this.handleOpenProUpgradeModal} className="button standard-small">{intl.formatMessage(messages.create)}</button>
}
</div>
<div className="group-column-header__title">{intl.formatMessage(messages.heading)}</div>
<div className="column-header__wrapper">
<h1 className="column-header">
<Link to='/groups' className={classNames('btn grouped', {'active': 'featured' === activeTab})}>
{intl.formatMessage(messages.tab_featured)}
</Link>
<Link to='/groups/browse/member' className={classNames('btn grouped', {'active': 'member' === activeTab})}>
{intl.formatMessage(messages.tab_member)}
</Link>
<Link to='/groups/browse/admin' className={classNames('btn grouped', {'active': 'admin' === activeTab})}>
{intl.formatMessage(messages.tab_admin)}
</Link>
</h1>
</div>
</div>
);
}
render () {
const { groupIds, showCreateForm } = this.props;
return (
<div>
{!showCreateForm && this.renderHeader()}
{showCreateForm && <GroupCreate /> }
<div className="group-card-list">
{groupIds.map(id => <GroupCard key={id} id={id} />)}
</div>
</div>
);
}
}

View File

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

View File

@@ -1,99 +0,0 @@
import ImmutablePureComponent from 'react-immutable-pure-component'
import ImmutablePropTypes from 'react-immutable-proptypes'
import { injectIntl, defineMessages } from 'react-intl'
import { Link } from 'react-router-dom'
import classNames from 'classnames'
import { connectGroupStream } from '../../../actions/streaming'
import { expandGroupTimeline } from '../../../actions/timelines'
import StatusListContainer from '../../../containers/status_list_container'
import ColumnSettingsContainer from './containers/column_settings_container'
import Icon from '../../../components/icon'
import ColumnIndicator from '../../../components/column_indicator'
const messages = defineMessages({
tabLatest: { id: 'group.timeline.tab_latest', defaultMessage: 'Latest' },
show: { id: 'group.timeline.show_settings', defaultMessage: 'Show settings' },
hide: { id: 'group.timeline.hide_settings', defaultMessage: 'Hide settings' },
empty: { id: 'empty_column.group', defaultMessage: 'There is nothing in this group yet. When members of this group post new statuses, they will appear here.' },
})
const mapStateToProps = (state, props) => ({
group: state.getIn(['groups', props.params.id]),
relationships: state.getIn(['group_relationships', props.params.id]),
hasUnread: state.getIn(['timelines', `group:${props.params.id}`, 'unread']) > 0,
})
export default
@connect(mapStateToProps)
@injectIntl
class GroupTimeline extends ImmutablePureComponent {
static contextTypes = {
router: PropTypes.object,
}
static propTypes = {
params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
columnId: PropTypes.string,
hasUnread: PropTypes.bool,
group: PropTypes.oneOfType([ImmutablePropTypes.map, PropTypes.bool]),
relationships: ImmutablePropTypes.map,
intl: PropTypes.object.isRequired,
}
state = {
collapsed: true,
}
componentDidMount() {
const { dispatch } = this.props
const { id } = this.props.params
dispatch(expandGroupTimeline(id))
this.disconnect = dispatch(connectGroupStream(id))
}
componentWillUnmount() {
if (this.disconnect) {
this.disconnect()
this.disconnect = null
}
}
handleLoadMore = maxId => {
const { id } = this.props.params
this.props.dispatch(expandGroupTimeline(id, { maxId }))
}
handleToggleClick = (e) => {
e.stopPropagation()
this.setState({ collapsed: !this.state.collapsed })
}
render() {
const { columnId, group, relationships, account, intl } = this.props
const { collapsed } = this.state
const { id } = this.props.params
if (typeof group === 'undefined' || !relationships) {
return (<ColumnIndicator type='loading' />)
} else if (group === false) {
return (<ColumnIndicator type='missing' />)
}
return (
<StatusListContainer
alwaysPrepend
scrollKey={`group_timeline-${columnId}`}
timelineId={`group:${id}`}
onLoadMore={this.handleLoadMore}
group={group}
withGroupAdmin={relationships && relationships.get('admin')}
emptyMessage={intl.formatMessage(messages.empty)}
/>
)
}
}

View File

@@ -1 +1 @@
export { default } from './groups_collection';
export { default } from './groups_collection'

View File

@@ -1 +1 @@
export { default } from './hashtag_timeline';
export { default } from './hashtag_timeline'

View File

@@ -1 +1 @@
export { default } from './column_settings';
export { default } from './column_settings'

View File

@@ -1 +1 @@
export { default } from './introduction';
export { default } from './introduction'

View File

@@ -1 +1 @@
export { default } from './list';
export { default } from './list'

View File

@@ -1 +1 @@
export { default } from './list_adder';
export { default } from './list_adder'

View File

@@ -1 +1 @@
export { default } from './edit_list_form';
export { default } from './edit_list_form'

View File

@@ -1 +1 @@
export { default } from './list_editor_search';
export { default } from './list_editor_search'

View File

@@ -1 +1 @@
export { default } from './list_editor';
export { default } from './list_editor'

View File

@@ -1 +1 @@
export { default } from './list_timeline';
export { default } from './list_timeline'

View File

@@ -1 +1 @@
export { default } from './new_list_form';
export { default } from './new_list_form'

View File

@@ -1 +1 @@
export { default } from './lists_directory';
export { default } from './lists_directory'

View File

@@ -1 +1 @@
export { default } from './mutes';
export { default } from './mutes'

View File

@@ -1 +1 @@
export { default } from './column_settings';
export { default } from './column_settings'

View File

@@ -1 +1 @@
export { default } from './notification';
export { default } from './notification'

View File

@@ -1 +1 @@
export { default } from './notification_filter_bar';
export { default } from './notification_filter_bar'

View File

@@ -1 +1 @@
export { default } from './notifications';
export { default } from './notifications'

View File

@@ -1 +1 @@
export { default } from './reblogs';
export { default } from './reblogs'

View File

@@ -1 +1 @@
export { default } from './header';
export { default } from './header'

View File

@@ -1 +1 @@
export { default } from './search';
export { default } from './search'

View File

@@ -1 +1 @@
export { default } from './compose';
export { default } from './compose'

View File

@@ -1 +1 @@
export { default } from './hashtag_timeline';
export { default } from './hashtag_timeline'

View File

@@ -1 +1 @@
export { default } from './public_timeline';
export { default } from './public_timeline'

View File

@@ -167,7 +167,7 @@ export default class Card extends ImmutablePureComponent {
{trim(card.get('description') || '', maxDescription)}
</p>
<span className={[_s.default, _s.marginTopAuto, _s.flexRow, _s.alignItemsCenter, _s.colorSecondary, _s.text, _s.displayFlex, _s.textOverflowEllipsis, _s.fontSize13PX].join(' ')}>
<Icon id='link' width='12px' height='12px' className={[_s.fillcolorSecondary, _s.marginRight5PX].join(' ')} fixedWidth />
<Icon id='link' width='10px' height='10px' className={[_s.fillcolorSecondary, _s.marginRight5PX].join(' ')} fixedWidth />
{provider}
</span>
</div>
@@ -177,7 +177,7 @@ export default class Card extends ImmutablePureComponent {
let thumbnail = interactive ?
<img src={cardImg} className={[_s.default, _s.objectFitCover, _s.positionAbsolute, _s.width100PC, _s.height100PC, _s.top0, _s.right0, _s.bottom0, _s.left0].join(' ')} />
:
<img src={cardImg} className={[_s.default, _s.objectFitCover, _s.width400PX, _s.height260PX].join(' ')} />
<img src={cardImg} className={[_s.default, _s.objectFitCover, _s.width330PX, _s.height220PX].join(' ')} />
if (interactive) {
if (embedded) {
@@ -231,7 +231,7 @@ export default class Card extends ImmutablePureComponent {
<div className={[_s.default, _s.width100PC, _s.paddingHorizontal10PX].join(' ')}>
<a
href={card.get('url')}
className={[_s.default, _s.cursorPointer, _s.flexRow, _s.overflowHidden, _s.noUnderline, _s.width100PC, _s.borderColorSecondary2, _s.border1PX, _s.radiusSmall].join(' ')}
className={[_s.default, _s.cursorPointer, _s.flexRow, _s.overflowHidden, _s.noUnderline, _s.width100PC, _s.backgroundSubtle_onHover, _s.borderColorSecondary2, _s.border1PX, _s.radiusSmall].join(' ')}
rel='noopener'
ref={this.setRef}
>

View File

@@ -1 +1 @@
export { default } from './card';
export { default } from './card'

View File

@@ -1 +1 @@
export { default } from './detailed_status';
export { default } from './detailed_status'

View File

@@ -1 +1 @@
export { default } from './detailed_status_action_bar';
export { default } from './detailed_status_action_bar'

View File

@@ -1 +1 @@
export { default } from './status';
export { default } from './status'

View File

@@ -1 +1 @@
export { default } from './ui';
export { default } from './ui'

View File

@@ -22,7 +22,7 @@ import UploadArea from '../../components/upload_area'
// import { WhoToFollowPanel } from '../../components/panel'
// import LinkFooter from '../../components/link_footer'
import ProfilePage from '../../pages/profile_page'
// import GroupPage from '../../pages/group_page'
import GroupPage from '../../pages/group_page'
import GroupsPage from '../../pages/groups_page'
import SearchPage from '../../pages/search_page'
import ErrorPage from '../../pages/error_page'
@@ -40,30 +40,29 @@ import {
AccountTimeline,
// AccountGallery,
HomeTimeline,
// Followers,
// Following,
Followers,
Following,
// Reblogs,
// Favourites,
// Favorites,
// DirectTimeline,
// HashtagTimeline,
Notifications,
// FollowRequests,
GenericNotFound,
// FavouritedStatuses,
FavoritedStatuses,
// Blocks,
// DomainBlocks,
// Mutes,
// PinnedStatuses,
Search,
// Explore,
GroupsCollection,
// GroupTimeline,
GroupTimeline,
ListTimeline,
ListsDirectory,
// GroupMembers,
// GroupRemovedAccounts,
// GroupCreate,
// GroupEdit,
GroupMembers,
GroupRemovedAccounts,
GroupCreate,
GroupEdit,
} from './util/async-components'
import { me, meUsername } from '../../initial_state'
@@ -90,7 +89,7 @@ const keyMap = {
forceNew: 'option+n',
focusColumn: ['1', '2', '3', '4', '5', '6', '7', '8', '9'],
reply: 'r',
favourite: 'f',
Favorite: 'f',
boost: 'b',
mention: 'm',
open: ['enter', 'o'],
@@ -101,7 +100,7 @@ const keyMap = {
goToHome: 'g h',
goToNotifications: 'g n',
goToStart: 'g s',
goToFavourites: 'g f',
goToFavorites: 'g f',
goToPinned: 'g p',
goToProfile: 'g u',
goToBlocked: 'g b',
@@ -154,15 +153,13 @@ class SwitchingArea extends PureComponent {
<WrappedRoute path='/groups/browse/member' exact page={GroupsPage} component={GroupsCollection} content={children} componentParams={{ activeTab: 'member' }} />
<WrappedRoute path='/groups/browse/admin' exact page={GroupsPage} component={GroupsCollection} content={children} componentParams={{ activeTab: 'admin' }} />
{ /*
<WrappedRoute path='/groups/create' page={GroupsPage} component={Groups} content={children} componentParams={{ showCreateForm: true, activeTab: 'featured' }} />
<WrappedRoute path='/groups/create' page={GroupsPage} component={GroupCreate} content={children} componentParams={{ showCreateForm: true, activeTab: 'featured' }} />
<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/edit' page={GroupPage} component={GroupEdit} content={children} />
<WrappedRoute path='/groups/:id' page={GroupPage} component={GroupTimeline} content={children} />
<WrappedRoute path='/tags/:id' publicRoute component={HashtagTimeline} content={children} />
*/ }
{ /* <WrappedRoute path='/tags/:id' publicRoute component={HashtagTimeline} content={children} /> */}
<WrappedRoute path='/lists' exact page={ListsPage} component={ListsDirectory} content={children} />
<WrappedRoute path='/list/:id' page={ListPage} component={ListTimeline} content={children} />
@@ -189,28 +186,25 @@ class SwitchingArea extends PureComponent {
<Redirect from='/@:username' to='/:username' exact />
<WrappedRoute path='/:username' publicRoute exact page={ProfilePage} component={AccountTimeline} content={children} />
{ /*
<Redirect from='/@:username/with_replies' to='/:username/with_replies' />
<WrappedRoute path='/:username/with_replies' component={AccountTimeline} page={ProfilePage} content={children} componentParams={{ withReplies: true }} />
<Redirect from='/@:username/comments' to='/:username/comments' />
<WrappedRoute path='/:username/comments' page={ProfilePage} component={AccountTimeline} content={children} componentParams={{ commentsOnly: true }} />
<Redirect from='/@:username/followers' to='/:username/followers' />
<WrappedRoute path='/:username/followers' component={Followers} page={ProfilePage} content={children} />
<WrappedRoute path='/:username/followers' page={ProfilePage} component={Followers} content={children} />
<Redirect from='/@:username/following' to='/:username/following' />
<WrappedRoute path='/:username/following' component={Following} page={ProfilePage} content={children} />
<WrappedRoute path='/:username/following' page={ProfilePage} component={Following} content={children} />
{ /*
<Redirect from='/@:username/media' to='/:username/media' />
<WrappedRoute path='/:username/media' component={AccountGallery} page={ProfilePage} content={children} />
<Redirect from='/@:username/tagged/:tag' to='/:username/tagged/:tag' exact />
<WrappedRoute path='/:username/tagged/:tag' exact component={AccountTimeline} page={ProfilePage} content={children} />
*/ }
<Redirect from='/@:username/favorites' to='/:username/favorites' />
<WrappedRoute path='/:username/favorites' component={FavouritedStatuses} page={ProfilePage} content={children} />
<Redirect from='/@:username/pins' to='/:username/pins' />
<WrappedRoute path='/:username/pins' component={PinnedStatuses} page={ProfilePage} content={children} />
<WrappedRoute path='/:username/favorites' page={ProfilePage} component={FavoritedStatuses} content={children} />
{ /*
<Redirect from='/@:username/posts/:statusId' to='/:username/posts/:statusId' exact />
<WrappedRoute path='/:username/posts/:statusId' publicRoute exact component={Status} content={children} />
*/ }
@@ -473,7 +467,7 @@ class UI extends PureComponent {
this.context.router.history.push('/getting-started')
}
handleHotkeyGoToFavourites = () => {
handleHotkeyGoToFavorites = () => {
this.context.router.history.push(`/${meUsername}/favorites`)
}
@@ -515,7 +509,7 @@ class UI extends PureComponent {
goToHome: this.handleHotkeyGoToHome,
goToNotifications: this.handleHotkeyGoToNotifications,
goToStart: this.handleHotkeyGoToStart,
goToFavourites: this.handleHotkeyGoToFavourites,
goToFavorites: this.handleHotkeyGoToFavorites,
goToPinned: this.handleHotkeyGoToPinned,
goToProfile: this.handleHotkeyGoToProfile,
goToBlocked: this.handleHotkeyGoToBlocked,

View File

@@ -27,19 +27,19 @@ export function ListTimeline() {
}
export function GroupTimeline() {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/timeline')
return import(/* webpackChunkName: "features/group_timeline" */'../../group_timeline')
}
export function GroupMembers() {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/members')
return import(/* webpackChunkName: "features/group_members" */'../../group_members')
}
export function GroupRemovedAccounts() {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/removed_accounts')
return import(/* webpackChunkName: "features/group_removed_accounts" */'../../group_removed_accounts')
}
export function GroupCreate() {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/create')
return import(/* webpackChunkName: "features/groups_create" */'../../group_create')
}
export function GroupEdit() {
@@ -87,7 +87,7 @@ export function GenericNotFound() {
}
export function FavoritedStatuses() {
return import(/* webpackChunkName: "features/favourited_statuses" */'../../favourited_statuses')
return import(/* webpackChunkName: "features/favorited_statuses" */'../../favorited_statuses')
}
export function Blocks() {

View File

@@ -1 +1 @@
export { default } from './video';
export { default } from './video'