This commit is contained in:
mgabdev
2020-03-04 17:26:01 -05:00
parent 143725b5bd
commit 567894f614
109 changed files with 976 additions and 1643 deletions

View File

@@ -0,0 +1,125 @@
import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component'
import { injectIntl, defineMessages } from 'react-intl'
import { expandAccountMediaTimeline } from '../actions/timelines'
import { getAccountGallery } from '../selectors'
import ColumnIndicator from '../components/column_indicator'
import MediaItem from '../components/media_item'
import LoadMore from '../components/load_more'
import Block from '../components/block'
const messages = defineMessages({
none: { id: 'account_gallery.none', defaultMessage: 'No media to show.' },
})
const mapStateToProps = (state, { account }) => {
const accountId = !!account ? account.get('id') : -1
return {
accountId,
attachments: getAccountGallery(state, accountId),
isLoading: state.getIn(['timelines', `account:${accountId}:media`, 'isLoading']),
hasMore: state.getIn(['timelines', `account:${accountId}:media`, 'hasMore']),
}
}
export default
@connect(mapStateToProps)
@injectIntl
class AccountGallery extends ImmutablePureComponent {
static propTypes = {
dispatch: PropTypes.func.isRequired,
account: ImmutablePropTypes.map,
accountId: PropTypes.string,
attachments: ImmutablePropTypes.list.isRequired,
isLoading: PropTypes.bool,
hasMore: PropTypes.bool,
intl: PropTypes.object.isRequired,
}
componentDidMount() {
const { accountId } = this.props
if (accountId) {
this.props.dispatch(expandAccountMediaTimeline(accountId))
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.accountId && nextProps.accountId !== this.props.accountId) {
this.props.dispatch(expandAccountMediaTimeline(nextProps.accountId))
}
}
handleScrollToBottom = () => {
if (this.props.hasMore) {
this.handleLoadMore(this.props.attachments.size > 0 ? this.props.attachments.last().getIn(['status', 'id']) : undefined)
}
}
handleScroll = e => {
const { scrollTop, scrollHeight, clientHeight } = e.target
const offset = scrollHeight - scrollTop - clientHeight
if (150 > offset && !this.props.isLoading) {
this.handleScrollToBottom()
}
}
handleLoadMore = maxId => {
if (this.props.accountId && this.props.accountId !== -1) {
this.props.dispatch(expandAccountMediaTimeline(this.props.accountId, { maxId }))
}
}
handleLoadOlder = e => {
e.preventDefault()
this.handleScrollToBottom()
}
render() {
const {
attachments,
isLoading,
hasMore,
intl,
account
} = this.props
if (!account) return null
return (
<Block>
<div
role='feed'
onScroll={this.handleScroll}
className={[_s.default, _s.flexRow, _s.flexWrap, _s.heightMin50VH, _s.paddingVertical5PX, _s.paddingHorizontal5PX].join(' ')}
>
{
attachments.map((attachment) => (
<MediaItem key={attachment.get('id')} attachment={attachment} />
))
}
{
isLoading && attachments.size === 0 &&
<ColumnIndicator type='loading' />
}
{ /*
attachments.size == 0 &&
<ColumnIndicator type='empty' message={intl.formatMessage(messages.none)} />
*/ }
{
hasMore && !(isLoading && attachments.size === 0) &&
<LoadMore visible={!isLoading} onClick={this.handleLoadOlder} />
}
</div>
</Block>
)
}
}

View File

@@ -1,205 +0,0 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
import {
fetchAccount,
fetchAccountByUsername,
} from '../../actions/accounts';
import { openModal } from '../../actions/modal';
import { expandAccountMediaTimeline } from '../../actions/timelines';
import { me } from '../../initial_state';
import { getAccountGallery } from '../../selectors';
import ColumnIndicator from '../../components/column_indicator';
import MediaItem from './components/media_item';
import LoadMore from '../../components/load_more';
const messages = defineMessages({
posts: { id: 'account.posts', defaultMessage: 'Gabs' },
postsWithReplies: { id: 'account.posts_with_replies', defaultMessage: 'Gabs and replies' },
media: { id: 'account.media', defaultMessage: 'Media' },
error: { id: 'empty_column.account_unavailable', defaultMessage: 'Profile unavailable' },
});
const mapStateToProps = (state, { mediaType, params: { username } }) => {
const accounts = state.getIn(['accounts']);
const accountFetchError = (state.getIn(['accounts', -1, 'username'], '').toLowerCase() == username.toLowerCase());
let accountId = -1;
let accountUsername = username;
if (accountFetchError) {
accountId = null;
} else {
let account = accounts.find(acct => username.toLowerCase() == acct.getIn(['acct'], '').toLowerCase());
accountId = account ? account.getIn(['id'], null) : -1;
accountUsername = account ? account.getIn(['acct'], '') : '';
}
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,
unavailable,
accountUsername,
isAccount: !!state.getIn(['accounts', accountId]),
attachments: getAccountGallery(state, accountId),
isLoading: state.getIn(['timelines', `account:${accountId}:media`, 'isLoading']),
hasMore: state.getIn(['timelines', `account:${accountId}:media`, 'hasMore']),
};
};
class LoadMoreMedia extends ImmutablePureComponent {
static propTypes = {
maxId: PropTypes.string,
onLoadMore: PropTypes.func.isRequired,
};
handleLoadMore = () => {
this.props.onLoadMore(this.props.maxId);
}
render() {
return (
<LoadMore
disabled={this.props.disabled}
onClick={this.handleLoadMore}
/>
)
}
}
export default
@connect(mapStateToProps)
@injectIntl
class AccountGallery extends ImmutablePureComponent {
static propTypes = {
params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
attachments: ImmutablePropTypes.list.isRequired,
isLoading: PropTypes.bool,
hasMore: PropTypes.bool,
isAccount: PropTypes.bool,
unavailable: PropTypes.bool,
intl: PropTypes.object.isRequired,
}
state = {
width: 323,
}
componentDidMount() {
const { params: { username }, accountId } = this.props;
if (accountId && accountId !== -1) {
this.props.dispatch(fetchAccount(accountId));
this.props.dispatch(expandAccountMediaTimeline(accountId));
} else {
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.params.accountId));
this.props.dispatch(expandAccountMediaTimeline(nextProps.accountId));
}
}
handleScrollToBottom = () => {
if (this.props.hasMore) {
this.handleLoadMore(this.props.attachments.size > 0 ? this.props.attachments.last().getIn(['status', 'id']) : undefined);
}
}
handleScroll = e => {
const { scrollTop, scrollHeight, clientHeight } = e.target;
const offset = scrollHeight - scrollTop - clientHeight;
if (150 > offset && !this.props.isLoading) {
this.handleScrollToBottom();
}
}
handleLoadMore = maxId => {
if (this.props.accountId && this.props.accountId !== -1) {
this.props.dispatch(expandAccountMediaTimeline(this.props.accountId, { maxId }));
}
};
handleLoadOlder = e => {
e.preventDefault();
this.handleScrollToBottom();
}
handleOpenMedia = attachment => {
if (attachment.get('type') === 'video') {
this.props.dispatch(openModal('VIDEO', { media: attachment, status: attachment.get('status') }));
} else {
const media = attachment.getIn(['status', 'media_attachments']);
const index = media.findIndex(x => x.get('id') === attachment.get('id'));
this.props.dispatch(openModal('MEDIA', { media, index, status: attachment.get('status') }));
}
}
handleRef = c => {
if (c) {
this.setState({ width: c.offsetWidth });
}
}
render() {
const { attachments, isLoading, hasMore, isAccount, accountId, unavailable, accountUsername, intl } = this.props;
const { width } = this.state;
if (!isAccount && accountId !== -1) {
return <ColumnIndicator type='missing' />
} else if (accountId === -1 || (!attachments && isLoading)) {
return <ColumnIndicator type='loading' />
} else if (unavailable) {
return <ColumnIndicator type='error' message={intl.formatMessage(messages.error)} />
}
let loadOlder = null
if (hasMore && !(isLoading && attachments.size === 0)) {
loadOlder = <LoadMore visible={!isLoading} onClick={this.handleLoadOlder} />
}
return (
<div className='scrollable-list scrollable-list--flex' onScroll={this.handleScroll}>
<div role='feed' className='account-gallery__container' ref={this.handleRef}>
{
attachments.map((attachment, index) => attachment === null ? (
<LoadMoreMedia key={'more:' + attachments.getIn(index + 1, 'id')} maxId={index > 0 ? attachments.getIn(index - 1, 'id') : null} onLoadMore={this.handleLoadMore} />
) : (
<MediaItem key={attachment.get('id')} attachment={attachment} displayWidth={width} onOpenMedia={this.handleOpenMedia} />
))
}
{
attachments.size == 0 &&
<div className='empty-column-indicator'>
<FormattedMessage id='account_gallery.none' defaultMessage='No media to show.' />
</div>
}
{loadOlder}
</div>
{
isLoading && attachments.size === 0 &&
<div className='slist__append'>
<ColumnIndicator type='loading' />
</div>
}
</div>
);
}
}

