Merge branch 'develop' into bugfix/patch-fix-mention-button-mobile

This commit is contained in:
Dank Gabs
2019-07-09 14:34:39 -04:00
14 changed files with 300 additions and 82 deletions

View File

@@ -208,7 +208,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
}
return [
<div className='compose-form__autosuggest-wrapper'>
<div className='compose-form__autosuggest-wrapper' key='compose-form__autosuggest-wrapper'>
<div className='autosuggest-textarea'>
<label>
<span style={{ display: 'none' }}>{placeholder}</span>
@@ -233,7 +233,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
</div>
{children}
</div>,
<div className='autosuggest-textarea__suggestions-wrapper'>
<div className='autosuggest-textarea__suggestions-wrapper' key='autosuggest-textarea__suggestions-wrapper'>
<div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>
{suggestions.map(this.renderSuggestion)}
</div>

View File

@@ -0,0 +1,109 @@
'use strict';
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
import { Link } from 'react-router-dom';
import Icon from 'gabsocial/components/icon';
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' },
});
export default @injectIntl
class ColumnHeader extends React.PureComponent {
static contextTypes = {
router: PropTypes.object,
};
static propTypes = {
intl: PropTypes.object.isRequired,
active: PropTypes.bool,
children: PropTypes.node,
activeItem: PropTypes.string,
};
state = {
collapsed: true,
animating: false,
};
handleToggleClick = (e) => {
e.stopPropagation();
this.setState({ collapsed: !this.state.collapsed, animating: true });
}
handleTransitionEnd = () => {
this.setState({ animating: false });
}
render () {
const { active, children, intl: { formatMessage }, activeItem } = this.props;
const { collapsed, animating } = 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,
});
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,
];
return (
<div className={wrapperClassName}>
<h1 className={buttonClassName}>
<Link to='/home' className={classNames('btn grouped', {'active': 'home' === activeItem})}>
<Icon id='home' fixedWidth className='column-header__icon' />
{formatMessage(messages.homeTitle)}
</Link>
<Link to='/timeline/all' className={classNames('btn grouped', {'active': 'all' === activeItem})}>
<Icon id='globe' fixedWidth className='column-header__icon' />
{formatMessage(messages.allTitle)}
</Link>
<div className='column-header__buttons'>
{collapseButton}
</div>
</h1>
<div className={collapsibleClassName} tabIndex={collapsed ? -1 : null} onTransitionEnd={this.handleTransitionEnd}>
<div className='column-header__collapsible-inner'>
{(!collapsed || animating) && collapsedContent}
</div>
</div>
</div>
);
}
}

View File

