Merge branch 'develop' of https://code.gab.com/gab/social/gab-social into develop

This commit is contained in:
Rob Colbert 2019-07-21 22:56:50 -04:00
commit daee22dcbb
25 changed files with 320 additions and 127 deletions

View File

@ -1,20 +1,39 @@
'use strict'; 'use strict';
import React from 'react'; import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import classNames from 'classnames'; import classNames from 'classnames';
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl'; import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import Icon from 'gabsocial/components/icon'; import Icon from 'gabsocial/components/icon';
import { me } from 'gabsocial/initial_state';
import { fetchLists } from 'gabsocial/actions/lists';
import { createSelector } from 'reselect';
const messages = defineMessages({ const messages = defineMessages({
show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' }, show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
hide: { id: 'column_header.hide_settings', defaultMessage: 'Hide settings' }, hide: { id: 'column_header.hide_settings', defaultMessage: 'Hide settings' },
homeTitle: { id: 'home_column_header.home', defaultMessage: 'Home' }, homeTitle: { id: 'home_column_header.home', defaultMessage: 'Home' },
allTitle: { id: 'home_column_header.all', defaultMessage: 'All' }, allTitle: { id: 'home_column_header.all', defaultMessage: 'All' },
listTitle: { id: 'home_column.lists', defaultMessage: 'Lists' },
}); });
export default @injectIntl 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 => {
return {
lists: getOrderedLists(state),
};
};
class ColumnHeader extends React.PureComponent { class ColumnHeader extends React.PureComponent {
static contextTypes = { static contextTypes = {
@ -23,16 +42,24 @@ class ColumnHeader extends React.PureComponent {
static propTypes = { static propTypes = {
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
active: PropTypes.bool, active: PropTypes.bool,
children: PropTypes.node, children: PropTypes.node,
activeItem: PropTypes.string, activeItem: PropTypes.string,
activeSubItem: PropTypes.string,
lists: ImmutablePropTypes.list,
}; };
state = { state = {
collapsed: true, collapsed: true,
animating: false, animating: false,
expandedFor: null, //lists, groups, etc.
}; };
componentDidMount() {
this.props.dispatch(fetchLists());
}
handleToggleClick = (e) => { handleToggleClick = (e) => {
e.stopPropagation(); e.stopPropagation();
this.setState({ collapsed: !this.state.collapsed, animating: true }); this.setState({ collapsed: !this.state.collapsed, animating: true });
@ -42,9 +69,15 @@ class ColumnHeader extends React.PureComponent {
this.setState({ animating: false }); this.setState({ animating: false });
} }
expandLists = () => {
this.setState({
expandedFor: 'lists',
});
}
render () { render () {
const { active, children, intl: { formatMessage }, activeItem } = this.props; const { active, children, intl: { formatMessage }, activeItem, activeSubItem, lists } = this.props;
const { collapsed, animating } = this.state; const { collapsed, animating, expandedFor } = this.state;
const wrapperClassName = classNames('column-header__wrapper', { const wrapperClassName = classNames('column-header__wrapper', {
'active': active, 'active': active,
@ -63,6 +96,10 @@ class ColumnHeader extends React.PureComponent {
'active': !collapsed, 'active': !collapsed,
}); });
const expansionClassName = classNames('column-header column-header__expansion', {
'open': expandedFor,
});
let extraContent, collapseButton; let extraContent, collapseButton;
if (children) { if (children) {
@ -79,6 +116,23 @@ class ColumnHeader extends React.PureComponent {
extraContent, 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 ( return (
<div className={wrapperClassName}> <div className={wrapperClassName}>
<h1 className={buttonClassName}> <h1 className={buttonClassName}>
@ -92,11 +146,31 @@ class ColumnHeader extends React.PureComponent {
{formatMessage(messages.allTitle)} {formatMessage(messages.allTitle)}
</Link> </Link>
{ lists.size > 0 &&
<a onClick={this.expandLists} className={classNames('btn grouped', {'active': 'lists' === activeItem})}>
<Icon id='list' fixedWidth className='column-header__icon' />
{formatMessage(messages.listTitle)}
</a>
}
{ lists.size == 0 &&
<Link to='/lists' className='btn grouped'>
<Icon id='list' fixedWidth className='column-header__icon' />
{formatMessage(messages.listTitle)}
</Link>
}
<div className='column-header__buttons'> <div className='column-header__buttons'>
{collapseButton} {collapseButton}
</div> </div>
</h1> </h1>
{
expandedContent &&
<h1 className={expansionClassName}>
{expandedContent}
</h1>
}
<div className={collapsibleClassName} tabIndex={collapsed ? -1 : null} onTransitionEnd={this.handleTransitionEnd}> <div className={collapsibleClassName} tabIndex={collapsed ? -1 : null} onTransitionEnd={this.handleTransitionEnd}>
<div className='column-header__collapsible-inner'> <div className='column-header__collapsible-inner'>
{(!collapsed || animating) && collapsedContent} {(!collapsed || animating) && collapsedContent}
@ -105,5 +179,6 @@ class ColumnHeader extends React.PureComponent {
</div> </div>
); );
} }
} }
export default injectIntl(connect(mapStateToProps)(ColumnHeader));

View File

@ -82,7 +82,7 @@ export default class ScrollableList extends PureComponent {
componentDidMount () { componentDidMount () {
this.window = window; this.window = window;
this.documentElement = document.documentElement; this.documentElement = document.scrollingElement || document.documentElement;
this.attachScrollListener(); this.attachScrollListener();
this.attachIntersectionObserver(); this.attachIntersectionObserver();
@ -124,10 +124,11 @@ export default class ScrollableList extends PureComponent {
handleScroll = throttle(() => { handleScroll = throttle(() => {
if (this.window) { if (this.window) {
const { scrollTop, scrollHeight, clientHeight } = this.documentElement; const { scrollTop, scrollHeight } = this.documentElement;
const offset = scrollHeight - scrollTop - clientHeight; const { innerHeight } = this.window;
const offset = scrollHeight - scrollTop - innerHeight;
if (600 > offset && this.props.onLoadMore && this.props.hasMore && !this.props.isLoading) { if (400 > offset && this.props.onLoadMore && this.props.hasMore && !this.props.isLoading) {
this.props.onLoadMore(); this.props.onLoadMore();
} }
@ -174,6 +175,7 @@ export default class ScrollableList extends PureComponent {
componentWillUnmount () { componentWillUnmount () {
this.clearMouseIdleTimer(); this.clearMouseIdleTimer();
this.detachScrollListener();
this.detachIntersectionObserver(); this.detachIntersectionObserver();
} }

View File

@ -43,6 +43,7 @@ const messages = defineMessages({
endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' }, endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' },
unendorse: { id: 'account.unendorse', defaultMessage: 'Don\'t feature on profile' }, unendorse: { id: 'account.unendorse', defaultMessage: 'Don\'t feature on profile' },
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' }, admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
add_or_remove_from_list: { id: 'account.add_or_remove_from_list', defaultMessage: 'Add or Remove from lists' },
}); });
const dateFormatOptions = { const dateFormatOptions = {
@ -128,6 +129,7 @@ class Header extends ImmutablePureComponent {
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.onReblogToggle });
} }
menu.push({ text: intl.formatMessage(messages.add_or_remove_from_list), action: this.props.onAddToList });
menu.push({ text: intl.formatMessage(account.getIn(['relationship', 'endorsed']) ? messages.unendorse : messages.endorse), action: this.props.onEndorseToggle }); menu.push({ text: intl.formatMessage(account.getIn(['relationship', 'endorsed']) ? messages.unendorse : messages.endorse), action: this.props.onEndorseToggle });
menu.push(null); menu.push(null);
} }

View File

@ -7,7 +7,6 @@ import { debounce } from 'lodash';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import LoadingIndicator from '../../components/loading_indicator'; import LoadingIndicator from '../../components/loading_indicator';
import Column from '../ui/components/column'; import Column from '../ui/components/column';
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
import AccountContainer from '../../containers/account_container'; import AccountContainer from '../../containers/account_container';
import { fetchBlocks, expandBlocks } from '../../actions/blocks'; import { fetchBlocks, expandBlocks } from '../../actions/blocks';
import ScrollableList from '../../components/scrollable_list'; import ScrollableList from '../../components/scrollable_list';
@ -55,8 +54,7 @@ class Blocks extends ImmutablePureComponent {
const emptyMessage = <FormattedMessage id='empty_column.blocks' defaultMessage="You haven't blocked any users yet." />; const emptyMessage = <FormattedMessage id='empty_column.blocks' defaultMessage="You haven't blocked any users yet." />;
return ( return (
<Column icon='ban' heading={intl.formatMessage(messages.heading)}> <Column icon='ban' heading={intl.formatMessage(messages.heading)} backBtnSlim>
<ColumnBackButtonSlim />
<ScrollableList <ScrollableList
scrollKey='blocks' scrollKey='blocks'
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}

View File

@ -7,7 +7,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import LoadingIndicator from '../../components/loading_indicator'; import LoadingIndicator from '../../components/loading_indicator';
import Column from '../ui/components/column'; import Column from '../ui/components/column';
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
import DomainContainer from '../../containers/domain_container'; import DomainContainer from '../../containers/domain_container';
import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks'; import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks';
import ScrollableList from '../../components/scrollable_list'; import ScrollableList from '../../components/scrollable_list';
@ -56,8 +55,7 @@ class Blocks extends ImmutablePureComponent {
const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no hidden domains yet.' />; const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no hidden domains yet.' />;
return ( return (
<Column icon='minus-circle' heading={intl.formatMessage(messages.heading)}> <Column icon='minus-circle' heading={intl.formatMessage(messages.heading)} backBtnSlim>
<ColumnBackButtonSlim />
<ScrollableList <ScrollableList
scrollKey='domain_blocks' scrollKey='domain_blocks'
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}

View File

@ -8,7 +8,6 @@ import { fetchFavourites } from '../../actions/interactions';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import AccountContainer from '../../containers/account_container'; import AccountContainer from '../../containers/account_container';
import Column from '../ui/components/column'; import Column from '../ui/components/column';
import ColumnBackButton from '../../components/column_back_button';
import ScrollableList from '../../components/scrollable_list'; import ScrollableList from '../../components/scrollable_list';
const mapStateToProps = (state, props) => ({ const mapStateToProps = (state, props) => ({
@ -49,8 +48,6 @@ class Favourites extends ImmutablePureComponent {
return ( return (
<Column> <Column>
<ColumnBackButton />
<ScrollableList <ScrollableList
scrollKey='favourites' scrollKey='favourites'
emptyMessage={emptyMessage} emptyMessage={emptyMessage}

View File

@ -7,7 +7,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import LoadingIndicator from '../../components/loading_indicator'; import LoadingIndicator from '../../components/loading_indicator';
import Column from '../ui/components/column'; import Column from '../ui/components/column';
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
import AccountAuthorizeContainer from './containers/account_authorize_container'; import AccountAuthorizeContainer from './containers/account_authorize_container';
import { fetchFollowRequests, expandFollowRequests } from '../../actions/accounts'; import { fetchFollowRequests, expandFollowRequests } from '../../actions/accounts';
import ScrollableList from '../../components/scrollable_list'; import ScrollableList from '../../components/scrollable_list';
@ -55,8 +54,7 @@ class FollowRequests extends ImmutablePureComponent {
const emptyMessage = <FormattedMessage id='empty_column.follow_requests' defaultMessage="You don't have any follow requests yet. When you receive one, it will show up here." />; const emptyMessage = <FormattedMessage id='empty_column.follow_requests' defaultMessage="You don't have any follow requests yet. When you receive one, it will show up here." />;
return ( return (
<Column icon='user-plus' heading={intl.formatMessage(messages.heading)}> <Column icon='user-plus' heading={intl.formatMessage(messages.heading)} backBtnSlim>
<ColumnBackButtonSlim />
<ScrollableList <ScrollableList
scrollKey='follow_requests' scrollKey='follow_requests'
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}

View File

@ -104,9 +104,11 @@ class Following extends ImmutablePureComponent {
if (unavailable) { if (unavailable) {
return ( return (
<Column>
<div className='empty-column-indicator'> <div className='empty-column-indicator'>
<FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' /> <FormattedMessage id='empty_column.account_unavailable' defaultMessage='Profile unavailable' />
</div> </div>
</Column>
); );
} }

View File

@ -4,7 +4,6 @@ import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import LoadingIndicator from '../../../components/loading_indicator'; import LoadingIndicator from '../../../components/loading_indicator';
import Column from '../../ui/components/column'; import Column from '../../ui/components/column';
import ColumnBackButtonSlim from '../../../components/column_back_button_slim';
import { fetchGroups } from '../../../actions/groups'; import { fetchGroups } from '../../../actions/groups';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
@ -60,9 +59,7 @@ class Groups extends ImmutablePureComponent {
const emptyMessage = <FormattedMessage id='empty_column.groups' defaultMessage="No groups." />; const emptyMessage = <FormattedMessage id='empty_column.groups' defaultMessage="No groups." />;
return ( return (
<Column icon='list-ul' heading={intl.formatMessage(messages.heading)}> <Column icon='list-ul' heading={intl.formatMessage(messages.heading)} backBtnSlim>
<ColumnBackButtonSlim />
<NewGroupForm /> <NewGroupForm />
<ColumnSubheading text={intl.formatMessage(messages.subheading)} /> <ColumnSubheading text={intl.formatMessage(messages.subheading)} />

View File

@ -4,7 +4,6 @@ import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import StatusListContainer from '../../ui/containers/status_list_container'; import StatusListContainer from '../../ui/containers/status_list_container';
import Column from '../../../components/column'; import Column from '../../../components/column';
import ColumnBackButton from '../../../components/column_back_button';
import ColumnHeader from '../../../components/column_header'; import ColumnHeader from '../../../components/column_header';
import { FormattedMessage, injectIntl } from 'react-intl'; import { FormattedMessage, injectIntl } from 'react-intl';
import { connectGroupStream } from '../../../actions/streaming'; import { connectGroupStream } from '../../../actions/streaming';
@ -73,7 +72,6 @@ class GroupTimeline extends React.PureComponent {
} else if (group === false) { } else if (group === false) {
return ( return (
<Column> <Column>
<ColumnBackButton />
<MissingIndicator /> <MissingIndicator />
</Column> </Column>
); );

View File

@ -8,6 +8,7 @@ import { expandHashtagTimeline, clearTimeline } from '../../actions/timelines';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { connectHashtagStream } from '../../actions/streaming'; import { connectHashtagStream } from '../../actions/streaming';
import { isEqual } from 'lodash'; import { isEqual } from 'lodash';
import ColumnBackButton from '../../components/column_back_button';
const mapStateToProps = (state, props) => ({ const mapStateToProps = (state, props) => ({
hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}`, 'unread']) > 0, hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}`, 'unread']) > 0,
@ -107,6 +108,7 @@ class HashtagTimeline extends React.PureComponent {
return ( return (
<Column label={`#${id}`}> <Column label={`#${id}`}>
<ColumnBackButton />
<ColumnHeader icon='hashtag' active={hasUnread} title={this.title()} /> <ColumnHeader icon='hashtag' active={hasUnread} title={this.title()} />
<StatusListContainer <StatusListContainer
scrollKey='hashtag_timeline' scrollKey='hashtag_timeline'

View File

@ -70,10 +70,7 @@ class HomeTimeline extends React.PureComponent {
return ( return (
<Column label={intl.formatMessage(messages.title)}> <Column label={intl.formatMessage(messages.title)}>
<HomeColumnHeader <HomeColumnHeader activeItem='home' active={hasUnread}>
activeItem='home'
active={hasUnread}
>
<ColumnSettingsContainer /> <ColumnSettingsContainer />
</HomeColumnHeader> </HomeColumnHeader>
<StatusListContainer <StatusListContainer

View File

@ -3,12 +3,14 @@ import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
import { injectIntl } from 'react-intl'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { setupListAdder, resetListAdder } from '../../actions/lists'; import { setupListAdder, resetListAdder } from '../../actions/lists';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import List from './components/list'; import List from './components/list';
import Account from './components/account'; import Account from './components/account';
import IconButton from 'gabsocial/components/icon_button';
import NewListForm from '../lists/components/new_list_form'; import NewListForm from '../lists/components/new_list_form';
import ColumnSubheading from '../ui/components/column_subheading';
// hack // hack
const getOrderedLists = createSelector([state => state.get('lists')], lists => { const getOrderedLists = createSelector([state => state.get('lists')], lists => {
@ -19,8 +21,9 @@ const getOrderedLists = createSelector([state => state.get('lists')], lists => {
return lists.toList().filter(item => !!item).sort((a, b) => a.get('title').localeCompare(b.get('title'))); return lists.toList().filter(item => !!item).sort((a, b) => a.get('title').localeCompare(b.get('title')));
}); });
const mapStateToProps = state => ({ const mapStateToProps = (state, {accountId}) => ({
listIds: getOrderedLists(state).map(list=>list.get('id')), listIds: getOrderedLists(state).map(list=>list.get('id')),
account: state.getIn(['accounts', accountId]),
}); });
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({
@ -28,6 +31,12 @@ const mapDispatchToProps = dispatch => ({
onReset: () => dispatch(resetListAdder()), onReset: () => dispatch(resetListAdder()),
}); });
const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' },
subheading: { id: 'lists.subheading', defaultMessage: 'Your lists' },
add: { id: 'lists.new.create', defaultMessage: 'Add List' },
});
export default @connect(mapStateToProps, mapDispatchToProps) export default @connect(mapStateToProps, mapDispatchToProps)
@injectIntl @injectIntl
class ListAdder extends ImmutablePureComponent { class ListAdder extends ImmutablePureComponent {
@ -39,6 +48,7 @@ class ListAdder extends ImmutablePureComponent {
onInitialize: PropTypes.func.isRequired, onInitialize: PropTypes.func.isRequired,
onReset: PropTypes.func.isRequired, onReset: PropTypes.func.isRequired,
listIds: ImmutablePropTypes.list.isRequired, listIds: ImmutablePropTypes.list.isRequired,
account: ImmutablePropTypes.map,
}; };
componentDidMount () { componentDidMount () {
@ -51,22 +61,43 @@ class ListAdder extends ImmutablePureComponent {
onReset(); onReset();
} }
onClickClose = () => {
this.props.onClose('LIST_ADDER');
};
render () { render () {
const { accountId, listIds } = this.props; const { accountId, listIds, intl, onClose, account } = this.props;
const displayNameHtml = account ? { __html: account.get('display_name_html') } : '';
return ( return (
<div className='modal-root__modal list-adder'> <div className='modal-root__modal compose-modal'>
<div className='compose-modal__header'>
<h3 className='compose-modal__header__title'>
<FormattedMessage id='list_adder.header_title' defaultMessage='Add or Remove from Lists' />
</h3>
<IconButton className='compose-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={this.onClickClose} size={20} />
</div>
<div className='compose-modal__content'>
<div className='list-adder'>
<div className='list-adder__account'> <div className='list-adder__account'>
<Account accountId={accountId} /> <Account accountId={accountId} />
</div> </div>
<br/>
<ColumnSubheading text={intl.formatMessage(messages.add)} />
<NewListForm /> <NewListForm />
<br/>
<ColumnSubheading text={intl.formatMessage(messages.subheading)} />
<div className='list-adder__lists'> <div className='list-adder__lists'>
{listIds.map(ListId => <List key={ListId} listId={ListId} />)} {listIds.map(ListId => <List key={ListId} listId={ListId} />)}
</div> </div>
</div> </div>
</div>
</div>
); );
} }

View File

@ -2,11 +2,12 @@ import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { changeListEditorTitle, submitListEditor } from '../../../actions/lists'; import { changeListEditorTitle, submitListEditor } from '../../../actions/lists';
import IconButton from '../../../components/icon_button'; import Button from '../../../components/button';
import { defineMessages, injectIntl } from 'react-intl'; import { defineMessages, injectIntl } from 'react-intl';
const messages = defineMessages({ const messages = defineMessages({
title: { id: 'lists.edit.submit', defaultMessage: 'Change title' }, title: { id: 'lists.edit.submit', defaultMessage: 'Change title' },
save: { id: 'lists.new.save_title', defaultMessage: 'Save Title' },
}); });
const mapStateToProps = state => ({ const mapStateToProps = state => ({
@ -48,21 +49,24 @@ class ListForm extends React.PureComponent {
const { value, disabled, intl } = this.props; const { value, disabled, intl } = this.props;
const title = intl.formatMessage(messages.title); const title = intl.formatMessage(messages.title);
const save = intl.formatMessage(messages.save);
return ( return (
<form className='column-inline-form' onSubmit={this.handleSubmit}> <form className='column-inline-form' onSubmit={this.handleSubmit}>
<input <input
className='setting-text' className='setting-text new-list-form__input'
value={value} value={value}
onChange={this.handleChange} onChange={this.handleChange}
/> />
<IconButton { !disabled &&
disabled={disabled} <Button
icon='check' className='new-list-form__btn'
title={title}
onClick={this.handleClick} onClick={this.handleClick}
/> >
{save}
</Button>
}
</form> </form>
); );
} }

View File

@ -5,9 +5,11 @@ import { defineMessages, injectIntl } from 'react-intl';
import { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from '../../../actions/lists'; import { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from '../../../actions/lists';
import classNames from 'classnames'; import classNames from 'classnames';
import Icon from 'gabsocial/components/icon'; import Icon from 'gabsocial/components/icon';
import Button from 'gabsocial/components/button';
const messages = defineMessages({ const messages = defineMessages({
search: { id: 'lists.search', defaultMessage: 'Search among people you follow' }, search: { id: 'lists.search', defaultMessage: 'Search among people you follow' },
searchTitle: { id: 'tabs_bar.search', defaultMessage: 'Search' },
}); });
const mapStateToProps = state => ({ const mapStateToProps = state => ({
@ -42,6 +44,10 @@ class Search extends React.PureComponent {
} }
} }
handleSubmit = () => {
this.props.onSubmit(this.props.value);
}
handleClear = () => { handleClear = () => {
this.props.onClear(); this.props.onClear();
} }
@ -69,6 +75,7 @@ class Search extends React.PureComponent {
<Icon id='search' className={classNames({ active: !hasValue })} /> <Icon id='search' className={classNames({ active: !hasValue })} />
<Icon id='times-circle' aria-label={intl.formatMessage(messages.search)} className={classNames({ active: hasValue })} /> <Icon id='times-circle' aria-label={intl.formatMessage(messages.search)} className={classNames({ active: hasValue })} />
</div> </div>
<Button onClick={this.handleSubmit}>{intl.formatMessage(messages.searchTitle)}</Button>
</div> </div>
); );
} }

View File

@ -3,13 +3,13 @@ import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
import { injectIntl } from 'react-intl'; import { injectIntl, defineMessages } from 'react-intl';
import { setupListEditor, clearListSuggestions, resetListEditor } from '../../actions/lists'; import { setupListEditor, clearListSuggestions, resetListEditor } from '../../actions/lists';
import Account from './components/account'; import Account from './components/account';
import Search from './components/search'; import Search from './components/search';
import EditListForm from './components/edit_list_form'; import EditListForm from './components/edit_list_form';
import Motion from '../ui/util/optional_motion'; import ColumnSubheading from '../ui/components/column_subheading';
import spring from 'react-motion/lib/spring'; import IconButton from 'gabsocial/components/icon_button';
const mapStateToProps = state => ({ const mapStateToProps = state => ({
accountIds: state.getIn(['listEditor', 'accounts', 'items']), accountIds: state.getIn(['listEditor', 'accounts', 'items']),
@ -22,6 +22,14 @@ const mapDispatchToProps = dispatch => ({
onReset: () => dispatch(resetListEditor()), onReset: () => dispatch(resetListEditor()),
}); });
const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' },
changeTitle: { id: 'lists.edit.submit', defaultMessage: 'Change title' },
addToList: { id: 'lists.account.add', defaultMessage: 'Add to list' },
removeFromList: { id: 'lists.account.remove', defaultMessage: 'Remove from list' },
editList: { id: 'lists.edit', defaultMessage: 'Edit list' },
});
export default @connect(mapStateToProps, mapDispatchToProps) export default @connect(mapStateToProps, mapDispatchToProps)
@injectIntl @injectIntl
class ListEditor extends ImmutablePureComponent { class ListEditor extends ImmutablePureComponent {
@ -47,30 +55,45 @@ class ListEditor extends ImmutablePureComponent {
onReset(); onReset();
} }
onClickClose = () => {
this.props.onClose('LIST_ADDER');
};
render () { render () {
const { accountIds, searchAccountIds, onClear } = this.props; const { accountIds, searchAccountIds, onClear, intl } = this.props;
const showSearch = searchAccountIds.size > 0; const showSearch = searchAccountIds.size > 0;
return ( return (
<div className='modal-root__modal list-editor'> <div className='modal-root__modal compose-modal'>
<div className='compose-modal__header'>
<h3 className='compose-modal__header__title'>
{intl.formatMessage(messages.editList)}
</h3>
<IconButton className='compose-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={this.onClickClose} size={20} />
</div>
<div className='compose-modal__content'>
<div className='list-editor'>
<ColumnSubheading text={intl.formatMessage(messages.changeTitle)} />
<EditListForm /> <EditListForm />
<br/>
<Search /> {
accountIds.size > 0 &&
<div className='drawer__pager'> <div>
<div className='drawer__inner list-editor__accounts'> <ColumnSubheading text={intl.formatMessage(messages.removeFromList)} />
<div className='list-editor__accounts'>
{accountIds.map(accountId => <Account key={accountId} accountId={accountId} added />)} {accountIds.map(accountId => <Account key={accountId} accountId={accountId} added />)}
</div> </div>
</div>
}
{showSearch && <div role='button' tabIndex='-1' className='drawer__backdrop' onClick={onClear} />} <br/>
<ColumnSubheading text={intl.formatMessage(messages.addToList)} />
<Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}> <Search />
{({ x }) => ( <div className='list-editor__accounts'>
<div className='drawer__inner backdrop' style={{ transform: x === 0 ? null : `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}>
{searchAccountIds.map(accountId => <Account key={accountId} accountId={accountId} />)} {searchAccountIds.map(accountId => <Account key={accountId} accountId={accountId} />)}
</div> </div>
)} </div>
</Motion>
</div> </div>
</div> </div>
); );

View File

@ -4,8 +4,6 @@ import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import StatusListContainer from '../ui/containers/status_list_container'; import StatusListContainer from '../ui/containers/status_list_container';
import Column from '../../components/column'; import Column from '../../components/column';
import ColumnBackButton from '../../components/column_back_button';
import ColumnHeader from '../../components/column_header';
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl'; import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
import { connectListStream } from '../../actions/streaming'; import { connectListStream } from '../../actions/streaming';
import { expandListTimeline } from '../../actions/timelines'; import { expandListTimeline } from '../../actions/timelines';
@ -14,6 +12,9 @@ import { openModal } from '../../actions/modal';
import MissingIndicator from '../../components/missing_indicator'; import MissingIndicator from '../../components/missing_indicator';
import LoadingIndicator from '../../components/loading_indicator'; import LoadingIndicator from '../../components/loading_indicator';
import Icon from 'gabsocial/components/icon'; import Icon from 'gabsocial/components/icon';
import HomeColumnHeader from '../../components/home_column_header';
import { Link } from 'react-router-dom';
import Button from 'gabsocial/components/button';
const messages = defineMessages({ const messages = defineMessages({
deleteMessage: { id: 'confirmations.delete_list.message', defaultMessage: 'Are you sure you want to permanently delete this list?' }, deleteMessage: { id: 'confirmations.delete_list.message', defaultMessage: 'Are you sure you want to permanently delete this list?' },
@ -97,15 +98,22 @@ class ListTimeline extends React.PureComponent {
} else if (list === false) { } else if (list === false) {
return ( return (
<Column> <Column>
<ColumnBackButton />
<MissingIndicator /> <MissingIndicator />
</Column> </Column>
); );
} }
const emptyMessage = (
<div>
<FormattedMessage id='empty_column.list' defaultMessage='There is nothing in this list yet. When members of this list post new statuses, they will appear here.' />
<br/><br/>
<Button onClick={this.handleEditClick}><FormattedMessage id='list.click_to_add' defaultMessage='Click here to add people'/></Button>
</div>
);
return ( return (
<Column label={title}> <Column label={title}>
<ColumnHeader icon='list-ul' active={hasUnread} title={title} > <HomeColumnHeader activeItem='lists' activeSubItem={id} active={hasUnread}>
<div className='column-header__links'> <div className='column-header__links'>
<button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleEditClick}> <button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleEditClick}>
<Icon id='pencil' /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' /> <Icon id='pencil' /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' />
@ -114,16 +122,21 @@ class ListTimeline extends React.PureComponent {
<button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleDeleteClick}> <button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleDeleteClick}>
<Icon id='trash' /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' /> <Icon id='trash' /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' />
</button> </button>
</div>
<hr /> <hr/>
</ColumnHeader>
<Link to='/lists' className='text-btn column-header__setting-btn column-header__setting-btn--link'>
<FormattedMessage id='lists.view_all' defaultMessage='View all lists' />
<Icon id='arrow-right' />
</Link>
</div>
</HomeColumnHeader>
<StatusListContainer <StatusListContainer
scrollKey='list_timeline' scrollKey='list_timeline'
timelineId={`list:${id}`} timelineId={`list:${id}`}
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}
emptyMessage={<FormattedMessage id='empty_column.list' defaultMessage='There is nothing in this list yet. When members of this list post new statuses, they will appear here.' />} emptyMessage={emptyMessage}
/> />
</Column> </Column>
); );

View File

@ -2,12 +2,13 @@ import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { changeListEditorTitle, submitListEditor } from '../../../actions/lists'; import { changeListEditorTitle, submitListEditor } from '../../../actions/lists';
import IconButton from '../../../components/icon_button'; import Button from '../../../components/button';
import { defineMessages, injectIntl } from 'react-intl'; import { defineMessages, injectIntl } from 'react-intl';
const messages = defineMessages({ const messages = defineMessages({
label: { id: 'lists.new.title_placeholder', defaultMessage: 'New list title' }, label: { id: 'lists.new.title_placeholder', defaultMessage: 'New list title' },
title: { id: 'lists.new.create', defaultMessage: 'Add list' }, title: { id: 'lists.new.create', defaultMessage: 'Add list' },
create: { id: 'lists.new.create_title', defaultMessage: 'Create' },
}); });
const mapStateToProps = state => ({ const mapStateToProps = state => ({
@ -50,6 +51,7 @@ class NewListForm extends React.PureComponent {
const label = intl.formatMessage(messages.label); const label = intl.formatMessage(messages.label);
const title = intl.formatMessage(messages.title); const title = intl.formatMessage(messages.title);
const create = intl.formatMessage(messages.create);
return ( return (
<form className='column-inline-form' onSubmit={this.handleSubmit}> <form className='column-inline-form' onSubmit={this.handleSubmit}>
@ -57,7 +59,7 @@ class NewListForm extends React.PureComponent {
<span style={{ display: 'none' }}>{label}</span> <span style={{ display: 'none' }}>{label}</span>
<input <input
className='setting-text' className='setting-text new-list-form__input'
value={value} value={value}
disabled={disabled} disabled={disabled}
onChange={this.handleChange} onChange={this.handleChange}
@ -65,12 +67,13 @@ class NewListForm extends React.PureComponent {
/> />
</label> </label>
<IconButton <Button
className='new-list-form__btn'
disabled={disabled} disabled={disabled}
icon='plus'
title={title}
onClick={this.handleClick} onClick={this.handleClick}
/> >
{create}
</Button>
</form> </form>
); );
} }

View File

@ -4,7 +4,6 @@ import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import LoadingIndicator from '../../components/loading_indicator'; import LoadingIndicator from '../../components/loading_indicator';
import Column from '../ui/components/column'; import Column from '../ui/components/column';
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
import { fetchLists } from '../../actions/lists'; import { fetchLists } from '../../actions/lists';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
@ -17,6 +16,7 @@ import ScrollableList from '../../components/scrollable_list';
const messages = defineMessages({ const messages = defineMessages({
heading: { id: 'column.lists', defaultMessage: 'Lists' }, heading: { id: 'column.lists', defaultMessage: 'Lists' },
subheading: { id: 'lists.subheading', defaultMessage: 'Your lists' }, subheading: { id: 'lists.subheading', defaultMessage: 'Your lists' },
add: { id: 'lists.new.create', defaultMessage: 'Add List' },
}); });
const getOrderedLists = createSelector([state => state.get('lists')], lists => { const getOrderedLists = createSelector([state => state.get('lists')], lists => {
@ -60,11 +60,11 @@ class Lists extends ImmutablePureComponent {
const emptyMessage = <FormattedMessage id='empty_column.lists' defaultMessage="You don't have any lists yet. When you create one, it will show up here." />; const emptyMessage = <FormattedMessage id='empty_column.lists' defaultMessage="You don't have any lists yet. When you create one, it will show up here." />;
return ( return (
<Column icon='list-ul' heading={intl.formatMessage(messages.heading)}> <Column icon='list-ul' heading={intl.formatMessage(messages.heading)} backBtnSlim>
<ColumnBackButtonSlim /> <br/>
<ColumnSubheading text={intl.formatMessage(messages.add)} />
<NewListForm /> <NewListForm />
<br/>
<ColumnSubheading text={intl.formatMessage(messages.subheading)} /> <ColumnSubheading text={intl.formatMessage(messages.subheading)} />
<ScrollableList <ScrollableList
scrollKey='lists' scrollKey='lists'

View File

@ -7,7 +7,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import LoadingIndicator from '../../components/loading_indicator'; import LoadingIndicator from '../../components/loading_indicator';
import Column from '../ui/components/column'; import Column from '../ui/components/column';
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
import AccountContainer from '../../containers/account_container'; import AccountContainer from '../../containers/account_container';
import { fetchMutes, expandMutes } from '../../actions/mutes'; import { fetchMutes, expandMutes } from '../../actions/mutes';
import ScrollableList from '../../components/scrollable_list'; import ScrollableList from '../../components/scrollable_list';
@ -55,8 +54,7 @@ class Mutes extends ImmutablePureComponent {
const emptyMessage = <FormattedMessage id='empty_column.mutes' defaultMessage="You haven't muted any users yet." />; const emptyMessage = <FormattedMessage id='empty_column.mutes' defaultMessage="You haven't muted any users yet." />;
return ( return (
<Column icon='volume-off' heading={intl.formatMessage(messages.heading)}> <Column icon='volume-off' heading={intl.formatMessage(messages.heading)} backBtnSlim>
<ColumnBackButtonSlim />
<ScrollableList <ScrollableList
scrollKey='mutes' scrollKey='mutes'
onLoadMore={this.handleLoadMore} onLoadMore={this.handleLoadMore}

View File

@ -10,7 +10,6 @@ import { fetchStatus } from '../../actions/statuses';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import AccountContainer from '../../containers/account_container'; import AccountContainer from '../../containers/account_container';
import Column from '../ui/components/column'; import Column from '../ui/components/column';
import ColumnBackButton from '../../components/column_back_button';
import ScrollableList from '../../components/scrollable_list'; import ScrollableList from '../../components/scrollable_list';
import { makeGetStatus } from '../../selectors'; import { makeGetStatus } from '../../selectors';
@ -72,8 +71,6 @@ class Reblogs extends ImmutablePureComponent {
return ( return (
<Column> <Column>
<ColumnBackButton />
<ScrollableList <ScrollableList
scrollKey='reblogs' scrollKey='reblogs'
emptyMessage={emptyMessage} emptyMessage={emptyMessage}

View File

@ -4,7 +4,6 @@ import { defineMessages, injectIntl } from 'react-intl';
import Column from './column'; import Column from './column';
import ColumnHeader from './column_header'; import ColumnHeader from './column_header';
import ColumnBackButtonSlim from '../../../components/column_back_button_slim';
import IconButton from '../../../components/icon_button'; import IconButton from '../../../components/icon_button';
const messages = defineMessages({ const messages = defineMessages({
@ -30,7 +29,6 @@ class BundleColumnError extends React.PureComponent {
return ( return (
<Column> <Column>
<ColumnHeader icon='exclamation-circle' type={formatMessage(messages.title)} /> <ColumnHeader icon='exclamation-circle' type={formatMessage(messages.title)} />
<ColumnBackButtonSlim />
<div className='error-column'> <div className='error-column'>
<IconButton title={formatMessage(messages.retry)} icon='refresh' onClick={this.handleRetry} size={64} /> <IconButton title={formatMessage(messages.retry)} icon='refresh' onClick={this.handleRetry} size={64} />
{formatMessage(messages.body)} {formatMessage(messages.body)}

View File

@ -2,6 +2,8 @@ import React from 'react';
import ColumnHeader from './column_header'; import ColumnHeader from './column_header';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { isMobile } from '../../../is_mobile'; import { isMobile } from '../../../is_mobile';
import ColumnBackButton from '../../../components/column_back_button';
import ColumnBackButtonSlim from '../../../components/column_back_button_slim';
export default class Column extends React.PureComponent { export default class Column extends React.PureComponent {
@ -11,10 +13,11 @@ export default class Column extends React.PureComponent {
children: PropTypes.node, children: PropTypes.node,
active: PropTypes.bool, active: PropTypes.bool,
hideHeadingOnMobile: PropTypes.bool, hideHeadingOnMobile: PropTypes.bool,
backBtnSlim: PropTypes.bool,
}; };
render () { render () {
const { heading, icon, children, active, hideHeadingOnMobile } = this.props; const { heading, icon, children, active, hideHeadingOnMobile, backBtnSlim } = this.props;
const showHeading = heading && (!hideHeadingOnMobile || (hideHeadingOnMobile && !isMobile(window.innerWidth))); const showHeading = heading && (!hideHeadingOnMobile || (hideHeadingOnMobile && !isMobile(window.innerWidth)));
@ -22,9 +25,13 @@ export default class Column extends React.PureComponent {
const header = showHeading && ( const header = showHeading && (
<ColumnHeader icon={icon} active={active} type={heading} columnHeaderId={columnHeaderId} /> <ColumnHeader icon={icon} active={active} type={heading} columnHeaderId={columnHeaderId} />
); );
const backBtn = backBtnSlim ? (<ColumnBackButtonSlim/>) : (<ColumnBackButton/>);
return ( return (
<div role='region' aria-labelledby={columnHeaderId} className='column'> <div role='region' aria-labelledby={columnHeaderId} className='column'>
{header} {header}
{backBtn}
{children} {children}
</div> </div>
); );

View File

@ -53,6 +53,8 @@ import {
Explore, Explore,
Groups, Groups,
GroupTimeline, GroupTimeline,
ListTimeline,
Lists,
} from './util/async-components'; } from './util/async-components';
import { me, meUsername } from '../../initial_state'; import { me, meUsername } from '../../initial_state';
import { previewState as previewMediaState } from './components/media_modal'; import { previewState as previewMediaState } from './components/media_modal';
@ -109,8 +111,8 @@ const LAYOUT = {
}, },
DEFAULT: { DEFAULT: {
LEFT: [ LEFT: [
<WhoToFollowPanel />, <WhoToFollowPanel key='0' />,
<LinkFooter />, <LinkFooter key='1' />,
], ],
RIGHT: [ RIGHT: [
// <TrendsPanel />, // <TrendsPanel />,
@ -120,9 +122,9 @@ const LAYOUT = {
TOP: null, TOP: null,
LEFT: null, LEFT: null,
RIGHT: [ RIGHT: [
<WhoToFollowPanel />, <WhoToFollowPanel key='0' />,
// <TrendsPanel />, // <TrendsPanel />,
<LinkFooter />, <LinkFooter key='1' />,
], ],
}, },
}; };
@ -177,8 +179,8 @@ class SwitchingColumnsArea extends React.PureComponent {
<WrappedRoute path='/tags/:id' component={HashtagTimeline} content={children} /> <WrappedRoute path='/tags/:id' component={HashtagTimeline} content={children} />
<Redirect from='/lists' to='/home' /> <WrappedRoute path='/lists' layout={LAYOUT.DEFAULT} component={Lists} content={children} />
<Redirect from='/list' to='/home' /> <WrappedRoute path='/list/:id' page={HomePage} component={ListTimeline} content={children} />
<WrappedRoute path='/notifications' layout={LAYOUT.DEFAULT} component={Notifications} content={children} /> <WrappedRoute path='/notifications' layout={LAYOUT.DEFAULT} component={Notifications} content={children} />

View File

@ -2495,11 +2495,14 @@ a.status-card.compact:hover {
background: transparent; background: transparent;
font: inherit; font: inherit;
text-align: left; text-align: left;
text-overflow: ellipsis;
text-decoration: none; text-decoration: none;
overflow: hidden;
white-space: nowrap; white-space: nowrap;
&--sub {
font-size: 14px;
padding: 6px 10px;
}
&.grouped { &.grouped {
margin: 6px; margin: 6px;
} }
@ -2597,6 +2600,13 @@ a.status-card.compact:hover {
} }
.column-header__setting-btn { .column-header__setting-btn {
&--link {
text-decoration: none;
.fa {
margin-left: 10px;
}
}
&:hover { &:hover {
color: $darker-text-color; color: $darker-text-color;
text-decoration: underline; text-decoration: underline;
@ -2615,6 +2625,12 @@ a.status-card.compact:hover {
} }
} }
.column-header__expansion {
overflow-x: scroll;
overflow-y: hidden;
white-space: nowrap;
}
.text-btn { .text-btn {
display: inline-block; display: inline-block;
padding: 0; padding: 0;
@ -2961,6 +2977,7 @@ a.status-card.compact:hover {
flex: 1 1 auto; flex: 1 1 auto;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
min-height: 160px;
@supports(display: grid) { // hack to fix Chrome <57 @supports(display: grid) { // hack to fix Chrome <57
contain: strict; contain: strict;
@ -4364,12 +4381,11 @@ noscript {
} }
.list-editor { .list-editor {
background: $ui-base-color;
flex-direction: column; flex-direction: column;
border-radius: 8px; width: 100%;
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
width: 380px;
overflow: hidden; overflow: hidden;
height: 100%;
overflow-y: scroll;
@media screen and (max-width: 420px) { @media screen and (max-width: 420px) {
width: 90%; width: 90%;
@ -4384,10 +4400,6 @@ noscript {
border-radius: 8px 8px 0 0; border-radius: 8px 8px 0 0;
} }
.drawer__pager {
height: 50vh;
}
.drawer__inner { .drawer__inner {
border-radius: 0 0 8px 8px; border-radius: 0 0 8px 8px;
@ -4399,7 +4411,9 @@ noscript {
} }
&__accounts { &__accounts {
background: lighten($ui-base-color, 13%);
overflow-y: auto; overflow-y: auto;
max-height: 200px;
} }
.account__display-name { .account__display-name {
@ -4413,17 +4427,31 @@ noscript {
} }
.search { .search {
margin-bottom: 0; display: flex;
flex-direction: row;
margin: 10px 0;
> label {
flex: 1 1;
}
> .search__icon .fa {
right: 102px !important;
}
> .button {
width: 80px;
margin-left: 10px;
}
} }
} }
.list-adder { .list-adder {
background: $ui-base-color;
flex-direction: column; flex-direction: column;
border-radius: 8px; width: 100%;
box-shadow: 2px 4px 15px rgba($base-shadow-color, 0.4);
width: 380px;
overflow: hidden; overflow: hidden;
height: 100%;
overflow-y: scroll;
@media screen and (max-width: 420px) { @media screen and (max-width: 420px) {
width: 90%; width: 90%;
@ -4431,22 +4459,24 @@ noscript {
&__account { &__account {
background: lighten($ui-base-color, 13%); background: lighten($ui-base-color, 13%);
border-radius: 4px;
} }
&__lists { &__lists {
background: lighten($ui-base-color, 13%); background: lighten($ui-base-color, 13%);
height: 50vh;
border-radius: 0 0 8px 8px;
overflow-y: auto;
} }
.list { .list {
padding: 10px; padding: 4px;
border-bottom: 1px solid lighten($ui-base-color, 8%); border-bottom: 1px solid lighten($ui-base-color, 8%);
} }
.list__wrapper { .list__wrapper {
display: flex; display: flex;
.account__relationship {
padding: 8px 5px 0 5px;
}
} }
.list__display-name { .list__display-name {
@ -4458,6 +4488,18 @@ noscript {
} }
} }
.new-list-form,
.edit-list-form {
&__btn {
margin-left: 6px;
width: 112px;
}
&__input {
height: 36px;
}
}
.focal-point-modal { .focal-point-modal {
max-width: 80vw; max-width: 80vw;
max-height: 80vh; max-height: 80vh;
@ -4827,6 +4869,7 @@ noscript {
border-radius: 6px; border-radius: 6px;
flex-direction: column; flex-direction: column;
width: 600px; width: 600px;
margin: 10px 0;
&__header { &__header {
display: block; display: block;
@ -4868,8 +4911,9 @@ noscript {
} }
@media screen and (max-width:895px) { @media screen and (max-width:895px) {
height: 100vh; margin: 0;
width: 100vw; height: 98vh;
width: 98vw;
} }
} }