View File

@@ -1,5 +0,0 @@
.account-gallery__container {
display: flex;
flex-wrap: wrap;
padding: 4px 2px;
}

View File

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

View File

@@ -1,156 +0,0 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import classNames from 'classnames';
import { decode } from 'blurhash';
import Icon from '../../../../components/icon';
import { autoPlayGif, displayMedia } from '../../../../initial_state';
import { isIOS } from '../../../../utils/is_mobile';
export default class MediaItem extends ImmutablePureComponent {
static propTypes = {
attachment: ImmutablePropTypes.map.isRequired,
displayWidth: PropTypes.number.isRequired,
onOpenMedia: PropTypes.func.isRequired,
};
state = {
visible: displayMedia !== 'hide_all' && !this.props.attachment.getIn(['status', 'sensitive']) || displayMedia === 'show_all',
loaded: false,
};
componentDidMount () {
if (this.props.attachment.get('blurhash')) {
this._decode();
}
}
componentDidUpdate (prevProps) {
if (prevProps.attachment.get('blurhash') !== this.props.attachment.get('blurhash') && this.props.attachment.get('blurhash')) {
this._decode();
}
}
_decode () {
const hash = this.props.attachment.get('blurhash');
const pixels = decode(hash, 32, 32);
if (pixels) {
const ctx = this.canvas.getContext('2d');
const imageData = new ImageData(pixels, 32, 32);
ctx.putImageData(imageData, 0, 0);
}
}
setCanvasRef = c => {
this.canvas = c;
}
handleImageLoad = () => {
this.setState({ loaded: true });
}
handleMouseEnter = e => {
if (this.hoverToPlay()) {
e.target.play();
}
}
handleMouseLeave = e => {
if (this.hoverToPlay()) {
e.target.pause();
e.target.currentTime = 0;
}
}
hoverToPlay () {
return !autoPlayGif && ['gifv', 'video'].indexOf(this.props.attachment.get('type')) !== -1;
}
handleClick = e => {
if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
e.preventDefault();
if (this.state.visible) {
this.props.onOpenMedia(this.props.attachment);
} else {
this.setState({ visible: true });
}
}
}
render () {
const { attachment, displayWidth } = this.props;
const { visible, loaded } = this.state;
const width = `${Math.floor((displayWidth - 4) / 3) - 4}px`;
const height = width;
const status = attachment.get('status');
const title = status.get('spoiler_text') || attachment.get('description');
let thumbnail = '';
let icon;
if (attachment.get('type') === 'unknown') {
// Skip
} else if (attachment.get('type') === 'image') {
const focusX = attachment.getIn(['meta', 'focus', 'x']) || 0;
const focusY = attachment.getIn(['meta', 'focus', 'y']) || 0;
const x = ((focusX / 2) + .5) * 100;
const y = ((focusY / -2) + .5) * 100;
thumbnail = (
<img
src={attachment.get('preview_url')}
alt={attachment.get('description')}
title={attachment.get('description')}
style={{ objectPosition: `${x}% ${y}%` }}
onLoad={this.handleImageLoad}
/>
);
} else if (['gifv', 'video'].indexOf(attachment.get('type')) !== -1) {
const autoPlay = !isIOS() && autoPlayGif;
thumbnail = (
<div className={classNames('media-gallery__gifv', { autoplay: autoPlay })}>
<video
className='media-gallery__item-gifv-thumbnail'
aria-label={attachment.get('description')}
title={attachment.get('description')}
role='application'
src={attachment.get('url')}
onMouseEnter={this.handleMouseEnter}
onMouseLeave={this.handleMouseLeave}
autoPlay={autoPlay}
preload='auto'
loop
muted
playsInline
/>
<span className='media-gallery__gifv__label'>GIF</span>
</div>
);
}
if (!visible) {
icon = (
<span className='account-gallery__item__icons'>
<Icon id='eye-slash' />
</span>
);
}
return (
<div className='account-gallery__item' style={{ width, height }}>
<a href={status.get('url')} target='_blank' onClick={this.handleClick} title={title}>
<canvas width={32} height={32} ref={this.setCanvasRef} className={classNames('media-gallery__preview', { 'media-gallery__preview--hidden': visible && loaded })} />
{visible && thumbnail}
{!visible && icon}
</a>
</div>
);
}
}

View File

@@ -1,17 +0,0 @@
.account-gallery__item {
border: none;
box-sizing: border-box;
display: block;
position: relative;
border-radius: 4px;
overflow: hidden;
margin: 2px;
&__icons {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24px;
}
}

View File

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

View File