@@ -4,10 +4,10 @@ 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 ColumnHeader from '../../components/column_header';
import { expandCommunityTimeline } from '../../actions/timelines';
import ColumnSettingsContainer from './containers/column_settings_container';
import { connectCommunityStream } from '../../actions/streaming';
import HomeColumnHeader from '../../components/home_column_header';
const messages = defineMessages({
title: { id: 'column.community', defaultMessage: 'Local timeline' },
@@ -79,14 +79,12 @@ class CommunityTimeline extends React.PureComponent {
return (
<Column label={intl.formatMessage(messages.title)}>
<ColumnHeader
icon='users'
<HomeColumnHeader
activeItem='all'
active={hasUnread}
title={intl.formatMessage(messages.title)}
>
<ColumnSettingsContainer columnId={columnId} />
</ColumnHeader>
<ColumnSettingsContainer />
</HomeColumnHeader>
<StatusListContainer
scrollKey={`community_timeline-${columnId}`}
timelineId={`community${onlyMedia ? ':media' : ''}`}

View File

@@ -4,13 +4,9 @@ import { expandHomeTimeline } from '../../actions/timelines';
import PropTypes from 'prop-types';
import StatusListContainer from '../ui/containers/status_list_container';
import Column from '../../components/column';
import ColumnHeader from '../../components/column_header';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ColumnSettingsContainer from './containers/column_settings_container';
import { Link } from 'react-router-dom';
import { me } from '../../initial_state';
import ComposeFormContainer from '../compose/containers/compose_form_container';
import Avatar from '../../components/avatar';
import HomeColumnHeader from '../../components/home_column_header';
const messages = defineMessages({
title: { id: 'column.home', defaultMessage: 'Home' },
@@ -19,7 +15,6 @@ const messages = defineMessages({
const mapStateToProps = state => ({
hasUnread: state.getIn(['timelines', 'home', 'unread']) > 0,
isPartial: state.getIn(['timelines', 'home', 'isPartial']),
account: state.getIn(['accounts', me]),
});
export default @connect(mapStateToProps)
@@ -72,22 +67,16 @@ class HomeTimeline extends React.PureComponent {
}
render () {
const { intl, hasUnread, columnId, account } = this.props;
const { intl, hasUnread, columnId } = this.props;
return (
<Column label={intl.formatMessage(messages.title)}>
<div className='timeline-compose-block'>
<div className='timeline-compose-block__avatar'>
<Avatar account={account} size={46} />
</div>
<ComposeFormContainer shouldCondense={true} autoFocus={false}/>
</div>
<ColumnHeader icon='home' active={hasUnread} title={intl.formatMessage(messages.title)}>
<HomeColumnHeader
activeItem='home'
active={hasUnread}
>
<ColumnSettingsContainer />
</ColumnHeader>
</HomeColumnHeader>
<StatusListContainer
scrollKey={`home_timeline-${columnId}`}
onLoadMore={this.handleLoadMore}

View File

@@ -64,6 +64,10 @@ class Notifications extends React.PureComponent {
this.props.dispatch(scrollTopNotifications(false));
}
componentDidMount() {
this.props.dispatch(scrollTopNotifications(true));
}
handleLoadGap = (maxId) => {
this.props.dispatch(expandNotifications({ maxId }));
};

View File

@@ -24,17 +24,14 @@ import TabsBar from './components/tabs_bar';
// import TrendsPanel from './components/trends_panel';
import WhoToFollowPanel from './components/who_to_follow_panel';
import LinkFooter from './components/link_footer';
import ProfileInfoPanel from './components/profile_info_panel';
import UserPanel from './components/user_panel';
import PromoPanel from './components/promo_panel';
import ProfilePage from 'gabsocial/pages/profile_page';
import SearchPage from 'gabsocial/pages/search_page';
import HomePage from 'gabsocial/pages/home_page';
import {
Compose,
Status,
GettingStarted,
PublicTimeline,
CommunityTimeline,
AccountTimeline,
AccountGallery,
@@ -110,17 +107,6 @@ const LAYOUT = {
LEFT: null,
RIGHT: null,
},
HOME: {
LEFT: [
<UserPanel />,
<PromoPanel />,
<LinkFooter />,
],
RIGHT: [
// <TrendsPanel />,
<WhoToFollowPanel />,
],
},
DEFAULT: {
LEFT: [
<WhoToFollowPanel />,
@@ -181,7 +167,8 @@ class SwitchingColumnsArea extends React.PureComponent {
return (
<Switch>
<Redirect from='/' to='/home' exact />
<WrappedRoute path='/home' exact layout={LAYOUT.HOME} component={HomeTimeline} content={children} />
<WrappedRoute path='/home' exact page={HomePage} component={HomeTimeline} content={children} />
<WrappedRoute path='/timeline/all' exact page={HomePage} component={CommunityTimeline} content={children} />
<WrappedRoute path='/groups' component={Groups} content={children} />
<WrappedRoute path='/groups/:id' component={GroupTimeline} content={children} />

View File

@@ -0,0 +1,58 @@
import React from 'react';
import { connect } from 'react-redux';
import { me } from 'gabsocial/initial_state';
import PropTypes from 'prop-types';
import ImmutablePureComponent from 'react-immutable-pure-component';
import WhoToFollowPanel from '../features/ui/components/who_to_follow_panel';
import LinkFooter from '../features/ui/components/link_footer';
import PromoPanel from '../features/ui/components/promo_panel';
import UserPanel from '../features/ui/components/user_panel';
import ComposeFormContainer from '../features/compose/containers/compose_form_container';
import Avatar from '../components/avatar';
const mapStateToProps = state => ({
account: state.getIn(['accounts', me]),
});
export default @connect(mapStateToProps)
class HomePage extends ImmutablePureComponent {
render () {
const {children, account} = this.props;
return (
<div className='page'>
<div className='page__columns'>
<div className='columns-area__panels'>
<div className='columns-area__panels__pane columns-area__panels__pane--left'>
<div className='columns-area__panels__pane__inner'>
<UserPanel />
<PromoPanel />
<LinkFooter />
</div>
</div>
<div className='columns-area__panels__main'>
<div className='columns-area columns-area--mobile'>
<div className='timeline-compose-block'>
<div className='timeline-compose-block__avatar'>
<Avatar account={account} size={46} />
</div>
<ComposeFormContainer shouldCondense={true} autoFocus={false}/>
</div>
{children}
</div>
</div>
<div className='columns-area__panels__pane columns-area__panels__pane--right'>
<div className='columns-area__panels__pane__inner'>
<WhoToFollowPanel />
</div>
</div>
</div>
</div>
</div>
)
}
}

View File

@@ -246,7 +246,7 @@
align-items: flex-start;
padding: 20px;
border-radius: 10px;
margin-bottom: 20px;
margin-bottom: 10px;
background: $gab-background-container;
body.theme-gabsocial-light & {
@include light-theme-shadow();
@@ -1475,7 +1475,8 @@ a.account__display-name {
flex-direction: column;
width: 100%;
margin: 0 auto;
overflow: hidden;
.column,
.drawer {
width: 100%;
@@ -2445,6 +2446,9 @@ a.status-card.compact:hover {
.column-header__wrapper {
position: relative;
flex: 0 0 auto;
border-top-right-radius: 10px;
border-top-left-radius: 10px;
overflow: hidden;
&.active {
&::before {
@@ -2481,18 +2485,29 @@ a.status-card.compact:hover {
outline: 0;
overflow: hidden;
& > button {
& > button,
& > .btn {
margin: 0;
border: none;
padding: 15px 0 15px 15px;
padding: 15px;
color: inherit;
background: transparent;
font: inherit;
text-align: left;
text-overflow: ellipsis;
text-decoration: none;
overflow: hidden;
white-space: nowrap;
flex: 1;
&.grouped {
margin: 6px;
}
&.active {
color: $primary-text-color;
border-radius: 10px;
background-color: rgba($highlight-text-color, .1);
}
}
& > .column-header__back-button {
@@ -2517,6 +2532,7 @@ a.status-card.compact:hover {
.column-header__buttons {
height: 48px;
display: flex;
margin-left: auto;
}
.column-header__links .text-btn {