Merge branch 'next' into 'locked-profile-header'
# Conflicts: # app/soapbox/features/account/components/header.js # app/soapbox/pages/profile_page.js
This commit is contained in:
commit
be5203f406
|
@ -25,7 +25,7 @@ exports[`<TimelineQueueButtonHeader /> renders correctly 1`] = `
|
|||
|
||||
exports[`<TimelineQueueButtonHeader /> renders correctly 2`] = `
|
||||
<div
|
||||
className="timeline-queue-header"
|
||||
className="timeline-queue-header hidden"
|
||||
>
|
||||
<a
|
||||
className="timeline-queue-header__btn"
|
||||
|
@ -42,14 +42,18 @@ exports[`<TimelineQueueButtonHeader /> renders correctly 2`] = `
|
|||
}
|
||||
/>
|
||||
</div>
|
||||
Click to see 1 new post
|
||||
<div
|
||||
className="timeline-queue-header__label"
|
||||
>
|
||||
Click to see 1 new post
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<TimelineQueueButtonHeader /> renders correctly 3`] = `
|
||||
<div
|
||||
className="timeline-queue-header"
|
||||
className="timeline-queue-header hidden"
|
||||
>
|
||||
<a
|
||||
className="timeline-queue-header__btn"
|
||||
|
@ -66,7 +70,11 @@ exports[`<TimelineQueueButtonHeader /> renders correctly 3`] = `
|
|||
}
|
||||
/>
|
||||
</div>
|
||||
Click to see 9999999 new posts
|
||||
<div
|
||||
className="timeline-queue-header__label"
|
||||
>
|
||||
Click to see 9999999 new posts
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { MediaGallery } from 'soapbox/features/ui/util/async-components';
|
||||
import { openModal } from 'soapbox/actions/modal';
|
||||
import Bundle from 'soapbox/features/ui/components/bundle';
|
||||
|
||||
export default @connect()
|
||||
class AttachmentThumbs extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
media: ImmutablePropTypes.list.isRequired,
|
||||
onClick: PropTypes.func,
|
||||
};
|
||||
|
||||
renderLoading() {
|
||||
return <div className='media-gallery--compact' />;
|
||||
}
|
||||
|
||||
onOpenMedia = (media, index) => {
|
||||
this.props.dispatch(openModal('MEDIA', { media, index }));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { media, onClick } = this.props;
|
||||
|
||||
return (
|
||||
<div className='attachment-thumbs'>
|
||||
<Bundle fetchComponent={MediaGallery} loading={this.renderLoading}>
|
||||
{Component => (
|
||||
<Component
|
||||
media={media}
|
||||
onOpenMedia={this.onOpenMedia}
|
||||
height={50}
|
||||
compact
|
||||
/>
|
||||
)}
|
||||
</Bundle>
|
||||
{onClick && (
|
||||
<div className='attachment-thumbs__clickable-region' onClick={onClick} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,185 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import classNames from 'classnames';
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
import { fetchLists } from 'soapbox/actions/lists';
|
||||
import { createSelector } from 'reselect';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
const messages = defineMessages({
|
||||
show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
|
||||
hide: { id: 'column_header.hide_settings', defaultMessage: 'Hide settings' },
|
||||
homeTitle: { id: 'home_column_header.home', defaultMessage: 'Home' },
|
||||
allTitle: { id: 'home_column_header.all', defaultMessage: 'All' },
|
||||
fediverseTitle: { id: 'home_column_header.fediverse', defaultMessage: 'Fediverse' },
|
||||
listTitle: { id: 'home_column.lists', defaultMessage: 'Lists' },
|
||||
});
|
||||
|
||||
const getOrderedLists = createSelector([state => state.get('lists')], lists => {
|
||||
if (!lists) {
|
||||
return lists;
|
||||
}
|
||||
|
||||
return lists.toList().filter(item => !!item).sort((a, b) => a.get('title').localeCompare(b.get('title')));
|
||||
});
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const instance = state.get('instance');
|
||||
const features = getFeatures(instance);
|
||||
|
||||
return {
|
||||
lists: getOrderedLists(state),
|
||||
siteTitle: state.getIn(['instance', 'title']),
|
||||
federating: features.federating,
|
||||
};
|
||||
};
|
||||
|
||||
class ColumnHeader extends React.PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
active: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
activeItem: PropTypes.string,
|
||||
activeSubItem: PropTypes.string,
|
||||
lists: ImmutablePropTypes.list,
|
||||
siteTitle: PropTypes.string,
|
||||
federating: PropTypes.bool,
|
||||
};
|
||||
|
||||
state = {
|
||||
collapsed: true,
|
||||
animating: false,
|
||||
expandedFor: null, //lists, groups, etc.
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatch(fetchLists());
|
||||
}
|
||||
|
||||
handleToggleClick = (e) => {
|
||||
e.stopPropagation();
|
||||
this.setState({ collapsed: !this.state.collapsed, animating: true });
|
||||
}
|
||||
|
||||
handleTransitionEnd = () => {
|
||||
this.setState({ animating: false });
|
||||
}
|
||||
|
||||
expandLists = () => {
|
||||
this.setState({
|
||||
expandedFor: 'lists',
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { active, children, intl: { formatMessage }, activeItem, activeSubItem, lists, siteTitle, federating } = this.props;
|
||||
const { collapsed, animating, expandedFor } = this.state;
|
||||
|
||||
const wrapperClassName = classNames('column-header__wrapper', {
|
||||
'active': active,
|
||||
});
|
||||
|
||||
const buttonClassName = classNames('column-header', {
|
||||
'active': active,
|
||||
});
|
||||
|
||||
const collapsibleClassName = classNames('column-header__collapsible', {
|
||||
'collapsed': collapsed,
|
||||
'animating': animating,
|
||||
});
|
||||
|
||||
const collapsibleButtonClassName = classNames('column-header__button', {
|
||||
'active': !collapsed,
|
||||
});
|
||||
|
||||
const expansionClassName = classNames('column-header column-header__expansion', {
|
||||
'open': expandedFor,
|
||||
});
|
||||
|
||||
let extraContent, collapseButton;
|
||||
|
||||
if (children) {
|
||||
extraContent = (
|
||||
<div key='extra-content' className='column-header__collapsible__extra'>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
collapseButton = <button className={collapsibleButtonClassName} title={formatMessage(collapsed ? messages.show : messages.hide)} aria-label={formatMessage(collapsed ? messages.show : messages.hide)} aria-pressed={collapsed ? 'false' : 'true'} onClick={this.handleToggleClick}><Icon id='sliders' /></button>;
|
||||
}
|
||||
|
||||
const collapsedContent = [
|
||||
extraContent,
|
||||
];
|
||||
|
||||
let expandedContent = null;
|
||||
if ((expandedFor === 'lists' || activeItem === 'lists') && lists) {
|
||||
expandedContent = lists.map(list =>
|
||||
(<Link
|
||||
key={list.get('id')}
|
||||
to={`/list/${list.get('id')}`}
|
||||
className={
|
||||
classNames('btn btn--sub grouped', {
|
||||
'active': list.get('id') === activeSubItem,
|
||||
})
|
||||
}
|
||||
>
|
||||
{list.get('title')}
|
||||
</Link>),
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={wrapperClassName}>
|
||||
<h1 className={buttonClassName}>
|
||||
<Link to='/' className={classNames('btn grouped', { 'active': 'home' === activeItem })}>
|
||||
<Icon id='home' fixedWidth className='column-header__icon' />
|
||||
{formatMessage(messages.homeTitle)}
|
||||
</Link>
|
||||
|
||||
<Link to='/timeline/local' className={classNames('btn grouped', { 'active': 'local' === activeItem })}>
|
||||
<Icon id={federating ? 'users' : 'globe-w'} fixedWidth className='column-header__icon' />
|
||||
{federating ? siteTitle : formatMessage(messages.allTitle)}
|
||||
</Link>
|
||||
|
||||
{federating && <Link to='/timeline/fediverse' className={classNames('btn grouped', { 'active': 'fediverse' === activeItem })}>
|
||||
<Icon id='fediverse' fixedWidth className='column-header__icon' />
|
||||
{formatMessage(messages.fediverseTitle)}
|
||||
</Link>}
|
||||
|
||||
<div className='column-header__buttons'>
|
||||
{collapseButton}
|
||||
</div>
|
||||
</h1>
|
||||
|
||||
{
|
||||
expandedContent &&
|
||||
<h1 className={expansionClassName}>
|
||||
{expandedContent}
|
||||
</h1>
|
||||
}
|
||||
|
||||
<div className={collapsibleClassName} tabIndex={collapsed ? -1 : null} onTransitionEnd={this.handleTransitionEnd}>
|
||||
<div className='column-header__collapsible-inner'>
|
||||
{(!collapsed || animating) && collapsedContent}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(connect(mapStateToProps)(ColumnHeader));
|
|
@ -19,9 +19,9 @@ export default class MaterialStatus extends React.Component {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className='material-status'>
|
||||
<div className='material-status__status'>
|
||||
<StatusContainer {...this.props} />
|
||||
<div className='material-status' tabIndex={-1}>
|
||||
<div className='material-status__status focusable' tabIndex={0}>
|
||||
<StatusContainer {...this.props} focusable={false} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -279,6 +279,7 @@ class MediaGallery extends React.PureComponent {
|
|||
visible: PropTypes.bool,
|
||||
onToggleVisibility: PropTypes.func,
|
||||
displayMedia: PropTypes.string,
|
||||
compact: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -560,7 +561,7 @@ class MediaGallery extends React.PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { media, intl, sensitive } = this.props;
|
||||
const { media, intl, sensitive, compact } = this.props;
|
||||
const { visible } = this.state;
|
||||
const sizeData = this.getSizeData(media.size);
|
||||
|
||||
|
@ -592,7 +593,7 @@ class MediaGallery extends React.PureComponent {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className='media-gallery' style={sizeData.get('style')} ref={this.handleRef}>
|
||||
<div className={classNames('media-gallery', { 'media-gallery--compact': compact })} style={sizeData.get('style')} ref={this.handleRef}>
|
||||
<div className={classNames('spoiler-button', { 'spoiler-button--minified': visible })}>
|
||||
{spoilerButton}
|
||||
</div>
|
||||
|
|
|
@ -8,7 +8,7 @@ import RelativeTimestamp from './relative_timestamp';
|
|||
import DisplayName from './display_name';
|
||||
import StatusContent from './status_content';
|
||||
import StatusActionBar from './status_action_bar';
|
||||
import AttachmentList from './attachment_list';
|
||||
import AttachmentThumbs from './attachment_thumbs';
|
||||
import Card from '../features/status/components/card';
|
||||
import { injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
@ -93,6 +93,11 @@ class Status extends ImmutablePureComponent {
|
|||
group: ImmutablePropTypes.map,
|
||||
displayMedia: PropTypes.string,
|
||||
allowedEmoji: ImmutablePropTypes.list,
|
||||
focusable: PropTypes.bool,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
focusable: true,
|
||||
};
|
||||
|
||||
// Avoid checking props that are functions (and whose equality will always
|
||||
|
@ -336,7 +341,7 @@ class Status extends ImmutablePureComponent {
|
|||
|
||||
return (
|
||||
<HotKeys handlers={minHandlers}>
|
||||
<div className='status__wrapper status__wrapper--filtered focusable' tabIndex='0' ref={this.handleRef}>
|
||||
<div className={classNames('status__wrapper', 'status__wrapper--filtered', { focusable: this.props.focusable })} tabIndex={this.props.focusable ? 0 : null} ref={this.handleRef}>
|
||||
<FormattedMessage id='status.filtered' defaultMessage='Filtered' />
|
||||
</div>
|
||||
</HotKeys>
|
||||
|
@ -384,10 +389,7 @@ class Status extends ImmutablePureComponent {
|
|||
if (size > 0) {
|
||||
if (this.props.muted) {
|
||||
media = (
|
||||
<AttachmentList
|
||||
compact
|
||||
media={status.get('media_attachments')}
|
||||
/>
|
||||
<AttachmentThumbs media={status.get('media_attachments')} onClick={this.handleClick} />
|
||||
);
|
||||
} else if (size === 1 && status.getIn(['media_attachments', 0, 'type']) === 'video') {
|
||||
const video = status.getIn(['media_attachments', 0]);
|
||||
|
@ -493,7 +495,7 @@ class Status extends ImmutablePureComponent {
|
|||
|
||||
return (
|
||||
<HotKeys handlers={handlers}>
|
||||
<div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), read: unread === false, focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText)} ref={this.handleRef}>
|
||||
<div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), read: unread === false, focusable: this.props.focusable && !this.props.muted })} tabIndex={this.props.focusable && !this.props.muted ? 0 : null} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText)} ref={this.handleRef}>
|
||||
{prepend}
|
||||
|
||||
<div className={classNames('status', `status-${status.get('visibility')}`, { 'status-reply': !!status.get('in_reply_to_id'), muted: this.props.muted, read: unread === false })} data-id={status.get('id')}>
|
||||
|
|
|
@ -458,7 +458,13 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||
emoji={meEmojiReact}
|
||||
onClick={this.handleLikeButtonClick}
|
||||
/>
|
||||
{emojiReactCount !== 0 && <span className='detailed-status__link'>{emojiReactCount}</span>}
|
||||
{emojiReactCount !== 0 && (
|
||||
(features.exposableReactions && !features.emojiReacts) ? (
|
||||
<Link to={`/@${status.getIn(['account', 'acct'])}/posts/${status.get('id')}/likes`} className='detailed-status__link'>{emojiReactCount}</Link>
|
||||
) : (
|
||||
<span className='detailed-status__link'>{emojiReactCount}</span>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
{shareButton}
|
||||
|
||||
|
|
|
@ -82,7 +82,6 @@ export default class StatusList extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
handleDequeueTimeline = () => {
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
const { onDequeueTimeline, timelineId } = this.props;
|
||||
if (!onDequeueTimeline || !timelineId) return;
|
||||
onDequeueTimeline(timelineId);
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { throttle } from 'lodash';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export default class SubNavigation extends React.PureComponent {
|
||||
|
||||
|
@ -13,6 +15,10 @@ export default class SubNavigation extends React.PureComponent {
|
|||
router: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
state = {
|
||||
scrolled: false,
|
||||
}
|
||||
|
||||
handleBackClick = () => {
|
||||
if (window.history && window.history.length === 1) {
|
||||
this.context.router.history.push('/');
|
||||
|
@ -27,11 +33,44 @@ export default class SubNavigation extends React.PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.attachScrollListener();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.detachScrollListener();
|
||||
}
|
||||
|
||||
attachScrollListener() {
|
||||
window.addEventListener('scroll', this.handleScroll);
|
||||
}
|
||||
|
||||
detachScrollListener() {
|
||||
window.removeEventListener('scroll', this.handleScroll);
|
||||
}
|
||||
|
||||
handleScroll = throttle(() => {
|
||||
if (this.node) {
|
||||
const { top } = this.node.getBoundingClientRect();
|
||||
|
||||
if (top <= 50) {
|
||||
this.setState({ scrolled: true });
|
||||
} else {
|
||||
this.setState({ scrolled: false });
|
||||
}
|
||||
}
|
||||
}, 150, { trailing: true });
|
||||
|
||||
setRef = c => {
|
||||
this.node = c;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { message } = this.props;
|
||||
const { scrolled } = this.state;
|
||||
|
||||
return (
|
||||
<div className='sub-navigation'>
|
||||
<div className={classNames('sub-navigation', { 'sub-navigation--scrolled': scrolled })} ref={this.setRef}>
|
||||
<div className='sub-navigation__content'>
|
||||
<button
|
||||
className='sub-navigation__back'
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import { throttle } from 'lodash';
|
||||
import classNames from 'classnames';
|
||||
import SvgIcon from 'soapbox/components/svg_icon';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
|
||||
export default @injectIntl
|
||||
class TimelineQueueButtonHeader extends React.PureComponent {
|
||||
|
@ -11,25 +12,87 @@ class TimelineQueueButtonHeader extends React.PureComponent {
|
|||
onClick: PropTypes.func.isRequired,
|
||||
count: PropTypes.number,
|
||||
message: PropTypes.object.isRequired,
|
||||
threshold: PropTypes.number,
|
||||
intl: PropTypes.object.isRequired,
|
||||
autoload: PropTypes.bool,
|
||||
autoloadThreshold: PropTypes.number,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
count: 0,
|
||||
threshold: 400,
|
||||
autoload: true,
|
||||
autoloadThreshold: 50,
|
||||
};
|
||||
|
||||
state = {
|
||||
scrolled: false,
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.attachScrollListener();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.detachScrollListener();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
const { scrollTop } = (document.scrollingElement || document.documentElement);
|
||||
const { count, onClick, autoload, autoloadThreshold } = this.props;
|
||||
|
||||
if (autoload && scrollTop <= autoloadThreshold && count !== prevProps.count) {
|
||||
onClick();
|
||||
}
|
||||
}
|
||||
|
||||
attachScrollListener() {
|
||||
window.addEventListener('scroll', this.handleScroll);
|
||||
}
|
||||
|
||||
detachScrollListener() {
|
||||
window.removeEventListener('scroll', this.handleScroll);
|
||||
}
|
||||
|
||||
handleScroll = throttle(() => {
|
||||
const { scrollTop } = (document.scrollingElement || document.documentElement);
|
||||
const { threshold, onClick, autoload, autoloadThreshold } = this.props;
|
||||
|
||||
if (autoload && scrollTop <= autoloadThreshold) {
|
||||
onClick();
|
||||
}
|
||||
|
||||
if (scrollTop > threshold) {
|
||||
this.setState({ scrolled: true });
|
||||
} else {
|
||||
this.setState({ scrolled: false });
|
||||
}
|
||||
}, 150, { trailing: true });
|
||||
|
||||
handleClick = e => {
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
this.props.onClick(e);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { count, message, onClick, intl } = this.props;
|
||||
const { count, message, intl } = this.props;
|
||||
const { scrolled } = this.state;
|
||||
|
||||
const visible = count > 0 && scrolled;
|
||||
|
||||
const classes = classNames('timeline-queue-header', {
|
||||
'hidden': (count <= 0),
|
||||
'hidden': !visible,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={classes}>
|
||||
<a className='timeline-queue-header__btn' onClick={onClick}>
|
||||
<SvgIcon src={require('@tabler/icons/icons/arrow-bar-to-up.svg')} />
|
||||
{(count > 0) && intl.formatMessage(message, { count })}
|
||||
<a className='timeline-queue-header__btn' onClick={this.handleClick}>
|
||||
<Icon src={require('@tabler/icons/icons/arrow-bar-to-up.svg')} />
|
||||
{(count > 0) && (
|
||||
<div className='timeline-queue-header__label'>
|
||||
{intl.formatMessage(message, { count })}
|
||||
</div>
|
||||
)}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -20,6 +20,8 @@ import classNames from 'classnames';
|
|||
import Avatar from 'soapbox/components/avatar';
|
||||
import { getAcct } from 'soapbox/utils/accounts';
|
||||
import { displayFqn } from 'soapbox/utils/state';
|
||||
import { shortNumberFormat } from 'soapbox/utils/numbers';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import DropdownMenuContainer from 'soapbox/containers/dropdown_menu_container';
|
||||
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
|
||||
import { ProfileInfoPanel } from 'soapbox/features/ui/util/async-components';
|
||||
|
@ -346,11 +348,12 @@ class Header extends ImmutablePureComponent {
|
|||
);
|
||||
}
|
||||
|
||||
const ownAccount = account.get('id') === me;
|
||||
const info = this.makeInfo();
|
||||
const menu = this.makeMenu();
|
||||
|
||||
const header = account.get('header', '');
|
||||
const headerMissing = !header || ['/images/banner.png', '/headers/original/missing.png'].some(path => header.endsWith(path));
|
||||
// const headerMissing = !header || ['/images/banner.png', '/headers/original/missing.png'].some(path => header.endsWith(path));
|
||||
const avatarSize = isSmallScreen ? 90 : 200;
|
||||
const deactivated = !account.getIn(['pleroma', 'is_active'], true);
|
||||
|
||||
|
@ -360,7 +363,7 @@ class Header extends ImmutablePureComponent {
|
|||
|
||||
return (
|
||||
<div className={classNames('account__header', { inactive: !!account.get('moved'), deactivated: deactivated })}>
|
||||
<div className={classNames('account__header__image', { 'account__header__image--none': headerMissing || deactivated })}>
|
||||
<div className={classNames('account__header__image', { /* 'account__header__image--none': headerMissing || deactivated */ })}>
|
||||
<div className='account__header__info'>
|
||||
{info}
|
||||
</div>
|
||||
|
@ -392,6 +395,40 @@ class Header extends ImmutablePureComponent {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className='account__header__extra__links'>
|
||||
|
||||
<NavLink isActive={this.isStatusesPageActive} activeClassName='active' to={`/@${account.get('acct')}`} title={intl.formatNumber(account.get('statuses_count'))}>
|
||||
<span>{shortNumberFormat(account.get('statuses_count'))}</span>
|
||||
<span><FormattedMessage id='account.posts' defaultMessage='Posts' /></span>
|
||||
</NavLink>
|
||||
|
||||
{(ownAccount || !account.getIn(['pleroma', 'hide_follows'], false)) && <NavLink exact activeClassName='active' to={`/@${account.get('acct')}/following`} title={intl.formatNumber(account.get('following_count'))}>
|
||||
{account.getIn(['pleroma', 'hide_follows_count'], false) ? <span>•</span> : <span>{shortNumberFormat(account.get('following_count'))}</span>}
|
||||
<span><FormattedMessage id='account.follows' defaultMessage='Follows' /></span>
|
||||
</NavLink>}
|
||||
|
||||
{(ownAccount || !account.getIn(['pleroma', 'hide_followers'], false)) && <NavLink exact activeClassName='active' to={`/@${account.get('acct')}/followers`} title={intl.formatNumber(account.get('followers_count'))}>
|
||||
{account.getIn(['pleroma', 'hide_followers_count'], false) ? <span>•</span> : <span>{shortNumberFormat(account.get('followers_count'))}</span>}
|
||||
<span><FormattedMessage id='account.followers' defaultMessage='Followers' /></span>
|
||||
</NavLink>}
|
||||
|
||||
{(ownAccount || !account.getIn(['pleroma', 'hide_favorites'], true)) && <NavLink exact activeClassName='active' to={`/@${account.get('acct')}/favorites`}>
|
||||
{ /* : TODO : shortNumberFormat(account.get('favourite_count')) */ }
|
||||
<span>•</span>
|
||||
<span><FormattedMessage id='navigation_bar.favourites' defaultMessage='Likes' /></span>
|
||||
</NavLink>}
|
||||
|
||||
{ownAccount &&
|
||||
<NavLink
|
||||
exact activeClassName='active' to={`/@${account.get('acct')}/pins`}
|
||||
>
|
||||
{ /* : TODO : shortNumberFormat(account.get('pinned_count')) */ }
|
||||
<span>•</span>
|
||||
<span><FormattedMessage id='navigation_bar.pins' defaultMessage='Pins' /></span>
|
||||
</NavLink>
|
||||
}
|
||||
</div>
|
||||
|
||||
{isSmallScreen && (
|
||||
<div className={classNames('account-mobile-container', { 'deactivated': deactivated })}>
|
||||
<BundleContainer fetchComponent={ProfileInfoPanel}>
|
||||
|
|
|
@ -10,7 +10,7 @@ import { expandAccountMediaTimeline } from '../../actions/timelines';
|
|||
import LoadingIndicator from 'soapbox/components/loading_indicator';
|
||||
import Column from '../ui/components/column';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { getAccountGallery } from 'soapbox/selectors';
|
||||
import { getAccountGallery, findAccountByUsername } from 'soapbox/selectors';
|
||||
import MediaItem from './components/media_item';
|
||||
import LoadMore from 'soapbox/components/load_more';
|
||||
import MissingIndicator from 'soapbox/components/missing_indicator';
|
||||
|
@ -21,7 +21,6 @@ import { FormattedMessage } from 'react-intl';
|
|||
const mapStateToProps = (state, { params, withReplies = false }) => {
|
||||
const username = params.username || '';
|
||||
const me = state.get('me');
|
||||
const accounts = state.getIn(['accounts']);
|
||||
const accountFetchError = (state.getIn(['accounts', -1, 'username'], '').toLowerCase() === username.toLowerCase());
|
||||
|
||||
let accountId = -1;
|
||||
|
@ -29,7 +28,7 @@ const mapStateToProps = (state, { params, withReplies = false }) => {
|
|||
if (accountFetchError) {
|
||||
accountId = null;
|
||||
} else {
|
||||
const account = accounts.find(acct => username.toLowerCase() === acct.getIn(['acct'], '').toLowerCase());
|
||||
const account = findAccountByUsername(state, username);
|
||||
accountId = account ? account.getIn(['id'], null) : -1;
|
||||
accountUsername = account ? account.getIn(['acct'], '') : '';
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import { NavLink } from 'react-router-dom';
|
|||
import { fetchPatronAccount } from '../../actions/patron';
|
||||
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
|
||||
import { getSettings } from 'soapbox/actions/settings';
|
||||
import { makeGetStatusIds } from 'soapbox/selectors';
|
||||
import { makeGetStatusIds, findAccountByUsername } from 'soapbox/selectors';
|
||||
import classNames from 'classnames';
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
|
@ -27,7 +27,6 @@ const makeMapStateToProps = () => {
|
|||
const mapStateToProps = (state, { params, withReplies = false }) => {
|
||||
const username = params.username || '';
|
||||
const me = state.get('me');
|
||||
const accounts = state.getIn(['accounts']);
|
||||
const accountFetchError = (state.getIn(['accounts', -1, 'username'], '').toLowerCase() === username.toLowerCase());
|
||||
const soapboxConfig = getSoapboxConfig(state);
|
||||
|
||||
|
@ -37,7 +36,7 @@ const makeMapStateToProps = () => {
|
|||
if (accountFetchError) {
|
||||
accountId = null;
|
||||
} else {
|
||||
const account = accounts.find(acct => username.toLowerCase() === acct.getIn(['acct'], '').toLowerCase());
|
||||
const account = findAccountByUsername(state, username);
|
||||
accountId = account ? account.getIn(['id'], null) : -1;
|
||||
accountUsername = account ? account.getIn(['acct'], '') : '';
|
||||
accountApId = account ? account.get('url') : '';
|
||||
|
|
|
@ -103,7 +103,6 @@ class UserIndex extends ImmutablePureComponent {
|
|||
<Column>
|
||||
<SimpleForm style={{ paddingBottom: 0 }}>
|
||||
<TextInput
|
||||
value={this.state.q}
|
||||
onChange={this.handleQueryChange}
|
||||
placeholder={intl.formatMessage(messages.searchPlaceholder)}
|
||||
/>
|
||||
|
|
|
@ -171,9 +171,8 @@ class ChatBox extends ImmutablePureComponent {
|
|||
return this.canSubmit() ? (
|
||||
<div className='chat-box__send'>
|
||||
<IconButton
|
||||
icon='send'
|
||||
src={require('@tabler/icons/icons/send.svg')}
|
||||
title={intl.formatMessage(messages.send)}
|
||||
size={16}
|
||||
onClick={this.sendMessage}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import CharacterCounter from './character_counter';
|
||||
// import TextCharacterCounter from './text_character_counter';
|
||||
import VisualCharacterCounter from './visual_character_counter';
|
||||
import Button from '../../../components/button';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PropTypes from 'prop-types';
|
||||
|
@ -351,7 +352,12 @@ export default class ComposeForm extends ImmutablePureComponent {
|
|||
<SpoilerButtonContainer />
|
||||
<MarkdownButtonContainer />
|
||||
</div>
|
||||
{maxTootChars && <div className='character-counter__wrapper'><CharacterCounter max={maxTootChars} text={text} /></div>}
|
||||
{maxTootChars && (
|
||||
<div className='compose-form__counter'>
|
||||
{/* <TextCharacterCounter max={maxTootChars} text={text} /> */}
|
||||
<VisualCharacterCounter max={maxTootChars} text={text} />
|
||||
</div>
|
||||
)}
|
||||
<div className='compose-form__publish'>
|
||||
<div className='compose-form__publish-button-wrapper'><Button text={publishText} onClick={this.handleSubmit} disabled={disabledButton} block /></div>
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,7 @@ import DisplayName from '../../../components/display_name';
|
|||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { isRtl } from '../../../rtl';
|
||||
import AttachmentList from 'soapbox/components/attachment_list';
|
||||
import AttachmentThumbs from 'soapbox/components/attachment_thumbs';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
const messages = defineMessages({
|
||||
|
@ -57,7 +57,7 @@ class ReplyIndicator extends ImmutablePureComponent {
|
|||
<div className='reply-indicator__content' style={style} dangerouslySetInnerHTML={content} />
|
||||
|
||||
{status.get('media_attachments').size > 0 && (
|
||||
<AttachmentList
|
||||
<AttachmentThumbs
|
||||
compact
|
||||
media={status.get('media_attachments')}
|
||||
/>
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { length } from 'stringz';
|
||||
|
||||
export default class TextCharacterCounter extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
text: PropTypes.string.isRequired,
|
||||
max: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
checkRemainingText(diff) {
|
||||
if (diff < 0) {
|
||||
return <span className='character-counter character-counter--over'>{diff}</span>;
|
||||
}
|
||||
|
||||
return <span className='character-counter'>{diff}</span>;
|
||||
}
|
||||
|
||||
render() {
|
||||
const diff = this.props.max - length(this.props.text);
|
||||
return this.checkRemainingText(diff);
|
||||
}
|
||||
|
||||
}
|
|
@ -13,7 +13,7 @@ const messages = defineMessages({
|
|||
* @param {string} props.text - text to use to measure
|
||||
* @param {number} props.max - max text allowed
|
||||
*/
|
||||
class CharacterCounter extends React.PureComponent {
|
||||
class VisualCharacterCounter extends React.PureComponent {
|
||||
|
||||
render() {
|
||||
const { intl, text, max } = this.props;
|
||||
|
@ -22,21 +22,23 @@ class CharacterCounter extends React.PureComponent {
|
|||
const progress = textLength / max;
|
||||
|
||||
return (
|
||||
<ProgressCircle
|
||||
title={intl.formatMessage(messages.title, { chars: textLength, maxChars: max })}
|
||||
progress={progress}
|
||||
radius={10}
|
||||
stroke={3}
|
||||
/>
|
||||
<div className='visual-character-counter'>
|
||||
<ProgressCircle
|
||||
title={intl.formatMessage(messages.title, { chars: textLength, maxChars: max })}
|
||||
progress={progress}
|
||||
radius={10}
|
||||
stroke={3}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CharacterCounter.propTypes = {
|
||||
VisualCharacterCounter.propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
text: PropTypes.string.isRequired,
|
||||
max: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(CharacterCounter);
|
||||
export default injectIntl(VisualCharacterCounter);
|
|
@ -6,30 +6,41 @@ import {
|
|||
showSearch,
|
||||
} from '../../../actions/search';
|
||||
import Search from '../components/search';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
value: state.getIn(['search', 'value']),
|
||||
submitted: state.getIn(['search', 'submitted']),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
const mapDispatchToProps = (dispatch, { autoSubmit }) => {
|
||||
|
||||
onChange(value) {
|
||||
dispatch(changeSearch(value));
|
||||
},
|
||||
|
||||
onClear() {
|
||||
dispatch(clearSearch());
|
||||
},
|
||||
|
||||
onSubmit() {
|
||||
const debouncedSubmit = debounce(() => {
|
||||
dispatch(submitSearch());
|
||||
},
|
||||
}, 900);
|
||||
|
||||
onShow() {
|
||||
dispatch(showSearch());
|
||||
},
|
||||
return {
|
||||
onChange(value) {
|
||||
dispatch(changeSearch(value));
|
||||
|
||||
});
|
||||
if (autoSubmit) {
|
||||
debouncedSubmit();
|
||||
}
|
||||
},
|
||||
|
||||
onClear() {
|
||||
dispatch(clearSearch());
|
||||
},
|
||||
|
||||
onSubmit() {
|
||||
dispatch(submitSearch());
|
||||
},
|
||||
|
||||
onShow() {
|
||||
dispatch(showSearch());
|
||||
},
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Search);
|
||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { getAcct, isVerified } from 'soapbox/utils/accounts';
|
||||
import StillImage from 'soapbox/components/still_image';
|
||||
import VerificationBadge from 'soapbox/components/verification_badge';
|
||||
|
@ -13,7 +14,7 @@ const mapStateToProps = state => ({
|
|||
|
||||
const ProfilePreview = ({ account, displayFqn }) => (
|
||||
<div className='card h-card'>
|
||||
<a target='_blank' rel='noopener' href={account.get('url')}>
|
||||
<Link to={`/@${account.get('acct')}`}>
|
||||
<div className='card__img'>
|
||||
<StillImage alt='' src={account.get('header')} />
|
||||
</div>
|
||||
|
@ -32,7 +33,7 @@ const ProfilePreview = ({ account, displayFqn }) => (
|
|||
<span>@{getAcct(account, displayFqn)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import { debounce } from 'lodash';
|
|||
import MissingIndicator from 'soapbox/components/missing_indicator';
|
||||
import { fetchAccount, fetchAccountByUsername } from '../../actions/accounts';
|
||||
import LoadingIndicator from '../../components/loading_indicator';
|
||||
import { findAccountByUsername } from 'soapbox/selectors';
|
||||
|
||||
const mapStateToProps = (state, { params }) => {
|
||||
const username = params.username || '';
|
||||
|
@ -28,14 +29,13 @@ const mapStateToProps = (state, { params }) => {
|
|||
};
|
||||
}
|
||||
|
||||
const accounts = state.getIn(['accounts']);
|
||||
const accountFetchError = (state.getIn(['accounts', -1, 'username'], '').toLowerCase() === username.toLowerCase());
|
||||
|
||||
let accountId = -1;
|
||||
if (accountFetchError) {
|
||||
accountId = null;
|
||||
} else {
|
||||
const account = accounts.find(acct => username.toLowerCase() === acct.getIn(['acct'], '').toLowerCase());
|
||||
const account = findAccountByUsername(state, username);
|
||||
accountId = account ? account.getIn(['id'], null) : -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,19 +5,25 @@ import PropTypes from 'prop-types';
|
|||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import LoadingIndicator from '../../components/loading_indicator';
|
||||
import { fetchFavourites } from '../../actions/interactions';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||
import AccountContainer from '../../containers/account_container';
|
||||
import Column from '../ui/components/column';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.favourites', defaultMessage: 'Likes' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
accountIds: state.getIn(['user_lists', 'favourited_by', props.params.statusId]),
|
||||
});
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class Favourites extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
params: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
accountIds: ImmutablePropTypes.orderedSet,
|
||||
|
@ -37,7 +43,7 @@ class Favourites extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { accountIds } = this.props;
|
||||
const { intl, accountIds } = this.props;
|
||||
|
||||
if (!accountIds) {
|
||||
return (
|
||||
|
@ -50,7 +56,7 @@ class Favourites extends ImmutablePureComponent {
|
|||
const emptyMessage = <FormattedMessage id='empty_column.favourites' defaultMessage='No one has liked this post yet. When someone does, they will show up here.' />;
|
||||
|
||||
return (
|
||||
<Column>
|
||||
<Column heading={intl.formatMessage(messages.heading)}>
|
||||
<ScrollableList
|
||||
scrollKey='favourites'
|
||||
emptyMessage={emptyMessage}
|
||||
|
|
|
@ -17,18 +17,18 @@ import Column from '../ui/components/column';
|
|||
import ScrollableList from '../../components/scrollable_list';
|
||||
import MissingIndicator from 'soapbox/components/missing_indicator';
|
||||
import { getFollowDifference } from 'soapbox/utils/accounts';
|
||||
import { findAccountByUsername } from 'soapbox/selectors';
|
||||
|
||||
const mapStateToProps = (state, { params, withReplies = false }) => {
|
||||
const username = params.username || '';
|
||||
const me = state.get('me');
|
||||
const accounts = state.getIn(['accounts']);
|
||||
const accountFetchError = (state.getIn(['accounts', -1, 'username'], '').toLowerCase() === username.toLowerCase());
|
||||
|
||||
let accountId = -1;
|
||||
if (accountFetchError) {
|
||||
accountId = null;
|
||||
} else {
|
||||
const account = accounts.find(acct => username.toLowerCase() === acct.getIn(['acct'], '').toLowerCase());
|
||||
const account = findAccountByUsername(state, username);
|
||||
accountId = account ? account.getIn(['id'], null) : -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,18 +17,18 @@ import Column from '../ui/components/column';
|
|||
import ScrollableList from '../../components/scrollable_list';
|
||||
import MissingIndicator from 'soapbox/components/missing_indicator';
|
||||
import { getFollowDifference } from 'soapbox/utils/accounts';
|
||||
import { findAccountByUsername } from 'soapbox/selectors';
|
||||
|
||||
const mapStateToProps = (state, { params, withReplies = false }) => {
|
||||
const username = params.username || '';
|
||||
const me = state.get('me');
|
||||
const accounts = state.getIn(['accounts']);
|
||||
const accountFetchError = (state.getIn(['accounts', -1, 'username'], '').toLowerCase() === username.toLowerCase());
|
||||
|
||||
let accountId = -1;
|
||||
if (accountFetchError) {
|
||||
accountId = null;
|
||||
} else {
|
||||
const account = accounts.find(acct => username.toLowerCase() === acct.getIn(['acct'], '').toLowerCase());
|
||||
const account = findAccountByUsername(state, username);
|
||||
accountId = account ? account.getIn(['id'], null) : -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import { expandHashtagTimeline, clearTimeline } from '../../actions/timelines';
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
import { connectHashtagStream } from '../../actions/streaming';
|
||||
import { isEqual } from 'lodash';
|
||||
import ColumnBackButton from '../../components/column_back_button';
|
||||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}`, 'unread']) > 0,
|
||||
|
@ -26,8 +25,10 @@ class HashtagTimeline extends React.PureComponent {
|
|||
};
|
||||
|
||||
title = () => {
|
||||
const title = [this.props.params.id];
|
||||
const title = [`#${this.props.params.id}`];
|
||||
|
||||
// TODO: wtf is all this?
|
||||
// It exists in Mastodon's codebase, but undocumented
|
||||
if (this.additionalFor('any')) {
|
||||
title.push(' ', <FormattedMessage key='any' id='hashtag.column_header.tag_mode.any' values={{ additional: this.additionalFor('any') }} defaultMessage='or {additional}' />);
|
||||
}
|
||||
|
@ -43,6 +44,8 @@ class HashtagTimeline extends React.PureComponent {
|
|||
return title;
|
||||
}
|
||||
|
||||
// TODO: wtf is this?
|
||||
// It exists in Mastodon's codebase, but undocumented
|
||||
additionalFor = (mode) => {
|
||||
const { tags } = this.props.params;
|
||||
|
||||
|
@ -108,9 +111,8 @@ class HashtagTimeline extends React.PureComponent {
|
|||
const { id } = this.props.params;
|
||||
|
||||
return (
|
||||
<Column label={`#${id}`}>
|
||||
<ColumnBackButton />
|
||||
<ColumnHeader icon='hashtag' active={hasUnread} title={this.title()} />
|
||||
<Column label={`#${id}`} transparent>
|
||||
<ColumnHeader active={hasUnread} title={this.title()} />
|
||||
<StatusListContainer
|
||||
scrollKey='hashtag_timeline'
|
||||
timelineId={`hashtag:${id}`}
|
||||
|
|
|
@ -96,10 +96,11 @@ class HomeTimeline extends React.PureComponent {
|
|||
render() {
|
||||
const { intl, siteTitle, isLoading, isEmpty, features } = this.props;
|
||||
const { done } = this.state;
|
||||
const showSuggestions = features.suggestions && isEmpty && !isLoading && !done;
|
||||
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.title)} transparent>
|
||||
{(features.suggestions && isEmpty && !isLoading && !done) ? (
|
||||
<Column label={intl.formatMessage(messages.title)} transparent={!showSuggestions}>
|
||||
{showSuggestions ? (
|
||||
<BundleContainer fetchComponent={FollowRecommendationsContainer}>
|
||||
{Component => <Component onDone={this.handleDone} />}
|
||||
</BundleContainer>
|
||||
|
|
|
@ -3,7 +3,7 @@ import { connect } from 'react-redux';
|
|||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
import Column from '../../components/column';
|
||||
import Column from 'soapbox/features/ui/components/column';
|
||||
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
||||
import { connectListStream } from '../../actions/streaming';
|
||||
import { expandListTimeline } from '../../actions/timelines';
|
||||
|
@ -11,9 +11,6 @@ import { fetchList, deleteList } from '../../actions/lists';
|
|||
import { openModal } from '../../actions/modal';
|
||||
import MissingIndicator from '../../components/missing_indicator';
|
||||
import LoadingIndicator from '../../components/loading_indicator';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
import HomeColumnHeader from '../../components/home_column_header';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Button from 'soapbox/components/button';
|
||||
|
||||
const messages = defineMessages({
|
||||
|
@ -23,7 +20,7 @@ const messages = defineMessages({
|
|||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
list: state.getIn(['lists', props.params.id]),
|
||||
hasUnread: state.getIn(['timelines', `list:${props.params.id}`, 'unread']) > 0,
|
||||
// hasUnread: state.getIn(['timelines', `list:${props.params.id}`, 'unread']) > 0,
|
||||
});
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
|
@ -37,7 +34,7 @@ class ListTimeline extends React.PureComponent {
|
|||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
hasUnread: PropTypes.bool,
|
||||
// hasUnread: PropTypes.bool,
|
||||
list: PropTypes.oneOfType([ImmutablePropTypes.map, PropTypes.bool]),
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
@ -97,7 +94,7 @@ class ListTimeline extends React.PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { hasUnread, list } = this.props;
|
||||
const { list } = this.props;
|
||||
const { id } = this.props.params;
|
||||
const title = list ? list.get('title') : id;
|
||||
|
||||
|
@ -126,8 +123,8 @@ class ListTimeline extends React.PureComponent {
|
|||
);
|
||||
|
||||
return (
|
||||
<Column label={title}>
|
||||
<HomeColumnHeader activeItem='lists' activeSubItem={id} active={hasUnread}>
|
||||
<Column label={title} heading={title} transparent>
|
||||
{/* <HomeColumnHeader activeItem='lists' activeSubItem={id} active={hasUnread}>
|
||||
<div className='column-header__links'>
|
||||
<button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleEditClick}>
|
||||
<Icon id='pencil' /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' />
|
||||
|
@ -144,7 +141,7 @@ class ListTimeline extends React.PureComponent {
|
|||
<Icon id='arrow-right' />
|
||||
</Link>
|
||||
</div>
|
||||
</HomeColumnHeader>
|
||||
</HomeColumnHeader> */}
|
||||
|
||||
<StatusListContainer
|
||||
scrollKey='list_timeline'
|
||||
|
|
|
@ -7,12 +7,16 @@ import LoadingIndicator from '../../components/loading_indicator';
|
|||
import MissingIndicator from '../../components/missing_indicator';
|
||||
import { fetchReblogs } from '../../actions/interactions';
|
||||
import { fetchStatus } from '../../actions/statuses';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||
import AccountContainer from '../../containers/account_container';
|
||||
import Column from '../ui/components/column';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import { makeGetStatus } from '../../selectors';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.reblogs', defaultMessage: 'Reposts' },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const getStatus = makeGetStatus();
|
||||
const status = getStatus(state, {
|
||||
|
@ -27,9 +31,11 @@ const mapStateToProps = (state, props) => {
|
|||
};
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class Reblogs extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
params: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
accountIds: ImmutablePropTypes.orderedSet,
|
||||
|
@ -50,7 +56,7 @@ class Reblogs extends ImmutablePureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { accountIds, status } = this.props;
|
||||
const { intl, accountIds, status } = this.props;
|
||||
|
||||
if (!accountIds) {
|
||||
return (
|
||||
|
@ -71,7 +77,7 @@ class Reblogs extends ImmutablePureComponent {
|
|||
const emptyMessage = <FormattedMessage id='status.reblogs.empty' defaultMessage='No one has reposted this post yet. When someone does, they will show up here.' />;
|
||||
|
||||
return (
|
||||
<Column>
|
||||
<Column heading={intl.formatMessage(messages.heading)}>
|
||||
<ScrollableList
|
||||
scrollKey='reblogs'
|
||||
emptyMessage={emptyMessage}
|
||||
|
|
|
@ -3,8 +3,7 @@ import { connect } from 'react-redux';
|
|||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
import Column from '../../components/column';
|
||||
import HomeColumnHeader from '../../components/home_column_header';
|
||||
import Column from 'soapbox/features/ui/components/column';
|
||||
import PinnedHostsPicker from './components/pinned_hosts_picker';
|
||||
import IconButton from 'soapbox/components/icon_button';
|
||||
import { expandRemoteTimeline } from '../../actions/timelines';
|
||||
|
@ -82,11 +81,10 @@ class RemoteTimeline extends React.PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { intl, hasUnread, onlyMedia, timelineId, instance, pinned } = this.props;
|
||||
const { intl, onlyMedia, timelineId, instance, pinned } = this.props;
|
||||
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.title)} transparent>
|
||||
<HomeColumnHeader activeItem='fediverse' active={hasUnread} />
|
||||
<Column label={intl.formatMessage(messages.title)} heading={instance} transparent>
|
||||
<PinnedHostsPicker host={instance} />
|
||||
{!pinned && <div className='timeline-filter-message'>
|
||||
<IconButton icon='times' onClick={this.handleCloseClick} />
|
||||
|
|
|
@ -10,7 +10,7 @@ import { Link, NavLink } from 'react-router-dom';
|
|||
import { getDomain } from 'soapbox/utils/accounts';
|
||||
import Avatar from 'soapbox/components/avatar';
|
||||
import DisplayName from 'soapbox/components/display_name';
|
||||
import AttachmentList from 'soapbox/components/attachment_list';
|
||||
import AttachmentThumbs from 'soapbox/components/attachment_thumbs';
|
||||
import PollPreview from './poll_preview';
|
||||
import ScheduledStatusActionBar from './scheduled_status_action_bar';
|
||||
|
||||
|
@ -67,7 +67,7 @@ class ScheduledStatus extends ImmutablePureComponent {
|
|||
collapsable
|
||||
/>
|
||||
|
||||
<AttachmentList
|
||||
<AttachmentThumbs
|
||||
compact
|
||||
media={status.get('media_attachments')}
|
||||
/>
|
||||
|
|
|
@ -12,12 +12,8 @@ const messages = defineMessages({
|
|||
const Search = ({ intl }) => (
|
||||
<div className='column search-page'>
|
||||
<ColumnHeader icon='search' title={intl.formatMessage(messages.heading)} />
|
||||
<SearchContainer />
|
||||
<div className='drawer__pager'>
|
||||
<div className='drawer__inner darker'>
|
||||
<SearchResultsContainer />
|
||||
</div>
|
||||
</div>
|
||||
<SearchContainer autoSubmit />
|
||||
<SearchResultsContainer />
|
||||
</div>
|
||||
);
|
||||
|
||||
|
|
|
@ -14,11 +14,10 @@ import { getSoapboxConfig } from 'soapbox/actions/soapbox';
|
|||
|
||||
const mapStateToProps = state => {
|
||||
const instance = state.get('instance');
|
||||
const features = getFeatures(instance);
|
||||
|
||||
return {
|
||||
allowedEmoji: getSoapboxConfig(state).get('allowedEmoji'),
|
||||
reactionList: features.exposableReactions,
|
||||
features: getFeatures(instance),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -29,7 +28,7 @@ class StatusInteractionBar extends ImmutablePureComponent {
|
|||
status: ImmutablePropTypes.map,
|
||||
me: SoapboxPropTypes.me,
|
||||
allowedEmoji: ImmutablePropTypes.list,
|
||||
reactionList: PropTypes.bool,
|
||||
features: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
getNormalizedReacts = () => {
|
||||
|
@ -42,7 +41,7 @@ class StatusInteractionBar extends ImmutablePureComponent {
|
|||
).reverse();
|
||||
}
|
||||
|
||||
getRepost = () => {
|
||||
getReposts = () => {
|
||||
const { status } = this.props;
|
||||
if (status.get('reblogs_count')) {
|
||||
return (
|
||||
|
@ -58,8 +57,39 @@ class StatusInteractionBar extends ImmutablePureComponent {
|
|||
return '';
|
||||
}
|
||||
|
||||
getFavourites = () => {
|
||||
const { features, status } = this.props;
|
||||
|
||||
if (status.get('favourites_count')) {
|
||||
const favourites = (
|
||||
<>
|
||||
<Icon src={require('@tabler/icons/icons/thumb-up.svg')} />
|
||||
<span className='emoji-reacts__count'>
|
||||
<FormattedNumber value={status.get('favourites_count')} />
|
||||
</span>
|
||||
</>
|
||||
);
|
||||
|
||||
if (features.exposableReactions) {
|
||||
return (
|
||||
<Link to={`/@${status.getIn(['account', 'acct'])}/posts/${status.get('id')}/likes`} className='emoji-react emoji-react--favourites'>
|
||||
{favourites}
|
||||
</Link>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className='emoji-react emoji-react--favourites'>
|
||||
{favourites}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
getEmojiReacts = () => {
|
||||
const { status, reactionList } = this.props;
|
||||
const { status, features } = this.props;
|
||||
|
||||
const emojiReacts = this.getNormalizedReacts();
|
||||
const count = emojiReacts.reduce((acc, cur) => (
|
||||
|
@ -81,7 +111,7 @@ class StatusInteractionBar extends ImmutablePureComponent {
|
|||
</>
|
||||
);
|
||||
|
||||
if (reactionList) {
|
||||
if (features.exposableReactions) {
|
||||
return <Link to={`/@${status.getIn(['account', 'acct'])}/posts/${status.get('id')}/reactions/${e.get('name')}`} className='emoji-react' key={i}>{emojiReact}</Link>;
|
||||
}
|
||||
|
||||
|
@ -99,13 +129,12 @@ class StatusInteractionBar extends ImmutablePureComponent {
|
|||
};
|
||||
|
||||
render() {
|
||||
const emojiReacts = this.getEmojiReacts();
|
||||
const repost = this.getRepost();
|
||||
const { features } = this.props;
|
||||
|
||||
return (
|
||||
<div className='status-interaction-bar'>
|
||||
{emojiReacts}
|
||||
{repost}
|
||||
{features.emojiReacts ? this.getEmojiReacts() : this.getFavourites()}
|
||||
{this.getReposts()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -573,7 +573,7 @@ class Status extends ImmutablePureComponent {
|
|||
};
|
||||
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.detailedStatus)} showBackBtn={false}>
|
||||
<Column label={intl.formatMessage(messages.detailedStatus)} transparent>
|
||||
<SubNavigation message={intl.formatMessage(messages.title)} />
|
||||
{/*
|
||||
Eye icon to show/hide all CWs in a thread.
|
||||
|
|
|
@ -2,7 +2,6 @@ import React from 'react';
|
|||
import ColumnHeader from './column_header';
|
||||
import PropTypes from 'prop-types';
|
||||
import Column from 'soapbox/components/column';
|
||||
import ColumnBackButton from '../../../components/column_back_button_slim';
|
||||
import DropdownMenu from 'soapbox/containers/dropdown_menu_container';
|
||||
|
||||
// Yes, there are 3 types of columns at this point, but this one is better, I swear
|
||||
|
@ -29,7 +28,6 @@ export default class BetterColumn extends React.PureComponent {
|
|||
<DropdownMenu items={menu} icon='ellipsis-v' size={18} direction='right' />
|
||||
</div>
|
||||
)}
|
||||
<ColumnBackButton />
|
||||
</div>
|
||||
{children}
|
||||
</Column>
|
||||
|
|
|
@ -9,7 +9,7 @@ import RelativeTimestamp from '../../../components/relative_timestamp';
|
|||
import DisplayName from '../../../components/display_name';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
import AttachmentList from 'soapbox/components/attachment_list';
|
||||
import AttachmentThumbs from 'soapbox/components/attachment_thumbs';
|
||||
|
||||
const messages = defineMessages({
|
||||
cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Un-repost' },
|
||||
|
@ -88,7 +88,7 @@ class BoostModal extends ImmutablePureComponent {
|
|||
<StatusContent status={status} />
|
||||
|
||||
{status.get('media_attachments').size > 0 && (
|
||||
<AttachmentList
|
||||
<AttachmentThumbs
|
||||
compact
|
||||
media={status.get('media_attachments')}
|
||||
/>
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
import React from 'react';
|
||||
|
||||
const DrawerLoading = () => (
|
||||
<div className='drawer'>
|
||||
<div className='drawer__pager'>
|
||||
<div className='drawer__inner' />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default DrawerLoading;
|
|
@ -138,8 +138,17 @@ class MediaModal extends ImmutablePureComponent {
|
|||
const index = this.getIndex();
|
||||
let pagination = [];
|
||||
|
||||
const leftNav = media.size > 1 && <button tabIndex='0' className='media-modal__nav media-modal__nav--left' onClick={this.handlePrevClick} aria-label={intl.formatMessage(messages.previous)}><Icon id='chevron-left' fixedWidth /></button>;
|
||||
const rightNav = media.size > 1 && <button tabIndex='0' className='media-modal__nav media-modal__nav--right' onClick={this.handleNextClick} aria-label={intl.formatMessage(messages.next)}><Icon id='chevron-right' fixedWidth /></button>;
|
||||
const leftNav = media.size > 1 && (
|
||||
<button tabIndex='0' className='media-modal__nav media-modal__nav--left' onClick={this.handlePrevClick} aria-label={intl.formatMessage(messages.previous)}>
|
||||
<Icon src={require('@tabler/icons/icons/arrow-left.svg')} />
|
||||
</button>
|
||||
);
|
||||
|
||||
const rightNav = media.size > 1 && (
|
||||
<button tabIndex='0' className='media-modal__nav media-modal__nav--right' onClick={this.handleNextClick} aria-label={intl.formatMessage(messages.next)}>
|
||||
<Icon src={require('@tabler/icons/icons/arrow-right.svg')} />
|
||||
</button>
|
||||
);
|
||||
|
||||
if (media.size > 1) {
|
||||
pagination = media.map((item, i) => {
|
||||
|
|
|
@ -56,7 +56,7 @@ import {
|
|||
Following,
|
||||
Reblogs,
|
||||
Reactions,
|
||||
// Favourites,
|
||||
Favourites,
|
||||
DirectTimeline,
|
||||
Conversations,
|
||||
HashtagTimeline,
|
||||
|
@ -259,7 +259,7 @@ class SwitchingColumnsArea extends React.PureComponent {
|
|||
<Redirect from='/canary' to='/about/canary' />
|
||||
<Redirect from='/canary.txt' to='/about/canary' />
|
||||
|
||||
<WrappedRoute path='/tags/:id' publicRoute component={HashtagTimeline} content={children} />
|
||||
<WrappedRoute path='/tags/:id' publicRoute page={DefaultPage} component={HashtagTimeline} content={children} />
|
||||
|
||||
<WrappedRoute path='/lists' page={DefaultPage} component={Lists} content={children} />
|
||||
<WrappedRoute path='/list/:id' page={HomePage} component={ListTimeline} content={children} />
|
||||
|
@ -288,6 +288,7 @@ class SwitchingColumnsArea extends React.PureComponent {
|
|||
<WrappedRoute path='/@:username/pins' component={PinnedStatuses} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/posts/:statusId' publicRoute exact page={StatusPage} component={Status} content={children} />
|
||||
<WrappedRoute path='/@:username/posts/:statusId/reblogs' page={DefaultPage} component={Reblogs} content={children} />
|
||||
<WrappedRoute path='/@:username/posts/:statusId/likes' page={DefaultPage} component={Favourites} content={children} />
|
||||
<WrappedRoute path='/@:username/posts/:statusId/reactions/:reaction?' page={DefaultPage} component={Reactions} content={children} />
|
||||
<Redirect from='/@:username/:statusId' to='/@:username/posts/:statusId' />
|
||||
|
||||
|
|
|
@ -119,7 +119,7 @@
|
|||
"auth.invalid_credentials": "Nieprawidłowa nazwa użytkownika lub hasło",
|
||||
"auth.logged_out": "Wylogowano.",
|
||||
"backups.actions.create": "Utwórz kopię zapasową",
|
||||
"backups.empty_message": "Nie znaleziono kopii zapasaowych. {action}",
|
||||
"backups.empty_message": "Nie znaleziono kopii zapasowych. {action}",
|
||||
"backups.empty_message.action": "Chcesz utworzyć?",
|
||||
"backups.pending": "Oczekująca",
|
||||
"boost_modal.combo": "Naciśnij {combo}, aby pominąć to następnym razem",
|
||||
|
@ -525,12 +525,18 @@
|
|||
"morefollows.followers_label": "…i {count} więcej {count, plural, one {obserwujący(-a)} few {obserwujących} many {obserwujących} other {obserwujących}} na zdalnych stronach.",
|
||||
"morefollows.following_label": "…i {count} więcej {count, plural, one {obserwowany(-a)} few {obserwowanych} many {obserwowanych} other {obserwowanych}} na zdalnych stronach.",
|
||||
"mute_modal.hide_notifications": "Chcesz ukryć powiadomienia od tego użytkownika?",
|
||||
"navigation.chats": "Czaty",
|
||||
"navigation.direct_messages": "Wiadomości",
|
||||
"navigation.home": "Strona główna",
|
||||
"navigation.notifications": "Powiadomienia",
|
||||
"navigation.search": "Szukaj",
|
||||
"navigation_bar.account_aliases": "Aliasy kont",
|
||||
"navigation_bar.admin_settings": "Ustawienia administracyjne",
|
||||
"navigation_bar.blocks": "Zablokowani użytkownicy",
|
||||
"navigation_bar.bookmarks": "Zakładki",
|
||||
"navigation_bar.compose": "Utwórz nowy wpis",
|
||||
"navigation_bar.domain_blocks": "Ukryte domeny",
|
||||
"navigation_bar.export_data": "Eksportuj dane",
|
||||
"navigation_bar.favourites": "Ulubione",
|
||||
"navigation_bar.filters": "Wyciszone słowa",
|
||||
"navigation_bar.follow_requests": "Prośby o śledzenie",
|
||||
|
@ -809,10 +815,13 @@
|
|||
"status.unpin": "Odepnij z profilu",
|
||||
"status_list.queue_label": "Naciśnij aby zobaczyć {count} {count, plural, one {nowy wpis} few {nowe wpisy} many {nowych wpisów} other {nowe wpisy}}",
|
||||
"statuses.tombstone": "Jeden lub więcej z wpisów jest już niedostępny.",
|
||||
"sub_navigation.back": "Wróć",
|
||||
"suggestions.dismiss": "Odrzuć sugestię",
|
||||
"tabs_bar.all": "Wszystkie",
|
||||
"tabs_bar.apps": "Aplikacje",
|
||||
"tabs_bar.chats": "Rozmowy",
|
||||
"tabs_bar.dashboard": "Panel administracyjny",
|
||||
"tabs_bar.fediverse": "Fediwersum",
|
||||
"tabs_bar.header": "Informacje o koncie",
|
||||
"tabs_bar.home": "Strona główna",
|
||||
"tabs_bar.news": "Nowości",
|
||||
|
|
|
@ -17,10 +17,9 @@ import LinkFooter from '../features/ui/components/link_footer';
|
|||
import { getAcct } from 'soapbox/utils/accounts';
|
||||
import { displayFqn } from 'soapbox/utils/state';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
import { makeGetAccount } from '../selectors';
|
||||
import { Redirect } from 'react-router-dom';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { findAccountByUsername, makeGetAccount } from 'soapbox/selectors';
|
||||
|
||||
const mapStateToProps = (state, { params, withReplies = false }) => {
|
||||
const username = params.username || '';
|
||||
|
@ -34,7 +33,7 @@ const mapStateToProps = (state, { params, withReplies = false }) => {
|
|||
if (accountFetchError) {
|
||||
accountId = null;
|
||||
} else {
|
||||
account = accounts.find(acct => username.toLowerCase() === acct.getIn(['acct'], '').toLowerCase());
|
||||
account = findAccountByUsername(state, username);
|
||||
accountId = account ? account.getIn(['id'], null) : -1;
|
||||
accountUsername = account ? account.getIn(['acct'], '') : '';
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import Sticky from 'react-stickynode';
|
||||
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
|
||||
import PrimaryNavigation from 'soapbox/components/primary_navigation';
|
||||
import {
|
||||
PromoPanel,
|
||||
FeaturesPanel,
|
||||
|
@ -36,14 +38,9 @@ class RemoteInstancePage extends ImmutablePureComponent {
|
|||
|
||||
<div className='columns-area__panels__pane columns-area__panels__pane--left'>
|
||||
<div className='columns-area__panels__pane__inner'>
|
||||
<BundleContainer fetchComponent={InstanceInfoPanel}>
|
||||
{Component => <Component host={host} />}
|
||||
</BundleContainer>
|
||||
{(disclosed || isAdmin) && (
|
||||
<BundleContainer fetchComponent={InstanceModerationPanel}>
|
||||
{Component => <Component host={host} />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
<Sticky top={65}>
|
||||
<PrimaryNavigation />
|
||||
</Sticky>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -55,15 +52,25 @@ class RemoteInstancePage extends ImmutablePureComponent {
|
|||
|
||||
<div className='columns-area__panels__pane columns-area__panels__pane--right'>
|
||||
<div className='columns-area__panels__pane__inner'>
|
||||
{me && (
|
||||
<BundleContainer fetchComponent={FeaturesPanel}>
|
||||
{Component => <Component key='features-panel' />}
|
||||
<Sticky top={65}>
|
||||
{me && (
|
||||
<BundleContainer fetchComponent={FeaturesPanel}>
|
||||
{Component => <Component key='features-panel' />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
<BundleContainer fetchComponent={PromoPanel}>
|
||||
{Component => <Component key='promo-panel' />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
<BundleContainer fetchComponent={PromoPanel}>
|
||||
{Component => <Component key='promo-panel' />}
|
||||
</BundleContainer>
|
||||
<LinkFooter key='link-footer' />
|
||||
<BundleContainer fetchComponent={InstanceInfoPanel}>
|
||||
{Component => <Component host={host} />}
|
||||
</BundleContainer>
|
||||
{(disclosed || isAdmin) && (
|
||||
<BundleContainer fetchComponent={InstanceModerationPanel}>
|
||||
{Component => <Component host={host} />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
<LinkFooter key='link-footer' />
|
||||
</Sticky>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -47,6 +47,36 @@ export const makeGetAccount = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const findAccountsByUsername = (state, username) => {
|
||||
const accounts = state.get('accounts');
|
||||
|
||||
return accounts.filter(account => {
|
||||
return username.toLowerCase() === account.getIn(['acct'], '').toLowerCase();
|
||||
});
|
||||
};
|
||||
|
||||
export const findAccountByUsername = (state, username) => {
|
||||
const accounts = findAccountsByUsername(state, username);
|
||||
|
||||
if (accounts.size > 1) {
|
||||
const me = state.get('me');
|
||||
const meURL = state.getIn(['accounts', me, 'url']);
|
||||
|
||||
return accounts.find(account => {
|
||||
try {
|
||||
// If more than one account has the same username, try matching its host
|
||||
const { host } = new URL(account.get('url'));
|
||||
const { host: meHost } = new URL(meURL);
|
||||
return host === meHost;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return accounts.first();
|
||||
}
|
||||
};
|
||||
|
||||
const toServerSideType = columnType => {
|
||||
switch (columnType) {
|
||||
case 'home':
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
display: block;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);
|
||||
box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.3);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
|
||||
@media screen and (max-width: $no-gap-breakpoint) {
|
||||
box-shadow: none;
|
||||
|
@ -13,7 +15,7 @@
|
|||
&:active,
|
||||
&:focus {
|
||||
.card__bar {
|
||||
background: var(--foreground-color);
|
||||
background-color: var(--brand-color--faint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +24,6 @@
|
|||
height: 130px;
|
||||
position: relative;
|
||||
background: var(--background-color);
|
||||
border-radius: 4px 4px 0 0;
|
||||
|
||||
.still-image {
|
||||
display: block;
|
||||
|
@ -30,7 +31,6 @@
|
|||
height: 100%;
|
||||
margin: 0;
|
||||
object-fit: cover;
|
||||
border-radius: 4px 4px 0 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
|
@ -48,12 +48,8 @@
|
|||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
background: var(--brand-color--faint);
|
||||
border-radius: 0 0 4px 4px;
|
||||
|
||||
@media screen and (max-width: $no-gap-breakpoint) {
|
||||
border-radius: 0;
|
||||
}
|
||||
background: var(--background-color);
|
||||
transition: 0.2s;
|
||||
|
||||
.avatar {
|
||||
flex: 0 0 auto;
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
@import 'components/react-toggle';
|
||||
@import 'components/getting-started';
|
||||
@import 'components/promo-panel';
|
||||
@import 'components/drawer';
|
||||
@import 'components/still-image';
|
||||
@import 'components/timeline-queue-header';
|
||||
@import 'components/badge';
|
||||
|
|
|
@ -296,20 +296,22 @@
|
|||
position: relative;
|
||||
|
||||
.icon-button {
|
||||
color: var(--primary-text-color--faint);
|
||||
color: var(--primary-text-color);
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: calc(50% - 13px);
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: auto;
|
||||
height: auto;
|
||||
background: transparent !important;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.chat-box__send .icon-button {
|
||||
top: calc(50% - 9px);
|
||||
.svg-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
|
@ -332,7 +334,7 @@
|
|||
.ui--chatroom {
|
||||
padding-bottom: 0;
|
||||
|
||||
.columns-area__panels__main .columns-area {
|
||||
.columns-area__panels__main .columns-area .column {
|
||||
height: calc(100vh - 100px);
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
|
|
|
@ -313,9 +313,11 @@
|
|||
display: flex;
|
||||
font-size: 14px;
|
||||
color: var(--primary-text-color--faint);
|
||||
|
||||
@media screen and (max-width: 895px) {
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
display: none;
|
||||
}
|
||||
|
||||
a {
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 100%;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 631px) {
|
||||
|
@ -68,8 +69,7 @@
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
.column,
|
||||
.drawer {
|
||||
.column {
|
||||
flex: 0 0 auto;
|
||||
padding: 10px;
|
||||
padding-left: 5px;
|
||||
|
@ -85,8 +85,7 @@
|
|||
}
|
||||
|
||||
.columns-area > div {
|
||||
.column,
|
||||
.drawer {
|
||||
.column {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
@ -98,12 +97,10 @@
|
|||
flex-direction: column;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding: 15px 0;
|
||||
padding-top: 15px;
|
||||
|
||||
.column,
|
||||
.drawer {
|
||||
.column {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
@ -125,11 +122,9 @@
|
|||
}
|
||||
|
||||
@media (max-width: 580px) {
|
||||
padding: 0;
|
||||
|
||||
.timeline-compose-block {
|
||||
border-radius: 0;
|
||||
margin-top: 10px; // Make less claustrophobic
|
||||
margin-top: -5px;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,6 +347,10 @@
|
|||
background: transparent;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
|
||||
.sub-navigation {
|
||||
box-shadow: 0 -6px 6px -6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 580px) {
|
||||
|
@ -710,6 +709,7 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 160px;
|
||||
border-radius: 0 0 10px 10px;
|
||||
|
||||
@supports (display: grid) { // hack to fix Chrome <57
|
||||
contain: strict;
|
||||
|
@ -727,21 +727,20 @@
|
|||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 580px) {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.error-column {
|
||||
flex-direction: column;
|
||||
border-radius: 0 0 10px 10px;
|
||||
|
||||
.svg-icon {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 580px) {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.column-link--transparent .icon-with-badge__badge {
|
||||
|
@ -775,6 +774,11 @@
|
|||
.column__top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid hsla(var(--primary-text-color_hsl), 0.2);
|
||||
|
||||
.sub-navigation {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.column-header {
|
||||
|
@ -856,6 +860,10 @@
|
|||
|
||||
.column-list {
|
||||
position: relative;
|
||||
|
||||
&__empty-message {
|
||||
padding: 0 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.column-loading {
|
||||
|
@ -882,6 +890,10 @@
|
|||
.column--transparent {
|
||||
.slist__append {
|
||||
@include standard-panel;
|
||||
|
||||
@media screen and (max-width: 580px) {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.sub-navigation ~ .slist .slist__append {
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.compose-form__warning {
|
||||
&__warning {
|
||||
color: var(--primary-text-color);
|
||||
margin-bottom: 10px;
|
||||
background: var(--brand-color--faint);
|
||||
|
@ -66,7 +66,7 @@
|
|||
right: 5px;
|
||||
}
|
||||
|
||||
.compose-form__autosuggest-wrapper {
|
||||
&__autosuggest-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@
|
|||
color: var(--primary-text-color--faint);
|
||||
}
|
||||
|
||||
.compose-form__modifiers {
|
||||
&__modifiers {
|
||||
color: var(--primary-text-color);
|
||||
font-family: inherit;
|
||||
font-size: 14px;
|
||||
|
@ -327,7 +327,7 @@
|
|||
}
|
||||
} // end .compose-form .compose-form__modifiers
|
||||
|
||||
.compose-form__buttons-wrapper {
|
||||
&__buttons-wrapper {
|
||||
padding: 10px;
|
||||
background: var(--background-color);
|
||||
display: flex;
|
||||
|
@ -380,13 +380,23 @@
|
|||
}
|
||||
}
|
||||
|
||||
.character-counter__wrapper {
|
||||
align-self: center;
|
||||
margin: 0 10px 0 auto;
|
||||
.character-counter {
|
||||
display: block;
|
||||
cursor: default;
|
||||
font-family: var(--font-sans-serif), sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--primary-text-color--faint);
|
||||
&.character-counter--over { color: $warning-red; }
|
||||
}
|
||||
|
||||
.character-counter,
|
||||
.visual-character-counter {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.compose-form__publish {
|
||||
&__publish {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
min-width: 0;
|
||||
|
@ -396,6 +406,13 @@
|
|||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&__counter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-self: center;
|
||||
margin-left: auto;
|
||||
}
|
||||
} // end .compose-form
|
||||
|
||||
// Icon tweaks
|
||||
|
|
|
@ -71,7 +71,6 @@
|
|||
|
||||
.detailed-status__link {
|
||||
color: var(--primary-text-color--faint);
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
@ -159,8 +158,34 @@
|
|||
}
|
||||
|
||||
.thread {
|
||||
@include standard-panel;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
|
||||
@media screen and (max-width: 580px) {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
&__status {
|
||||
position: relative;
|
||||
|
||||
// Only display line if posts are below
|
||||
&:last-child .detailed-status__action-bar {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__descendants .thread__status:first-child {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
&__status--focused:first-child,
|
||||
&__ancestors &__status:first-child {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
&__descendants &__status:last-child {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
&__connector {
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
.drawer {
|
||||
width: 300px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.drawer__tab {
|
||||
display: block;
|
||||
flex: 1 1 auto;
|
||||
padding: 15px 5px 13px;
|
||||
color: var(--primary-text-color--faint);
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
border-bottom: 2px solid transparent;
|
||||
}
|
||||
|
||||
.column,
|
||||
.drawer {
|
||||
flex: 1 1 100%;
|
||||
}
|
||||
|
||||
.drawer__pager {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.drawer__inner {
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: var(--foreground-color);
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.pseudo-drawer {
|
||||
background: var(--background-color);
|
||||
font-size: 13px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.drawer__header {
|
||||
flex: 0 0 auto;
|
||||
font-size: 16px;
|
||||
background: var(--brand-color--med);
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
a {
|
||||
transition: background 100ms ease-in;
|
||||
|
||||
&:hover {
|
||||
background: var(--background-color);
|
||||
transition: background 200ms ease-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.drawer__backdrop {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba($base-overlay-background, 0.5);
|
||||
}
|
|
@ -21,12 +21,19 @@
|
|||
}
|
||||
}
|
||||
|
||||
.emoji-react--reblogs {
|
||||
.emoji-react--reblogs,
|
||||
.emoji-react--favourites {
|
||||
vertical-align: middle;
|
||||
display: inline-flex;
|
||||
margin-right: 10px;
|
||||
|
||||
.svg-icon {
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.emoji-react--reblogs {
|
||||
.svg-icon {
|
||||
color: var(--highlight-text-color);
|
||||
|
||||
svg {
|
||||
|
@ -35,6 +42,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
.emoji-react--favourites {
|
||||
.svg-icon {
|
||||
color: $gold-star;
|
||||
}
|
||||
}
|
||||
|
||||
.emoji-reacts {
|
||||
display: inline-flex;
|
||||
flex-direction: row-reverse;
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
|
||||
&__footer {
|
||||
flex: 0 0 auto;
|
||||
padding: 10px;
|
||||
padding-top: 20px;
|
||||
padding: 20px 10px 40px;
|
||||
|
||||
ul {
|
||||
margin-bottom: 10px;
|
||||
|
|
|
@ -14,16 +14,6 @@
|
|||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
.drawer__inner {
|
||||
border-radius: 0 0 8px 8px;
|
||||
|
||||
&.backdrop {
|
||||
width: calc(100% - 60px);
|
||||
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
|
||||
border-radius: 0 0 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&__accounts {
|
||||
background: var(--background-color);
|
||||
overflow-y: auto;
|
||||
|
|
|
@ -192,3 +192,33 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
$media-compact-size: 50px;
|
||||
|
||||
.media-gallery--compact {
|
||||
height: $media-compact-size !important;
|
||||
background: transparent;
|
||||
|
||||
.spoiler-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.media-gallery__item {
|
||||
width: $media-compact-size !important;
|
||||
height: $media-compact-size !important;
|
||||
inset: auto !important;
|
||||
margin-right: 5px;
|
||||
|
||||
&-overflow {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
&__icons {
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.media-gallery__file-extension__label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,8 +128,9 @@
|
|||
|
||||
@media screen and (max-width: 600px) { padding: 30px 2px; }
|
||||
|
||||
.fa {
|
||||
margin-right: 0;
|
||||
.svg-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,7 +181,7 @@
|
|||
}
|
||||
|
||||
.media-modal__button {
|
||||
background-color: var(--primary-text-color);
|
||||
background-color: #fff;
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
border-radius: 6px;
|
||||
|
@ -337,7 +338,7 @@
|
|||
overflow: hidden;
|
||||
width: 480px;
|
||||
max-width: 90vw;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid var(--primary-text-color--faint);
|
||||
color: var(--primary-text-color--faint);
|
||||
background: var(--foreground-color);
|
||||
|
|
|
@ -29,9 +29,11 @@
|
|||
}
|
||||
|
||||
.pinned-hosts-picker {
|
||||
margin-left: 10px;
|
||||
padding: 10px 0 0 10px;
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
background: var(--foreground-color);
|
||||
border-bottom: 1px solid hsla(var(--primary-text-color_hsl), 0.2);
|
||||
|
||||
.pinned-host {
|
||||
margin-right: 10px;
|
||||
|
|
|
@ -166,9 +166,7 @@
|
|||
}
|
||||
|
||||
.search-page {
|
||||
.drawer__inner:not(:empty) {
|
||||
min-height: 48px;
|
||||
}
|
||||
height: 100%;
|
||||
|
||||
.search {
|
||||
padding: 10px 15px;
|
||||
|
@ -184,14 +182,6 @@
|
|||
.search__icon .svg-icon {
|
||||
right: 24px;
|
||||
}
|
||||
|
||||
.drawer__pager {
|
||||
border-radius: 0 0 10px 10px;
|
||||
|
||||
@media screen and (max-width: 450px) {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-results {
|
||||
|
|
|
@ -143,6 +143,10 @@
|
|||
.status__prepend-icon-wrapper {
|
||||
left: -26px;
|
||||
position: absolute;
|
||||
|
||||
svg.feather-repeat {
|
||||
color: var(--highlight-text-color);
|
||||
}
|
||||
}
|
||||
|
||||
.status {
|
||||
|
@ -710,3 +714,18 @@ a.status-card.compact:hover {
|
|||
padding: 15px 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.attachment-thumbs {
|
||||
position: relative;
|
||||
|
||||
&__clickable-region {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,35 +1,35 @@
|
|||
.timeline-queue-header {
|
||||
display: flex;
|
||||
align-self: center;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
max-height: 30px;
|
||||
position: sticky;
|
||||
height: 30px;
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 8px;
|
||||
background-color: var(--brand-color);
|
||||
color: #fff;
|
||||
border-bottom: 1px solid;
|
||||
border-top: 1px solid;
|
||||
border-color: var(--brand-color--faint);
|
||||
border-radius: 100px;
|
||||
transition: max-height 150ms ease;
|
||||
transition: 150ms ease;
|
||||
overflow: hidden;
|
||||
opacity: 1;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 0 10px;
|
||||
z-index: 500;
|
||||
|
||||
.sub-navigation ~ & {
|
||||
top: calc(60px + 41px);
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
&.hidden {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
transform: scaleY(0);
|
||||
pointer-events: none;
|
||||
|
||||
.timeline-queue-header__label {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__btn {
|
||||
|
@ -46,4 +46,8 @@
|
|||
height: 46px;
|
||||
}
|
||||
}
|
||||
|
||||
&__label {
|
||||
transition: 150ms ease;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -297,7 +297,7 @@
|
|||
left: 0;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
background: var(--brand-color);
|
||||
background: var(--accent-color);
|
||||
}
|
||||
|
||||
&__handle {
|
||||
|
@ -310,7 +310,7 @@
|
|||
left: 0;
|
||||
margin-left: -6px;
|
||||
transform: translate(0, -50%);
|
||||
background: var(--brand-color);
|
||||
background: var(--accent-color);
|
||||
box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);
|
||||
opacity: 0;
|
||||
|
||||
|
@ -364,7 +364,7 @@
|
|||
height: 4px;
|
||||
border-radius: 4px;
|
||||
top: 14px;
|
||||
background: var(--brand-color);
|
||||
background: var(--accent-color);
|
||||
}
|
||||
|
||||
&__buffer {
|
||||
|
@ -380,7 +380,7 @@
|
|||
height: 12px;
|
||||
top: 10px;
|
||||
margin-left: -6px;
|
||||
background: var(--brand-color);
|
||||
background: var(--accent-color);
|
||||
box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);
|
||||
|
||||
.no-reduce-motion & {
|
||||
|
|
|
@ -113,6 +113,10 @@
|
|||
justify-content: center;
|
||||
z-index: 999;
|
||||
|
||||
&--scrolled {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
&__content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
|
|
@ -228,8 +228,7 @@ body.rtl {
|
|||
}
|
||||
|
||||
@media screen and (min-width: 631px) {
|
||||
.column,
|
||||
.drawer {
|
||||
.column {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
|
||||
|
@ -240,8 +239,7 @@ body.rtl {
|
|||
}
|
||||
|
||||
.columns-area > div {
|
||||
.column,
|
||||
.drawer {
|
||||
.column {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
|
|
@ -318,7 +318,6 @@
|
|||
.react-swipeable-view-container {
|
||||
&,
|
||||
.columns-area,
|
||||
.drawer,
|
||||
.column {
|
||||
height: 100%;
|
||||
}
|
||||
|
|
|
@ -116,6 +116,7 @@
|
|||
"qrcode.react": "^1.0.0",
|
||||
"react": "^16.13.1",
|
||||
"react-color": "^2.18.1",
|
||||
"react-content-loader": "^6.0.3",
|
||||
"react-datepicker": "^4.1.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-helmet": "^6.0.0",
|
||||
|
|
|
@ -7757,6 +7757,11 @@ react-color@^2.18.1:
|
|||
reactcss "^1.2.0"
|
||||
tinycolor2 "^1.4.1"
|
||||
|
||||
react-content-loader@^6.0.3:
|
||||
version "6.0.3"
|
||||
resolved "https://registry.yarnpkg.com/react-content-loader/-/react-content-loader-6.0.3.tgz#32e28ca7120e0a2552fc26655d0d4448cc1fc0c5"
|
||||
integrity sha512-CIRgTHze+ls+jGDIfCitw27YkW2XcaMpsYORTUdBxsMFiKuUYMnlvY76dZE4Lsaa9vFXVw+41ieBEK7SJt0nug==
|
||||
|
||||
react-datepicker@^4.1.1:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.2.1.tgz#72caf5055bc7c4eb0279c1f6d7624ded053edc4c"
|
||||
|
|
Loading…
Reference in New Issue