@@ -1,55 +1,30 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { List as ImmutableList } from 'immutable';
import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
import { fetchAccount, fetchAccountByUsername } from '../../actions/accounts';
import { expandAccountFeaturedTimeline, expandAccountTimeline } from '../../actions/timelines';
import { fetchAccountIdentityProofs } from '../../actions/identity_proofs';
import { me } from '../../initial_state';
import StatusList from '../../components/status_list/status_list';
import ColumnIndicator from '../../components/column_indicator';
import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component'
import { List as ImmutableList } from 'immutable'
import { injectIntl, defineMessages } from 'react-intl'
import { expandAccountFeaturedTimeline, expandAccountTimeline } from '../../actions/timelines'
import { fetchAccountIdentityProofs } from '../../actions/identity_proofs'
import StatusList from '../../components/status_list/status_list'
const messages = defineMessages({
posts: { id: 'account.posts', defaultMessage: 'Gabs' },
postsWithReplies: { id: 'account.posts_with_replies', defaultMessage: 'Gabs and replies' },
media: { id: 'account.media', defaultMessage: 'Media' },
error: { id: 'empty_column.account_unavailable', defaultMessage: 'Profile unavailable' },
});
empty: { id: 'empty_column.account_timeline', defaultMessage: 'No gabs here!' },
})
const emptyList = ImmutableList();
const emptyList = ImmutableList()
const mapStateToProps = (state, { params: { username }, withReplies = false }) => {
const accounts = state.getIn(['accounts']);
const accountFetchError = (state.getIn(['accounts', -1, 'username'], '').toLowerCase() == username.toLowerCase());
const mapStateToProps = (state, { account, withReplies = false }) => {
const accountId = !!account ? account.getIn(['id'], null) : -1
let accountId = -1;
let accountUsername = username;
if (accountFetchError) {
accountId = null;
} else {
let account = accounts.find(acct => username.toLowerCase() == acct.getIn(['acct'], '').toLowerCase());
accountId = account ? account.getIn(['id'], null) : -1;
accountUsername = account ? account.getIn(['acct'], '') : '';
}
const path = withReplies ? `${accountId}:with_replies` : accountId;
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 path = withReplies ? `${accountId}:with_replies` : accountId
return {
accountId,
unavailable,
accountUsername,
isAccount: !!state.getIn(['accounts', accountId]),
statusIds: state.getIn(['timelines', `account:${path}`, 'items'], emptyList),
featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], emptyList),
isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']),
hasMore: state.getIn(['timelines', `account:${path}`, 'hasMore']),
};
};
}
}
export default
@connect(mapStateToProps)
@@ -64,57 +39,56 @@ class AccountTimeline extends ImmutablePureComponent {
isLoading: PropTypes.bool,
hasMore: PropTypes.bool,
withReplies: PropTypes.bool,
isAccount: PropTypes.bool,
unavailable: PropTypes.bool,
intl: PropTypes.object.isRequired,
};
}
componentWillMount() {
const { params: { username }, accountId, withReplies } = this.props;
const { accountId, withReplies } = this.props
if (accountId && accountId !== -1) {
this.props.dispatch(fetchAccount(accountId));
this.props.dispatch(fetchAccountIdentityProofs(accountId));
this.props.dispatch(fetchAccountIdentityProofs(accountId))
if (!withReplies) {
this.props.dispatch(expandAccountFeaturedTimeline(accountId));
this.props.dispatch(expandAccountFeaturedTimeline(accountId))
}
this.props.dispatch(expandAccountTimeline(accountId, { withReplies }));
} else {
this.props.dispatch(fetchAccountByUsername(username));
this.props.dispatch(expandAccountTimeline(accountId, { withReplies }))
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.accountId && nextProps.accountId !== -1 && (nextProps.accountId !== this.props.accountId && nextProps.accountId) || nextProps.withReplies !== this.props.withReplies) {
this.props.dispatch(fetchAccount(nextProps.accountId));
this.props.dispatch(fetchAccountIdentityProofs(nextProps.accountId));
this.props.dispatch(fetchAccountIdentityProofs(nextProps.accountId))
if (!nextProps.withReplies) {
this.props.dispatch(expandAccountFeaturedTimeline(nextProps.accountId));
this.props.dispatch(expandAccountFeaturedTimeline(nextProps.accountId))
}
this.props.dispatch(expandAccountTimeline(nextProps.accountId, { withReplies: nextProps.withReplies }));
this.props.dispatch(expandAccountTimeline(nextProps.accountId, { withReplies: nextProps.withReplies }))
}
}
handleLoadMore = maxId => {
if (this.props.accountId && this.props.accountId !== -1) {
this.props.dispatch(expandAccountTimeline(this.props.accountId, { maxId, withReplies: this.props.withReplies }));
this.props.dispatch(expandAccountTimeline(this.props.accountId, {
maxId,
withReplies: this.props.withReplies
}))
}
}
render() {
const { statusIds, featuredStatusIds, isLoading, hasMore, isAccount, accountId, unavailable, accountUsername, intl } = this.props;
const {
account,
statusIds,
featuredStatusIds,
isLoading,
hasMore,
intl
} = this.props
if (!account) return null
if (!isAccount && accountId !== -1) {
return <ColumnIndicator type='missing' />
} else if (accountId === -1 || (!statusIds && isLoading)) {
return <ColumnIndicator type='loading' />
} else if (unavailable) {
return <ColumnIndicator type='error' message={intl.formatMessage(messages.error)} />
}
return (
<StatusList
scrollKey='account_timeline'
@@ -123,9 +97,9 @@ class AccountTimeline extends ImmutablePureComponent {
isLoading={isLoading}
hasMore={hasMore}
onLoadMore={this.handleLoadMore}
emptyMessage={<FormattedMessage id='empty_column.account_timeline' defaultMessage='No gabs here!' />}
emptyMessage={intl.formatMessage(messages.empty)}
/>
);
)
}
}

View File

@@ -12,7 +12,7 @@ export default class Header extends ImmutablePureComponent {
onBlock: PropTypes.func.isRequired,
onMention: PropTypes.func.isRequired,
onDirect: PropTypes.func.isRequired,
onReblogToggle: PropTypes.func.isRequired,
onRepostToggle: PropTypes.func.isRequired,
onReport: PropTypes.func.isRequired,
onMute: PropTypes.func.isRequired,
onBlockDomain: PropTypes.func.isRequired,
@@ -47,8 +47,8 @@ export default class Header extends ImmutablePureComponent {
this.props.onReport(this.props.account);
}
handleReblogToggle = () => {
this.props.onReblogToggle(this.props.account);
handleRepostToggle = () => {
this.props.onRepostToggle(this.props.account);
}
handleMute = () => {
@@ -94,7 +94,7 @@ export default class Header extends ImmutablePureComponent {
onBlock={this.handleBlock}
onMention={this.handleMention}
onDirect={this.handleDirect}
onReblogToggle={this.handleReblogToggle}
onRepostToggle={this.handleRepostToggle}
onReport={this.handleReport}
onMute={this.handleMute}
onBlockDomain={this.handleBlockDomain}

View File

@@ -114,9 +114,9 @@ class Header extends ImmutablePureComponent {
} else {
if (account.getIn(['relationship', 'following'])) {
if (account.getIn(['relationship', 'showing_reblogs'])) {
menu.push({ text: intl.formatMessage(messages.hideReblogs, { name: account.get('username') }), action: this.props.onReblogToggle });
menu.push({ text: intl.formatMessage(messages.hideReblogs, { name: account.get('username') }), action: this.props.onRepostToggle });
} else {
menu.push({ text: intl.formatMessage(messages.showReblogs, { name: account.get('username') }), action: this.props.onReblogToggle });
menu.push({ text: intl.formatMessage(messages.showReblogs, { name: account.get('username') }), action: this.props.onRepostToggle });
}
menu.push({ text: intl.formatMessage(messages.add_or_remove_from_list), action: this.props.onAddToList });
@@ -279,7 +279,7 @@ class Header extends ImmutablePureComponent {
<NavLink exact activeClassName='active' to={`/${account.get('acct')}/favorites`} title={intl.formatNumber(account.get('favourite_count'))}>
{ /* : TODO : shortNumberFormat(account.get('favourite_count')) */ }
<span></span>
<FormattedMessage id='navigation_bar.favourites' defaultMessage='Favorites' />
<FormattedMessage id='navigation_bar.favorites' defaultMessage='Favorites' />
</NavLink>
<NavLink exact activeClassName='active' to={`/${account.get('acct')}/pins`} title={intl.formatNumber(account.get('pinned_count'))}>
{ /* : TODO : shortNumberFormat(account.get('pinned_count')) */ }

View File

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

View File

@@ -1,135 +0,0 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { List as ImmutableList } from 'immutable';
import Icon from '../../../../components/icon';
import VerifiedIcon from '../../../../components/verified_icon';
import Badge from '../../../../components/badge';
const messages = defineMessages({
linkVerifiedOn: { id: 'account.link_verified_on', defaultMessage: 'Ownership of this link was checked on {date}' },
account_locked: { id: 'account.locked_info', defaultMessage: 'This account privacy status is set to locked. The owner manually reviews who can follow them.' },
bot: { id: 'account.badges.bot', defaultMessage: 'Bot' },
memberSince: { id: 'account.member_since', defaultMessage:'Member since {date}'},
});
const dateFormatOptions = {
month: 'short',
day: 'numeric',
year: 'numeric',
hour12: false,
hour: '2-digit',
minute: '2-digit',
};
const mapStateToProps = (state, { account }) => {
const identity_proofs = account ? state.getIn(['identity_proofs', account.get('id')], ImmutableList()) : ImmutableList();
return {
identity_proofs,
domain: state.getIn(['meta', 'domain']),
};
};
export default
@connect(mapStateToProps)
@injectIntl
class ProfileInfoPanel extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map,
identity_proofs: ImmutablePropTypes.list,
intl: PropTypes.object.isRequired,
username: PropTypes.string,
};
render () {
const { account, intl, identity_proofs, username } = this.props;
if (!account) {
return (
<div className='profile-info-panel'>
<div className='profile-info-panel__content'>
<div className='profile-info-panel-content__name'>
<h1>
<span/>
<small>@{username}</small>
</h1>
</div>
</div>
</div>
);
}
const lockedIcon = account.get('locked') ? (<Icon id='lock' title={intl.formatMessage(messages.account_locked)} />) : '';
const badge = account.get('bot') ? (<div className='account-role bot'>{intl.formatMessage(messages.bot)}</div>) : null;
const content = { __html: account.get('note_emojified') };
const fields = account.get('fields');
const acct = account.get('acct');
const displayNameHtml = { __html: account.get('display_name_html') };
const memberSinceDate = intl.formatDate(account.get('created_at'), { month: 'long', year: 'numeric' });
return (
<div className='profile-info-panel'>
<div className='profile-info-panel__content'>
<div className='profile-info-panel-content__name'>
<h1>
<span dangerouslySetInnerHTML={displayNameHtml} />
{account.get('is_verified') && <VerifiedIcon />}
{badge}
<small>@{acct} {lockedIcon}</small>
</h1>
</div>
<div className='profile-info-panel-content__badges'>
{account.get('is_pro') && <Badge type='pro' />}
{account.get('is_donor') && <Badge type='donor' />}
{account.get('is_investor') && <Badge type='investor' />}
<div className='profile-info-panel-content__badges__join-date'>
<Icon id="calendar"/>
{intl.formatMessage(messages.memberSince, {
date: memberSinceDate
})}
</div>
</div>
{
(account.get('note').length > 0 && account.get('note') !== '<p></p>') &&
<div className='profile-info-panel-content__bio' dangerouslySetInnerHTML={content} />
}
{(fields.size > 0 || identity_proofs.size > 0) && (
<div className='profile-info-panel-content__fields'>
{identity_proofs.map((proof, i) => (
<dl className='test' key={i}>
<dt dangerouslySetInnerHTML={{ __html: proof.get('provider') }} />
<dd className='verified'>
<a href={proof.get('proof_url')} target='_blank' rel='noopener'>
<span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(proof.get('updated_at'), dateFormatOptions) })}>
<Icon id='check' className='verified__mark' />
</span>
</a>
<a href={proof.get('profile_url')} target='_blank' rel='noopener'>
<span dangerouslySetInnerHTML={{ __html: ' ' + proof.get('provider_username') }} />
</a>
</dd>
</dl>
))}
{fields.map((pair, i) => (
<dl className='profile-info-panel-content__fields__item' key={i}>
<dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} />
<dd className={pair.get('verified_at') && 'verified'} title={pair.get('value_plain')}>
{pair.get('verified_at') && <span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(pair.get('verified_at'), dateFormatOptions) })}><Icon id='check' className='verified__mark' /></span>} <span dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} />
</dd>
</dl>
))}
</div>
)}
</div>
</div>
);
}
}

View File

@@ -1,133 +0,0 @@
.profile-info-panel {
display: flex;
position: relative;
&__content {
display: flex;
flex-direction: column;
flex: 1 1;
@media (min-width:895px) {
padding-top: 60px;
}
}
}
.profile-info-panel-content {
display: flex;
&__badges {
display: flex;
margin: 5px 0;
flex-direction: row;
flex-wrap: wrap;
&__join-date {
display: block;
margin-top: 5px;
.fa {
margin-right: 8px;
}
span {
color: $primary-text-color;
@include text-sizing(15px, 400, 1.25);
body.theme-gabsocial-light & {
color: $gab-default-text-light;
}
}
}
}
&__name {
display: block;
.account-role {
vertical-align: top;
}
.emojione {
@include size(22px);
}
h1 {
span:first-of-type {
color: #ffffff;
@include text-overflow(nowrap);
@include text-sizing(20px, 600, 1.25);
body.theme-gabsocial-light & {
color: $gab-default-text-light;
}
}
small {
display: block;
color: $secondary-text-color;
@include text-sizing(16px, 400, 1.5);
@include text-overflow;
}
}
}
&__bio {
display: block;
flex: 1 1;
color: $primary-text-color;
margin: 15px 0;
@include text-sizing(15px, 400, 1.25);
a {
color: lighten($ui-highlight-color, 8%);
}
}
&__fields {
display: flex;
flex-direction: column;
border-top: 1px solid lighten($ui-base-color, 12%);
padding: 10px 0;
margin: 5px 0;
@media screen and (max-width:895px) {
border-bottom: 1px solid lighten($ui-base-color, 12%);
}
a {
color: lighten($ui-highlight-color, 8%);
}
dl:first-child .verified {
border-radius: 0 4px 0 0;
}
.verified a {
color: $valid-value-color;
}
&__item {
display: flex;
padding: 2px 0;
margin: 2px 0;
flex: 1 1;
* {
@include text-sizing(15px, 400, 24px);
}
dt {
min-width: 26px;
}
dd {
padding-left: 4px;
}
}
}
}

View File

@@ -83,7 +83,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
dispatch(directCompose(account, router));
},
onReblogToggle (account) {
onRepostToggle (account) {
if (account.getIn(['relationship', 'showing_reblogs'])) {
dispatch(followAccount(account.get('id'), false));
} else {

View File

@@ -1,11 +1,11 @@
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { debounce } from 'lodash';
import ColumnIndicator from '../../components/column_indicator';
import AccountContainer from '../../containers/account_container';
import { fetchBlocks, expandBlocks } from '../../actions/blocks';
import ScrollableList from '../../components/scrollable_list';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'
import ImmutablePureComponent from 'react-immutable-pure-component'
import ImmutablePropTypes from 'react-immutable-proptypes'
import { debounce } from 'lodash'
import ColumnIndicator from '../components/column_indicator'
import AccountContainer from '../containers/account_container'
import { fetchBlocks, expandBlocks } from '../actions/blocks'
import ScrollableList from '../components/scrollable_list'
const messages = defineMessages({
heading: { id: 'column.blocks', defaultMessage: 'Blocked users' },

View File

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

View File

@@ -2,10 +2,10 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { debounce } from 'lodash';
import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks';
import DomainContainer from '../../containers/domain_container';
import ColumnIndicator from '../../components/column_indicator';
import ScrollableList from '../../components/scrollable_list';
import { fetchDomainBlocks, expandDomainBlocks } from '../actions/domain_blocks';
import DomainContainer from '../containers/domain_container';
import ColumnIndicator from '../components/column_indicator';
import ScrollableList from '../components/scrollable_list';
const messages = defineMessages({
heading: { id: 'column.domain_blocks', defaultMessage: 'Hidden domains' },

View File

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

View File

@@ -1,7 +1,7 @@
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { FormattedMessage } from 'react-intl';
import { fetchReblogs } from '../../actions/interactions';
import { fetchReposts } from '../../actions/interactions';
import { fetchStatus } from '../../actions/statuses';
import { makeGetStatus } from '../../selectors';
import AccountContainer from '../../containers/account_container';
@@ -33,13 +33,13 @@ class Favorites extends ImmutablePureComponent {
};
componentWillMount() {
this.props.dispatch(fetchReblogs(this.props.params.statusId));
this.props.dispatch(fetchReposts(this.props.params.statusId));
this.props.dispatch(fetchStatus(this.props.params.statusId));
}
componentWillReceiveProps(nextProps) {
if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {
this.props.dispatch(fetchReblogs(nextProps.params.statusId));
this.props.dispatch(fetchReposts(nextProps.params.statusId));
this.props.dispatch(fetchStatus(nextProps.params.statusId));
}
}

View File

@@ -0,0 +1,100 @@
import ImmutablePureComponent from 'react-immutable-pure-component'
import ImmutablePropTypes from 'react-immutable-proptypes'
import { debounce } from 'lodash'
import { defineMessages, injectIntl } from 'react-intl'
import {
fetchFollowers,
expandFollowers,
} from '../actions/accounts'
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, { account }) => {
const accountId = !!account ? account.get('id') : -1
return {
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.' },
})
export default
@connect(mapStateToProps)
@injectIntl
class Followers extends ImmutablePureComponent {
static propTypes = {
account: ImmutablePropTypes.map,
accountId: PropTypes.string,
intl: PropTypes.object.isRequired,
params: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
accountIds: ImmutablePropTypes.list,
hasMore: PropTypes.bool,
}
componentWillMount() {
const { accountId } = this.props
if (accountId && accountId !== -1) {
this.props.dispatch(fetchFollowers(accountId))
}
}
componentWillReceiveProps(nextProps) {
if (!!nextProps.accountId && nextProps.accountId !== -1 && nextProps.accountId !== this.props.accountId) {
this.props.dispatch(fetchFollowers(nextProps.accountId))
}
}
handleLoadMore = debounce(() => {
const { accountId } = this.props
if (!!accountId && accountId !== -1) {
this.props.dispatch(expandFollowers(accountId))
}
}, 300, { leading: true })
render() {
const {
account,
accountIds,
hasMore,
intl
} = this.props
if (!account) return null
return (
<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 && accountIds.map((id) => (
<AccountContainer key={`follower-${id}`} id={id} withNote={false} compact />
))
}
</ScrollableList>
</div>
</Block>
)
}
}

View File

@@ -1,132 +0,0 @@
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'
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())
let accountId = -1
if (accountFetchError) {
accountId = null
} else {
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))
return {
accountId,
unavailable,
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
if (accountId && accountId !== -1) {
this.props.dispatch(fetchAccount(accountId))
this.props.dispatch(fetchFollowers(accountId))
} else {
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))
}
}
handleLoadMore = debounce(() => {
if (this.props.accountId && this.props.accountId !== -1) {
this.props.dispatch(expandFollowers(this.props.accountId))
}
}, 300, { leading: true })
render() {
const {
accountIds,
hasMore,
isAccount,
accountId,
unavailable,
intl
} = this.props
if (!isAccount && accountId !== -1) {
return <ColumnIndicator type='missing' />
} else if (accountId === -1 || (!accountIds)) {
return <ColumnIndicator type='loading' />
} else if (unavailable) {
return <ColumnIndicator type='error' message={intl.formatMessage(messages.unavailable)} />
}
return (
<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 +0,0 @@
export { default } from './followers'

View File

@@ -0,0 +1,100 @@
import ImmutablePureComponent from 'react-immutable-pure-component'
import ImmutablePropTypes from 'react-immutable-proptypes'
import { debounce } from 'lodash'
import { defineMessages, injectIntl } from 'react-intl'
import {
fetchFollowing,
expandFollowing,
} from '../actions/accounts'
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, { account }) => {
const accountId = !!account ? account.get('id') : -1
return {
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.' },
})
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,
account: ImmutablePropTypes.map,
accountId: PropTypes.string,
hasMore: PropTypes.bool,
}
componentWillMount() {
const { accountId } = this.props
if (!!accountId && accountId !== -1) {
this.props.dispatch(fetchFollowing(accountId))
}
}
componentWillReceiveProps(nextProps) {
if (!!nextProps.accountId && nextProps.accountId !== -1 && nextProps.accountId !== this.props.accountId) {
this.props.dispatch(fetchFollowing(nextProps.accountId))
}
}
handleLoadMore = debounce(() => {
const { accountId } = this.props
if (!!accountId && accountId !== -1) {
this.props.dispatch(expandFollowing(accountId))
}
}, 300, { leading: true })
render() {
const {
account,
accountIds,
hasMore,
intl
} = this.props
if (!account) return null
return (
<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 && accountIds.map((id) => (
<AccountContainer key={`following-${id}`} id={id} withNote={false} compact />
))
}
</ScrollableList>
</div>
</Block>
)
}
}

View File

@@ -1,134 +0,0 @@
import { Fragment } from 'react'
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'
import Block from '../../components/block'
import Divider from '../../components/divider'
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())
let accountId = -1
if (accountFetchError) {
accountId = null
} else {
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))
return {
accountId,
unavailable,
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
if (accountId && accountId !== -1) {
this.props.dispatch(fetchAccount(accountId))
this.props.dispatch(fetchFollowing(accountId))
} else {
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(fetchFollowing(nextProps.accountId))
}
}
handleLoadMore = debounce(() => {
if (this.props.accountId && this.props.accountId !== -1) {
this.props.dispatch(expandFollowing(this.props.accountId))
}
}, 300, { leading: true })
render() {
const {
accountIds,
hasMore,
isAccount,
accountId,
unavailable,
intl
} = this.props
if (!isAccount && accountId !== -1) {
return <ColumnIndicator type='missing' />
} else if (accountId === -1 || (!accountIds)) {
return <ColumnIndicator type='loading' />
} else if (unavailable) {
return <ColumnIndicator type='error' message={intl.formatMessage(messages.unavailable)} />
}
return (
<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) => (
<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,4 +1,4 @@
import ColumnIndicator from '../../components/column_indicator';
import ColumnIndicator from '../components/column_indicator';
export default class GenericNotFound extends PureComponent {

View File

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

View File

@@ -3,11 +3,11 @@ 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 { 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'
import ColumnIndicator from '../components/column_indicator'
const messages = defineMessages({
tabLatest: { id: 'group.timeline.tab_latest', defaultMessage: 'Latest' },

View File

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

View File

@@ -1,8 +1,8 @@
import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component'
import { fetchGroups } from '../../actions/groups'
import Block from '../../components/block'
import GroupCollectionItem from '../../components/group_collection_item'
import { fetchGroups } from '../actions/groups'
import Block from '../components/block'
import GroupCollectionItem from '../components/group_collection_item'
const mapStateToProps = (state, { activeTab }) => ({
groupIds: state.getIn(['group_lists', activeTab]),

View File

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

View File

@@ -1,8 +1,8 @@
import { FormattedMessage } from 'react-intl'
import { isEqual } from 'lodash'
import { expandHashtagTimeline, clearTimeline } from '../../actions/timelines'
import { connectHashtagStream } from '../../actions/streaming'
import StatusListContainer from '../../containers/status_list_container'
import { expandHashtagTimeline, clearTimeline } from '../actions/timelines'
import { connectHashtagStream } from '../actions/streaming'
import StatusListContainer from '../containers/status_list_container'
const mapStateToProps = (state, props) => ({
hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}`, 'unread']) > 0,

View File

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

View File

@@ -115,10 +115,10 @@ class FrameInteractions extends Component {
<div>
<h3>
<FormattedMessage id='introduction.interactions.favourite.headline' defaultMessage='Favorite' />
<FormattedMessage id='introduction.interactions.favorite.headline' defaultMessage='Favorite' />
</h3>
<p>
<FormattedMessage id='introduction.interactions.favourite.text' defaultMessage='You can save a gab for later, and let the author know that you liked it, by favouriting it.' />
<FormattedMessage id='introduction.interactions.favorite.text' defaultMessage='You can save a gab for later, and let the author know that you liked it, by favoriting it.' />
</p>
</div>
</div>

View File

@@ -1,13 +1,13 @@
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
import { connectListStream } from '../../actions/streaming';
import { expandListTimeline } from '../../actions/timelines';
import { fetchList, deleteList } from '../../actions/lists';
import { openModal } from '../../actions/modal';
import StatusListContainer from '../../containers/status_list_container';
import ColumnIndicator from '../../components/column_indicator';
import Button from '../../components/button';
import { connectListStream } from '../actions/streaming';
import { expandListTimeline } from '../actions/timelines';
import { fetchList, deleteList } from '../actions/lists';
import { openModal } from '../actions/modal';
import StatusListContainer from '../containers/status_list_container';
import ColumnIndicator from '../components/column_indicator';
import Button from '../components/button';
const messages = defineMessages({
deleteMessage: { id: 'confirmations.delete_list.message', defaultMessage: 'Are you sure you want to permanently delete this list?' },

View File

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

View File

@@ -2,10 +2,10 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { debounce } from 'lodash';
import { fetchMutes, expandMutes } from '../../actions/mutes';
import AccountContainer from '../../containers/account_container';
import ColumnIndicator from '../../components/column_indicator';
import ScrollableList from '../../components/scrollable_list';
import { fetchMutes, expandMutes } from '../actions/mutes';
import AccountContainer from '../containers/account_container';
import ColumnIndicator from '../components/column_indicator';
import ScrollableList from '../components/scrollable_list';
const messages = defineMessages({
heading: { id: 'column.mutes', defaultMessage: 'Muted users' },

View File

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

View File

@@ -51,12 +51,12 @@ export default class ColumnSettings extends ImmutablePureComponent {
<SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'follow']} onChange={onChange} label={soundStr} />
</div>
<div role='group' aria-labelledby='notifications-favourite'>
<FormattedMessage id='notifications.column_settings.favourite' defaultMessage='Favorites:' />
<SettingToggle prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'favourite']} onChange={onChange} label={alertStr} />
{showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'favourite']} onChange={this.onPushChange} label={pushStr} />}
<SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'favourite']} onChange={onChange} label={showStr} />
<SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'favourite']} onChange={onChange} label={soundStr} />
<div role='group' aria-labelledby='notifications-favorite'>
<FormattedMessage id='notifications.column_settings.favorite' defaultMessage='Favorites:' />
<SettingToggle prefix='notifications_desktop' settings={settings} settingPath={['alerts', 'favorite']} onChange={onChange} label={alertStr} />
{showPushSettings && <SettingToggle prefix='notifications_push' settings={pushSettings} settingPath={['alerts', 'favorite']} onChange={this.onPushChange} label={pushStr} />}
<SettingToggle prefix='notifications' settings={settings} settingPath={['shows', 'favorite']} onChange={onChange} label={showStr} />
<SettingToggle prefix='notifications' settings={settings} settingPath={['sounds', 'favorite']} onChange={onChange} label={soundStr} />
</div>
<div role='group' aria-labelledby='notifications-mention'>

View File

@@ -29,8 +29,8 @@ class Notification extends ImmutablePureComponent {
onMoveUp: PropTypes.func.isRequired,
onMoveDown: PropTypes.func.isRequired,
onMention: PropTypes.func.isRequired,
onFavourite: PropTypes.func.isRequired,
onReblog: PropTypes.func.isRequired,
onFavorite: PropTypes.func.isRequired,
onRepost: PropTypes.func.isRequired,
onToggleHidden: PropTypes.func.isRequired,
status: ImmutablePropTypes.map,
intl: PropTypes.object.isRequired,
@@ -72,14 +72,14 @@ class Notification extends ImmutablePureComponent {
onMention(notification.get('account'), this.context.router.history);
}
handleHotkeyFavourite = () => {
handleHotkeyFavorite = () => {
const { status } = this.props;
if (status) this.props.onFavourite(status);
if (status) this.props.onFavorite(status);
}
handleHotkeyBoost = e => {
const { status } = this.props;
if (status) this.props.onReblog(status, e);
if (status) this.props.onRepost(status, e);
}
handleHotkeyToggleHidden = () => {
@@ -90,7 +90,7 @@ class Notification extends ImmutablePureComponent {
getHandlers() {
return {
reply: this.handleMention,
favourite: this.handleHotkeyFavourite,
favorite: this.handleHotkeyFavorite,
boost: this.handleHotkeyBoost,
mention: this.handleMention,
open: this.handleOpen,
@@ -108,7 +108,7 @@ class Notification extends ImmutablePureComponent {
<HotKeys handlers={this.getHandlers()}>
<div className='notification notification--follow focusable' tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.follow', defaultMessage: '{name} followed you' }, { name: account.get('acct') }), notification.get('created_at'))}>
<div className='notification__message'>
<div className='notification__favourite-icon-wrapper'>
<div className='notification__favorite-icon-wrapper'>
<Icon id='user-plus' fixedWidth />
</div>
@@ -140,19 +140,19 @@ class Notification extends ImmutablePureComponent {
);
}
renderFavourite(notification, link) {
renderFavorite(notification, link) {
const { intl } = this.props;
return (
<HotKeys handlers={this.getHandlers()}>
<div className='notification notification--favourite focusable' tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.favourite', defaultMessage: '{name} favorited your status' }, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
<div className='notification notification--favorite focusable' tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.favorite', defaultMessage: '{name} favorited your status' }, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
<div className='notification__message'>
<div className='notification__favourite-icon-wrapper'>
<div className='notification__favorite-icon-wrapper'>
<Icon id='star' className='star-icon' fixedWidth />
</div>
<span title={notification.get('created_at')}>
<FormattedMessage id='notification.favourite' defaultMessage='{name} favorited your status' values={{ name: link }} />
<FormattedMessage id='notification.favorite' defaultMessage='{name} favorited your status' values={{ name: link }} />
</span>
</div>
@@ -173,14 +173,14 @@ class Notification extends ImmutablePureComponent {
);
}
renderReblog(notification, link) {
renderRepost(notification, link) {
const { intl } = this.props;
return (
<HotKeys handlers={this.getHandlers()}>
<div className='notification notification--reblog focusable' tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.reblog', defaultMessage: '{name} reposted your status' }, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
<div className='notification__message'>
<div className='notification__favourite-icon-wrapper'>
<div className='notification__favorite-icon-wrapper'>
<Icon id='retweet' fixedWidth />
</div>
@@ -212,7 +212,7 @@ class Notification extends ImmutablePureComponent {
<HotKeys handlers={this.getHandlers()}>
<div className='notification notification--poll focusable' tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.poll', defaultMessage: 'A poll you have voted in has ended' }), notification.get('created_at'))}>
<div className='notification__message'>
<div className='notification__favourite-icon-wrapper'>
<div className='notification__favorite-icon-wrapper'>
<Icon id='tasks' fixedWidth />
</div>
@@ -261,9 +261,9 @@ class Notification extends ImmutablePureComponent {
// case 'mention':
// return this.renderMention(notification);
case 'favourite':
return this.renderFavourite(notification, link);
return this.renderFavorite(notification, link);
// case 'reblog':
// return this.renderReblog(notification, link);
// return this.renderRepost(notification, link);
// case 'poll':
// return this.renderPoll(notification);
}

View File

@@ -1,59 +0,0 @@
.notification {
&--favourite {
.status.status-direct {
background: transparent;
.icon-button.disabled {
color: lighten($action-button-color, 13%);
}
}
}
&--follow {}
&--reblog {}
&--poll {}
&__message {
margin: 0 10px 0 68px;
padding: 8px 0 0;
cursor: default;
color: $gab-secondary-text;
position: relative;
@include text-sizing(15px, 400, 22px);
.fa {
color: $highlight-text-color;
}
>span {
display: inline;
@include text-overflow(nowrap);
}
}
&__display-name {
color: inherit;
font-weight: 500;
text-decoration: none;
&:hover {
color: $primary-text-color;
text-decoration: underline;
}
}
&__favourite-icon-wrapper {
left: -26px;
position: absolute;
.star-icon {
color: $gold-star;
}
}
}

View File

@@ -2,7 +2,7 @@ import { defineMessages, injectIntl } from 'react-intl';
const messages = defineMessages({
mentions: { id: 'notifications.filter.mentions', defaultMessage: 'Mentions' },
favourites: { id: 'notifications.filter.favourites', defaultMessage: 'Favorites' },
favorites: { id: 'notifications.filter.favorites', defaultMessage: 'Favorites' },
boosts: { id: 'notifications.filter.boosts', defaultMessage: 'Reposts' },
polls: { id: 'notifications.filter.polls', defaultMessage: 'Poll results' },
follows: { id: 'notifications.filter.follows', defaultMessage: 'Follows' },
@@ -65,9 +65,9 @@ class NotificationFilterBar extends PureComponent {
icon: 'at',
},
{
className: selectedFilter === 'favourite' ? 'active' : '',
onClick: this.onClick('favourite'),
title: intl.formatMessage(messages.favourites),
className: selectedFilter === 'favorite' ? 'active' : '',
onClick: this.onClick('favorite'),
title: intl.formatMessage(messages.favorites),
icon: 'star',
},
{

View File

@@ -2,9 +2,9 @@ import { openModal } from '../../../actions/modal'
import { mentionCompose } from '../../../actions/compose'
import {
reblog,
favourite,
favorite,
unreblog,
unfavourite,
unfavorite,
} from '../../../actions/interactions'
import {
hideStatus,
@@ -38,27 +38,27 @@ const mapDispatchToProps = dispatch => ({
dispatch(mentionCompose(account, router))
},
onModalReblog (status) {
dispatch(reblog(status))
onModalRepost (status) {
dispatch(repost(status))
},
onReblog (status, e) {
onRepost (status, e) {
if (status.get('reblogged')) {
dispatch(unreblog(status))
dispatch(unrepost(status))
} else {
if (e.shiftKey || !boostModal) {
this.onModalReblog(status)
this.onModalRepost(status)
} else {
dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }))
dispatch(openModal('BOOST', { status, onRepost: this.onModalRepost }))
}
}
},
onFavourite (status) {
if (status.get('favourited')) {
dispatch(unfavourite(status))
onFavorite (status) {
if (status.get('favorited')) {
dispatch(unfavorite(status))
} else {
dispatch(favourite(status))
dispatch(favorite(status))
}
},

View File

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

View File

@@ -1,12 +1,12 @@
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { FormattedMessage } from 'react-intl';
import { fetchReblogs } from '../../actions/interactions';
import { fetchStatus } from '../../actions/statuses';
import { makeGetStatus } from '../../selectors';
import AccountContainer from '../../containers/account_container';
import ColumnIndicator from '../../components/column_indicator';
import ScrollableList from '../../components/scrollable_list';
import { fetchReposts } from '../actions/interactions';
import { fetchStatus } from '../actions/statuses';
import { makeGetStatus } from '../selectors';
import AccountContainer from '../containers/account_container';
import ColumnIndicator from '../components/column_indicator';
import ScrollableList from '../components/scrollable_list';
const mapStateToProps = (state, props) => {
const getStatus = makeGetStatus();
@@ -23,7 +23,7 @@ const mapStateToProps = (state, props) => {
export default
@connect(mapStateToProps)
class Reblogs extends ImmutablePureComponent {
class Reposts extends ImmutablePureComponent {
static propTypes = {
params: PropTypes.object.isRequired,
@@ -33,13 +33,13 @@ class Reblogs extends ImmutablePureComponent {
};
componentWillMount () {
this.props.dispatch(fetchReblogs(this.props.params.statusId));
this.props.dispatch(fetchReposts(this.props.params.statusId));
this.props.dispatch(fetchStatus(this.props.params.statusId));
}
componentWillReceiveProps(nextProps) {
if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {
this.props.dispatch(fetchReblogs(nextProps.params.statusId));
this.props.dispatch(fetchReposts(nextProps.params.statusId));
this.props.dispatch(fetchStatus(nextProps.params.statusId));
}
}
@@ -48,19 +48,21 @@ class Reblogs extends ImmutablePureComponent {
const { accountIds, status } = this.props;
if (!accountIds) {
return (<ColumnIndicator type='loading' />);
return <ColumnIndicator type='loading' />
} else if (!status) {
return (<ColumnIndicator type='missing' />);
return <ColumnIndicator type='missing' />
}
return (
<ScrollableList
scrollKey='reblogs'
scrollKey='reposts'
emptyMessage={<FormattedMessage id='status.reblogs.empty' defaultMessage='No one has reposted this gab yet. When someone does, they will show up here.' />}
>
{accountIds.map(id =>
<AccountContainer key={id} id={id} withNote={false} />
)}
{
accountIds.map(id =>
<AccountContainer key={id} id={id} withNote={false} />
)
}
</ScrollableList>
);
}

View File

@@ -1,5 +1,5 @@
// import SearchContainer from '../compose/containers/search_container';
import SearchResultsContainer from '../compose/containers/search_results_container';
import SearchResultsContainer from './compose/containers/search_results_container';
export default class Search extends PureComponent {

View File

@@ -1,57 +0,0 @@
import { FormattedMessage } from 'react-intl';
const mapStateToProps = state => ({
value: state.getIn(['search', 'value']),
submitted: state.getIn(['search', 'submitted']),
});
export default
@connect(mapStateToProps)
class Header extends PureComponent {
static propTypes = {
value: PropTypes.string,
submitted: PropTypes.bool,
};
state = {
submittedValue: '',
};
componentWillReceiveProps (nextProps) {
if (nextProps.submitted) {
const submittedValue = nextProps.value;
this.setState({submittedValue})
}
}
render () {
const { submittedValue } = this.state;
if (!submittedValue) {
return null;
}
return (
<div className='search-header'>
<div className='search-header__text-container'>
<h1 className='search-header__title-text'>
{submittedValue}
</h1>
</div>
<div className='search-header__type-filters'>
<div className='search-header__type-filters-tabs'>
{ /* <SectionHeadlineBar
items={[
{
to: '/search',
title: <FormattedMessage id='search_results.top' defaultMessage='Top' />
}
]}
/> */ }
</div>
</div>
</div>
);
}
}

View File

@@ -1,44 +0,0 @@
.search-header {
display: block;
width: 100%;
&__text-container {
display: none;
padding: 25px 0;
background-color: lighten($ui-base-color, 6%);
@media (min-width:895px) {
display: block;
}
}
&__title-text {
color: $primary-text-color;
padding-left: 20px;
max-width: 1200px;
@include text-sizing(27px, bold, 32px);
@include text-overflow(nowrap);
@include margin-center;
@media (min-width:895px) and (max-width:1190px) {
max-width: 900px;
}
}
&__type-filters-tabs {
display: flex;
width: 100%;
max-width: 1200px;
@include margin-center;
@media screen and (max-width:895px) {
max-width: 580px;
}
@media (min-width:895px) and (max-width:1190px) {
max-width: 900px;
}
}
}

View File

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

View File

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

View File

@@ -6,9 +6,9 @@ import {
} from '../../../actions/compose';
import {
reblog,
favourite,
favorite,
unreblog,
unfavourite,
unfavorite,
pin,
unpin,
} from '../../../actions/interactions';
@@ -65,27 +65,27 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
});
},
onModalReblog (status) {
dispatch(reblog(status));
onModalRepost (status) {
dispatch(repost(status));
},
onReblog (status, e) {
onRepost (status, e) {
if (status.get('reblogged')) {
dispatch(unreblog(status));
dispatch(unrepost(status));
} else {
if (e.shiftKey || !boostModal) {
this.onModalReblog(status);
this.onModalRepost(status);
} else {
dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));
dispatch(openModal('BOOST', { status, onRepost: this.onModalRepost }));
}
}
},
onFavourite (status) {
if (status.get('favourited')) {
dispatch(unfavourite(status));
onFavorite (status) {
if (status.get('favorited')) {
dispatch(unfavorite(status));
} else {
dispatch(favourite(status));
dispatch(favorite(status));
}
},

View File

@@ -6,8 +6,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { HotKeys } from 'react-hotkeys';
import { fetchStatus } from '../../actions/statuses';
import {
favourite,
unfavourite,
favorite,
unfavorite,
reblog,
unreblog,
pin,
@@ -155,11 +155,11 @@ class Status extends ImmutablePureComponent {
this.setState({ showMedia: !this.state.showMedia });
}
handleFavouriteClick = (status) => {
handleFavoriteClick = (status) => {
if (status.get('favourited')) {
this.props.dispatch(unfavourite(status));
this.props.dispatch(unfavorite(status));
} else {
this.props.dispatch(favourite(status));
this.props.dispatch(favorite(status));
}
}
@@ -184,18 +184,18 @@ class Status extends ImmutablePureComponent {
}
}
handleModalReblog = (status) => {
this.props.dispatch(reblog(status));
handleModalRepost = (status) => {
this.props.dispatch(repost(status));
}
handleReblogClick = (status, e) => {
handleRepostClick = (status, e) => {
if (status.get('reblogged')) {
this.props.dispatch(unreblog(status));
this.props.dispatch(unrepost(status));
} else {
if ((e && e.shiftKey) || !boostModal) {
this.handleModalReblog(status);
this.handleModalRepost(status);
} else {
this.props.dispatch(openModal('BOOST', { status, onReblog: this.handleModalReblog }));
this.props.dispatch(openModal('BOOST', { status, onRepost: this.handleModalRepost }));
}
}
}
@@ -298,12 +298,12 @@ class Status extends ImmutablePureComponent {
this.handleReplyClick(this.props.status);
}
handleHotkeyFavourite = () => {
this.handleFavouriteClick(this.props.status);
handleHotkeyFavorite = () => {
this.handleFavoriteClick(this.props.status);
}
handleHotkeyBoost = () => {
this.handleReblogClick(this.props.status);
this.handleRepostClick(this.props.status);
}
handleHotkeyMention = e => {
@@ -432,7 +432,7 @@ class Status extends ImmutablePureComponent {
moveUp: this.handleHotkeyMoveUp,
moveDown: this.handleHotkeyMoveDown,
reply: this.handleHotkeyReply,
favourite: this.handleHotkeyFavourite,
favorite: this.handleHotkeyFavorite,
boost: this.handleHotkeyBoost,
mention: this.handleHotkeyMention,
openProfile: this.handleHotkeyOpenProfile,
@@ -481,11 +481,11 @@ class Status extends ImmutablePureComponent {
showThread
/>
<ActionBar
{/*<ActionBar
status={status}
onReply={this.handleReplyClick}
onFavourite={this.handleFavouriteClick}
onReblog={this.handleReblogClick}
onFavorite={this.handleFavoriteClick}
onRepost={this.handleRepostClick}
onDelete={this.handleDeleteClick}
onDirect={this.handleDirectClick}
onMention={this.handleMentionClick}
@@ -495,7 +495,7 @@ class Status extends ImmutablePureComponent {
onReport={this.handleReport}
onPin={this.handlePin}
onEmbed={this.handleEmbed}
/>
/>*/}
</div>
</HotKeys>

View File

@@ -182,8 +182,10 @@ class SwitchingArea extends PureComponent {
<Redirect from='/@:username' to='/:username' exact />
<WrappedRoute path='/:username' publicRoute exact page={ProfilePage} component={AccountTimeline} content={children} />
{ /*
<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' page={ProfilePage} component={Followers} content={children} />
@@ -191,11 +193,8 @@ class SwitchingArea extends PureComponent {
<Redirect from='/@:username/following' to='/:username/following' />
<WrappedRoute path='/:username/following' page={ProfilePage} component={Following} content={children} />
<Redirect from='/@:username/photos' to='/:username/photos' />
<WrappedRoute path='/:username/photos' page={ProfilePage} component={AccountGallery} content={children} componentParams={{ mediaType: 'photo' }} />
<Redirect from='/@:username/videos' to='/:username/videos' />
<WrappedRoute path='/:username/videos' page={ProfilePage} component={AccountGallery} content={children} componentParams={{ mediaType: 'video' }} />
<Redirect from='/@:username/media' to='/:username/media' />
<WrappedRoute path='/:username/media' page={ProfilePage} component={AccountGallery} content={children} />
<Redirect from='/@:username/favorites' to='/:username/favorites' />
<WrappedRoute path='/:username/favorites' page={ProfilePage} component={FavoritedStatuses} content={children} />
@@ -203,8 +202,8 @@ class SwitchingArea extends PureComponent {
<Redirect from='/@:username/posts/:statusId' to='/:username/posts/:statusId' exact />
<WrappedRoute path='/:username/posts/:statusId' publicRoute exact page={BasicPage} component={Status} content={children} componentParams={{ title: 'Status' }} />
<Redirect from='/@:username/posts/:statusId/reblogs' to='/:username/posts/:statusId/reblogs' />
<WrappedRoute path='/:username/posts/:statusId/reblogs' page={BasicPage} component={Reblogs} content={children} componentParams={{ title: 'Reblogs' }} />
<Redirect from='/@:username/posts/:statusId/reposts' to='/:username/posts/:statusId/reposts' />
<WrappedRoute path='/:username/posts/:statusId/reposts' page={BasicPage} component={Reposts} content={children} componentParams={{ title: 'Reposts' }} />
<Redirect from='/@:username/posts/:statusId/favorites' to='/:username/posts/:statusId/favorites' />
<WrappedRoute path='/:username/posts/:statusId/favorites' page={BasicPage} component={Favorites} content={children} componentParams={{ title: 'Favorites' }} />

View File

@@ -1,47 +0,0 @@
.ui {
display: block;
width: 100%;
padding: 0 0 100px 0;
}
@media screen and (max-width: 630px) and (max-height: 400px) {
.is-composing {
.tabs-bar,
.search {
margin-top: -50px;
}
.navigation-bar {
padding-bottom: 0;
&>a:first-child {
margin: -100px 10px 0 -50px;
}
&__profile {
padding-top: 2px;
}
&__profile-edit {
position: absolute;
margin-top: -60px;
}
&__actions {
.icon-button.close {
pointer-events: auto;
opacity: 1;
transform: scale(1.0, 1.0) translate(0, 0);
bottom: 5px;
}
.compose__action-bar .icon-button {
pointer-events: none;
opacity: 0;
transform: scale(0.0, 1.0) translate(100%, 0);
}
}
}
}
}

View File

@@ -114,8 +114,8 @@ export function Notifications() {
return import(/* webpackChunkName: "features/notifications" */'../../notifications')
}
export function Reblogs() {
return import(/* webpackChunkName: "features/reblogs" */'../../reblogs')
export function Reposts() {
return import(/* webpackChunkName: "features/reblogs" */'../../reposts')
}
export function ReportModal() {