Progress
This commit is contained in:
parent
0d9dbdfecd
commit
0f01c1bc97
|
@ -22,7 +22,6 @@ export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL';
|
||||||
export const COMPOSE_REPLY = 'COMPOSE_REPLY';
|
export const COMPOSE_REPLY = 'COMPOSE_REPLY';
|
||||||
export const COMPOSE_QUOTE = 'COMPOSE_QUOTE';
|
export const COMPOSE_QUOTE = 'COMPOSE_QUOTE';
|
||||||
export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL';
|
export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL';
|
||||||
export const COMPOSE_DIRECT = 'COMPOSE_DIRECT';
|
|
||||||
export const COMPOSE_MENTION = 'COMPOSE_MENTION';
|
export const COMPOSE_MENTION = 'COMPOSE_MENTION';
|
||||||
export const COMPOSE_RESET = 'COMPOSE_RESET';
|
export const COMPOSE_RESET = 'COMPOSE_RESET';
|
||||||
export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST';
|
export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST';
|
||||||
|
|
|
@ -57,9 +57,7 @@ const refreshHomeTimelineAndNotification = (dispatch, done) => {
|
||||||
|
|
||||||
export const connectUserStream = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification);
|
export const connectUserStream = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification);
|
||||||
export const connectCommunityStream = ({ onlyMedia } = {}) => connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`);
|
export const connectCommunityStream = ({ onlyMedia } = {}) => connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`);
|
||||||
export const connectPublicStream = ({ onlyMedia } = {}) => connectTimelineStream(`public${onlyMedia ? ':media' : ''}`, `public${onlyMedia ? ':media' : ''}`);
|
|
||||||
export const connectHashtagStream = (id, tag, accept) => connectTimelineStream(`hashtag:${id}`, `hashtag&tag=${tag}`, null, accept);
|
export const connectHashtagStream = (id, tag, accept) => connectTimelineStream(`hashtag:${id}`, `hashtag&tag=${tag}`, null, accept);
|
||||||
export const connectDirectStream = () => connectTimelineStream('direct', 'direct');
|
|
||||||
export const connectListStream = id => connectTimelineStream(`list:${id}`, `list&list=${id}`);
|
export const connectListStream = id => connectTimelineStream(`list:${id}`, `list&list=${id}`);
|
||||||
export const connectGroupStream = id => connectTimelineStream(`group:${id}`, `group&group=${id}`);
|
export const connectGroupStream = id => connectTimelineStream(`group:${id}`, `group&group=${id}`);
|
||||||
|
|
||||||
|
|
|
@ -153,7 +153,6 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
|
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
|
||||||
export const expandPublicTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`public${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { max_id: maxId, only_media: !!onlyMedia }, done);
|
|
||||||
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done);
|
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done);
|
||||||
export const expandAccountTimeline = (accountId, { maxId, withReplies } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, max_id: maxId });
|
export const expandAccountTimeline = (accountId, { maxId, withReplies } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, max_id: maxId });
|
||||||
export const expandAccountFeaturedTimeline = accountId => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true });
|
export const expandAccountFeaturedTimeline = accountId => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true });
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
const GroupAddIcon = ({
|
||||||
|
className = '',
|
||||||
|
width = '24px',
|
||||||
|
height = '24px',
|
||||||
|
viewBox = '0 0 64 64',
|
||||||
|
title = 'Group Add',
|
||||||
|
}) => (
|
||||||
|
<svg
|
||||||
|
className={className}
|
||||||
|
version='1.1'
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
x='0px'
|
||||||
|
y='0px'
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
viewBox={viewBox}
|
||||||
|
xmlSpace='preserve'
|
||||||
|
aria-label={title}
|
||||||
|
>
|
||||||
|
<g>
|
||||||
|
<path d="M 64 53.5 L 53.5 53.5 L 53.5 64 L 48.5 64 L 48.5 53.5 L 38 53.5 L 38 48.5 L 48.5 48.5 L 48.5 38 L 53.5 38 L 53.5 48.5 L 64 48.5 Z M 37.414062 27.929688 C 37.632812 28.917969 37.75 29.945312 37.75 31 C 37.75 35.320312 35.800781 39.191406 32.738281 41.785156 C 32.824219 41.820312 32.914062 41.851562 33 41.886719 L 33 47.414062 C 30.324219 45.953125 27.257812 45.125 24 45.125 L 24 45.121094 C 23.957031 45.121094 23.917969 45.121094 23.875 45.121094 L 23.875 45.125 C 13.46875 45.125 5 53.59375 5 64 L 0 64 C 0 54.078125 6.085938 45.550781 14.714844 41.953125 C 11.535156 39.359375 9.5 35.414062 9.5 31 C 9.5 23.210938 15.835938 16.875 23.625 16.875 C 24.550781 16.875 25.457031 16.964844 26.332031 17.136719 C 26.117188 16.15625 26 15.136719 26 14.09375 C 26 6.320312 32.324219 0 40.09375 0 C 47.863281 0 54.1875 6.320312 54.1875 14.09375 C 54.1875 18.453125 52.195312 22.359375 49.074219 24.945312 C 53.199219 26.585938 56.757812 29.335938 59.359375 32.875 L 52.628906 32.875 C 49.523438 30.121094 45.507812 28.375 41.097656 28.148438 C 40.765625 28.171875 40.429688 28.1875 40.09375 28.1875 C 39.175781 28.1875 38.28125 28.097656 37.414062 27.929688 Z M 31 14.09375 C 31 19.109375 35.078125 23.1875 40.09375 23.1875 C 45.105469 23.1875 49.1875 19.109375 49.1875 14.09375 C 49.1875 9.078125 45.105469 5 40.09375 5 C 35.078125 5 31 9.078125 31 14.09375 Z M 32.75 31 C 32.75 25.96875 28.65625 21.875 23.625 21.875 C 18.59375 21.875 14.5 25.96875 14.5 31 C 14.5 36.03125 18.59375 40.125 23.625 40.125 C 28.65625 40.125 32.75 36.03125 32.75 31 Z M 32.75 31" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default GroupAddIcon
|
|
@ -15,11 +15,13 @@ import ErrorIcon from './error_icon'
|
||||||
import FullscreenIcon from './fullscreen_icon'
|
import FullscreenIcon from './fullscreen_icon'
|
||||||
import GlobeIcon from './globe_icon'
|
import GlobeIcon from './globe_icon'
|
||||||
import GroupIcon from './group_icon'
|
import GroupIcon from './group_icon'
|
||||||
|
import GroupAddIcon from './group_add_icon'
|
||||||
import HappyIcon from './happy_icon'
|
import HappyIcon from './happy_icon'
|
||||||
import HomeIcon from './home_icon'
|
import HomeIcon from './home_icon'
|
||||||
import LikeIcon from './like_icon'
|
import LikeIcon from './like_icon'
|
||||||
import LinkIcon from './link_icon'
|
import LinkIcon from './link_icon'
|
||||||
import ListIcon from './list_icon'
|
import ListIcon from './list_icon'
|
||||||
|
import ListAddIcon from './list_add_icon'
|
||||||
import LoadingIcon from './loading_icon'
|
import LoadingIcon from './loading_icon'
|
||||||
import MediaIcon from './media_icon'
|
import MediaIcon from './media_icon'
|
||||||
import MinimizeFullscreenIcon from './minimize_fullscreen_icon'
|
import MinimizeFullscreenIcon from './minimize_fullscreen_icon'
|
||||||
|
@ -58,11 +60,13 @@ export {
|
||||||
FullscreenIcon,
|
FullscreenIcon,
|
||||||
GlobeIcon,
|
GlobeIcon,
|
||||||
GroupIcon,
|
GroupIcon,
|
||||||
|
GroupAddIcon,
|
||||||
HappyIcon,
|
HappyIcon,
|
||||||
HomeIcon,
|
HomeIcon,
|
||||||
LikeIcon,
|
LikeIcon,
|
||||||
LinkIcon,
|
LinkIcon,
|
||||||
ListIcon,
|
ListIcon,
|
||||||
|
ListAddIcon,
|
||||||
LoadingIcon,
|
LoadingIcon,
|
||||||
MediaIcon,
|
MediaIcon,
|
||||||
MinimizeFullscreenIcon,
|
MinimizeFullscreenIcon,
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
const ListAddIcon = ({
|
||||||
|
className = '',
|
||||||
|
width = '24px',
|
||||||
|
height = '24px',
|
||||||
|
viewBox = '0 0 24 24',
|
||||||
|
title = 'List Add',
|
||||||
|
}) => (
|
||||||
|
<svg
|
||||||
|
className={className}
|
||||||
|
version='1.1'
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
x='0px'
|
||||||
|
y='0px'
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
viewBox={viewBox}
|
||||||
|
xmlSpace='preserve'
|
||||||
|
aria-label={title}
|
||||||
|
>
|
||||||
|
<g>
|
||||||
|
<path d='M19,7H8A1,1,0,0,1,8,5H19a1,1,0,0,1,0,2Z' />
|
||||||
|
<path d='M19,11H8A1,1,0,0,1,8,9H19a1,1,0,0,1,0,2Z' />
|
||||||
|
<path d='M13,15H8a1,1,0,0,1,0-2h5a1,1,0,0,1,0,2Z' />
|
||||||
|
<circle cx='4' cy='6' r='1'/>
|
||||||
|
<circle cx='4' cy='10' r='1'/>
|
||||||
|
<circle cx='4' cy='14' r='1'/>
|
||||||
|
<path d='M13,19H8a1,1,0,0,1,0-2h5a1,1,0,0,1,0,2Z' />
|
||||||
|
<circle cx='4' cy='18' r='1'/>
|
||||||
|
<path d='M21,15H20V14a1,1,0,0,0-2,0v1H17a1,1,0,0,0,0,2h1v1a1,1,0,0,0,2,0V17h1a1,1,0,0,0,0-2Z' />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default ListAddIcon
|
|
@ -109,6 +109,9 @@ class Account extends ImmutablePureComponent {
|
||||||
const requested = account.getIn(['relationship', 'requested'])
|
const requested = account.getIn(['relationship', 'requested'])
|
||||||
const blocking = account.getIn(['relationship', 'blocking'])
|
const blocking = account.getIn(['relationship', 'blocking'])
|
||||||
|
|
||||||
|
// : todo :
|
||||||
|
// unmute
|
||||||
|
|
||||||
if (requested || blocking) {
|
if (requested || blocking) {
|
||||||
buttonText = intl.formatMessage(requested ? messages.requested : messages.unblock)
|
buttonText = intl.formatMessage(requested ? messages.requested : messages.unblock)
|
||||||
buttonOptions = {
|
buttonOptions = {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { textAtCursorMatchesToken } from '../../utils/cursor_token_match'
|
||||||
import AutosuggestAccount from '../autosuggest_account'
|
import AutosuggestAccount from '../autosuggest_account'
|
||||||
import AutosuggestEmoji from '../autosuggest_emoji'
|
import AutosuggestEmoji from '../autosuggest_emoji'
|
||||||
import Input from '../input'
|
import Input from '../input'
|
||||||
|
import Composer from '../composer'
|
||||||
|
|
||||||
const cx = classNames.bind(_s)
|
const cx = classNames.bind(_s)
|
||||||
|
|
||||||
|
@ -52,9 +53,9 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange = (e) => {
|
onChange = (e) => {
|
||||||
const [ tokenStart, token ] = textAtCursorMatchesToken(e.target.value, e.target.selectionStart, this.props.searchTokens);
|
const [tokenStart, token] = textAtCursorMatchesToken(e.target.value, e.target.selectionStart, this.props.searchTokens);
|
||||||
|
|
||||||
console.log('onChange', e.target.value, e.target, this.textbox, tokenStart, token)
|
// console.log('onChange', e.target.value, e.target, this.textbox, tokenStart, token)
|
||||||
|
|
||||||
if (token !== null && this.state.lastToken !== token) {
|
if (token !== null && this.state.lastToken !== token) {
|
||||||
this.setState({ lastToken: token, selectedSuggestion: 0, tokenStart });
|
this.setState({ lastToken: token, selectedSuggestion: 0, tokenStart });
|
||||||
|
@ -80,40 +81,40 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||||
// e.key may be a name of the physical key even in this case (e.x. Safari / Chrome on Mac)
|
// e.key may be a name of the physical key even in this case (e.x. Safari / Chrome on Mac)
|
||||||
if (e.which === 229 || e.isComposing) return;
|
if (e.which === 229 || e.isComposing) return;
|
||||||
|
|
||||||
switch(e.key) {
|
switch (e.key) {
|
||||||
case 'Escape':
|
case 'Escape':
|
||||||
if (suggestions.size === 0 || suggestionsHidden) {
|
if (suggestions.size === 0 || suggestionsHidden) {
|
||||||
document.querySelector('.ui').parentElement.focus();
|
document.querySelector('.ui').parentElement.focus();
|
||||||
} else {
|
} else {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.setState({ suggestionsHidden: true });
|
this.setState({ suggestionsHidden: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'ArrowDown':
|
case 'ArrowDown':
|
||||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) });
|
this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) });
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'ArrowUp':
|
case 'ArrowUp':
|
||||||
if (suggestions.size > 0 && !suggestionsHidden) {
|
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) });
|
this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) });
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
case 'Tab':
|
case 'Tab':
|
||||||
// Select suggestion
|
// Select suggestion
|
||||||
if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) {
|
if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion));
|
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.defaultPrevented || !this.props.onKeyDown) return;
|
if (e.defaultPrevented || !this.props.onKeyDown) return;
|
||||||
|
@ -151,7 +152,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||||
this.textbox.focus();
|
this.textbox.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps (nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) {
|
if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) {
|
||||||
this.setState({ suggestionsHidden: false });
|
this.setState({ suggestionsHidden: false });
|
||||||
}
|
}
|
||||||
|
@ -194,7 +195,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||||
this.textbox = c;
|
this.textbox = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render() {
|
||||||
const {
|
const {
|
||||||
value,
|
value,
|
||||||
small,
|
small,
|
||||||
|
@ -245,13 +246,18 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||||
// tabindex="0"
|
// tabindex="0"
|
||||||
// no-focuscontainer-refocus="true"
|
// no-focuscontainer-refocus="true"
|
||||||
// style="outline: none; user-select: text; white-space: pre-wrap; overflow-wrap: break-word;">
|
// style="outline: none; user-select: text; white-space: pre-wrap; overflow-wrap: break-word;">
|
||||||
|
|
||||||
if (textarea) {
|
if (textarea) {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className={[_s.default, _s.flexGrow1].join(' ')}>
|
<div className={[_s.default, _s.flexGrow1].join(' ')}>
|
||||||
<div className={[_s.default, _s.ml5].join(' ')}>
|
<div className={[_s.default, _s.ml5].join(' ')}>
|
||||||
<Textarea
|
|
||||||
|
<Composer
|
||||||
|
/>
|
||||||
|
|
||||||
|
{ /*
|
||||||
|
<Textarea
|
||||||
className={_s.default}
|
className={_s.default}
|
||||||
inputRef={this.setTextbox}
|
inputRef={this.setTextbox}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
@ -282,6 +288,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
|
||||||
onBlur={this.onBlur}
|
onBlur={this.onBlur}
|
||||||
onPaste={this.onPaste}
|
onPaste={this.onPaste}
|
||||||
/>
|
/>
|
||||||
|
*/ }
|
||||||
</div>
|
</div>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import {
|
||||||
|
Editor,
|
||||||
|
EditorState,
|
||||||
|
RichUtils
|
||||||
|
} from 'draft-js'
|
||||||
|
|
||||||
|
export default class Composer extends PureComponent {
|
||||||
|
|
||||||
|
state = {
|
||||||
|
editorState: EditorState.createEmpty(),
|
||||||
|
}
|
||||||
|
|
||||||
|
onChange = (editorState) => {
|
||||||
|
this.setState({ editorState })
|
||||||
|
}
|
||||||
|
|
||||||
|
onBoldClick() {
|
||||||
|
this.onChange(RichUtils.toggleInlineStyle(this.state.editorState, 'BOLD'));
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
|
||||||
|
{/*<button onClick={this.onBoldClick.bind(this)}>Bold</button>*/}
|
||||||
|
|
||||||
|
<Editor
|
||||||
|
editorState={this.state.editorState}
|
||||||
|
onChange={this.onChange}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
import { NavLink, withRouter } from 'react-router-dom';
|
import { NavLink, withRouter } from 'react-router-dom';
|
||||||
import { FormattedMessage, injectIntl } from 'react-intl';
|
import { FormattedMessage, injectIntl } from 'react-intl';
|
||||||
import NotificationCounter from '../notification_counter';
|
import NotificationCounter from '../notification_counter';
|
||||||
import { me } from '../../initial_state';
|
|
||||||
|
|
||||||
const links = [
|
const links = [
|
||||||
<NavLink key='pr1' className='footer-bar__link' to='/home' data-preview-title-id='column.home'>
|
<NavLink key='pr1' className='footer-bar__link' to='/home' data-preview-title-id='column.home'>
|
||||||
|
@ -39,8 +38,6 @@ class FooterBar extends PureComponent {
|
||||||
render() {
|
render() {
|
||||||
const { intl: { formatMessage } } = this.props;
|
const { intl: { formatMessage } } = this.props;
|
||||||
|
|
||||||
if (!me) return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='footer-bar'>
|
<div className='footer-bar'>
|
||||||
<div className='footer-bar__container'>
|
<div className='footer-bar__container'>
|
|
@ -1,45 +0,0 @@
|
||||||
.footer-bar {
|
|
||||||
display: block;
|
|
||||||
position: fixed;
|
|
||||||
background: #000;
|
|
||||||
height: 58px;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
transition: transform 0.2s ease;
|
|
||||||
overflow: hidden;
|
|
||||||
padding-bottom: 0;
|
|
||||||
padding-bottom: env(safe-area-inset-bottom);
|
|
||||||
|
|
||||||
@media screen and (min-width: 895px) {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__link {
|
|
||||||
display: flex;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
margin: 0;
|
|
||||||
min-width: 36px;
|
|
||||||
height: 58px;
|
|
||||||
padding-top: 4px;
|
|
||||||
justify-content: center;
|
|
||||||
color: white;
|
|
||||||
text-decoration: none;
|
|
||||||
border-top: 2px solid transparent;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
border-top-color: $gab-brand-default;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > span {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './footer_bar'
|
|
|
@ -45,6 +45,8 @@ export default class Icon extends PureComponent {
|
||||||
return <I.GlobeIcon {...options} />
|
return <I.GlobeIcon {...options} />
|
||||||
case 'group':
|
case 'group':
|
||||||
return <I.GroupIcon {...options} />
|
return <I.GroupIcon {...options} />
|
||||||
|
case 'group-add':
|
||||||
|
return <I.GroupAddIcon {...options} />
|
||||||
case 'happy':
|
case 'happy':
|
||||||
return <I.HappyIcon {...options} />
|
return <I.HappyIcon {...options} />
|
||||||
case 'home':
|
case 'home':
|
||||||
|
@ -55,6 +57,8 @@ export default class Icon extends PureComponent {
|
||||||
return <I.LinkIcon {...options} />
|
return <I.LinkIcon {...options} />
|
||||||
case 'list':
|
case 'list':
|
||||||
return <I.ListIcon {...options} />
|
return <I.ListIcon {...options} />
|
||||||
|
case 'list-add':
|
||||||
|
return <I.ListAddIcon {...options} />
|
||||||
case 'loading':
|
case 'loading':
|
||||||
return <I.LoadingIcon {...options} />
|
return <I.LoadingIcon {...options} />
|
||||||
case 'media':
|
case 'media':
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import Block from './block'
|
import Block from './block'
|
||||||
import ScrollableList from './scrollable_list'
|
import ScrollableList from './scrollable_list'
|
||||||
import ListItem from './list_item'
|
import ListItem from './list_item'
|
||||||
|
|
||||||
export default class List extends PureComponent {
|
export default class List extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
items: PropTypes.array,
|
items: PropTypes.array,
|
||||||
|
@ -21,16 +22,14 @@ export default class List extends PureComponent {
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
items.map((item, i) => {
|
items.map((item, i) => (
|
||||||
return (
|
<ListItem
|
||||||
<ListItem
|
small={small}
|
||||||
small={small}
|
key={`list-item-${i}`}
|
||||||
key={`list-item-${i}`}
|
isLast={items.size - 1 === i}
|
||||||
isLast={items.length - 1 === i}
|
{...item}
|
||||||
{...item}
|
/>
|
||||||
/>
|
))
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
</ScrollableList>
|
</ScrollableList>
|
||||||
</Block>
|
</Block>
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
import { defineMessages, injectIntl } from 'react-intl'
|
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
|
||||||
import Button from '../button'
|
|
||||||
import Text from '../text'
|
|
||||||
import ModalLayout from './modal_layout'
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
title: { id: 'promo.gab_pro', defaultMessage: 'Upgrade to GabPRO' },
|
|
||||||
text: { id: 'pro_upgrade_modal.text', defaultMessage: 'Gab is fully funded by people like you. Please consider supporting us on our mission to defend free expression online for all people.' },
|
|
||||||
benefits: { id: 'pro_upgrade_modal.benefits', defaultMessage: 'Here are just some of the benefits that thousands of GabPRO members receive:' },
|
|
||||||
})
|
|
||||||
|
|
||||||
export default
|
|
||||||
@injectIntl
|
|
||||||
class HomeTimelineSettingsModal extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { intl } = this.props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Text>
|
|
||||||
{intl.formatMessage(messages.text)}
|
|
||||||
</Text>
|
|
||||||
<Text>
|
|
||||||
{intl.formatMessage(messages.benefits)}
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<div className={[_s.default, _s.my10].join(' ')}>
|
|
||||||
<Text>• Schedule Posts</Text>
|
|
||||||
<Text>• Get Verified</Text>
|
|
||||||
<Text>• Create Groups</Text>
|
|
||||||
<Text>• Larger Video and Image Uploads</Text>
|
|
||||||
<Text>• Receive the PRO Badge</Text>
|
|
||||||
<Text>• Remove in-feed promotions</Text>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
centered
|
|
||||||
backgroundColor='brand'
|
|
||||||
color='white'
|
|
||||||
icon='pro'
|
|
||||||
href='https://pro.gab.com'
|
|
||||||
className={_s.justifyContentCenter}
|
|
||||||
iconClassName={[_s.mr5, _s.fillColorWhite].join(' ')}
|
|
||||||
>
|
|
||||||
<Text color='inherit' weight='bold' align='center'>
|
|
||||||
{intl.formatMessage(messages.title)}
|
|
||||||
</Text>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { injectIntl, defineMessages } from 'react-intl'
|
import { injectIntl, defineMessages } from 'react-intl'
|
||||||
import { makeGetAccount } from '../../selectors'
|
import { makeGetAccount } from '../../selectors'
|
||||||
import { closeModal } from '../../actions/modal'
|
|
||||||
import { blockAccount } from '../../actions/accounts'
|
import { blockAccount } from '../../actions/accounts'
|
||||||
import ConfirmationModal from './confirmation_modal'
|
import ConfirmationModal from './confirmation_modal'
|
||||||
|
|
||||||
|
@ -23,9 +22,6 @@ const mapDispatchToProps = dispatch => {
|
||||||
onConfirm(account) {
|
onConfirm(account) {
|
||||||
dispatch(blockAccount(account.get('id')))
|
dispatch(blockAccount(account.get('id')))
|
||||||
},
|
},
|
||||||
onClose() {
|
|
||||||
dispatch(closeModal())
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +33,6 @@ class BlockAccountModal extends PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
account: PropTypes.object.isRequired,
|
account: PropTypes.object.isRequired,
|
||||||
onConfirm: PropTypes.func.isRequired,
|
onConfirm: PropTypes.func.isRequired,
|
||||||
onClose: PropTypes.func.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,10 +40,6 @@ class BlockAccountModal extends PureComponent {
|
||||||
this.props.onConfirm(this.props.account)
|
this.props.onConfirm(this.props.account)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClose = () => {
|
|
||||||
this.props.onClose()
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { account, intl } = this.props
|
const { account, intl } = this.props
|
||||||
|
|
||||||
|
@ -64,7 +55,6 @@ class BlockAccountModal extends PureComponent {
|
||||||
title={title}
|
title={title}
|
||||||
message={message}
|
message={message}
|
||||||
confirm={intl.formatMessage(messages.block)}
|
confirm={intl.formatMessage(messages.block)}
|
||||||
onClose={this.handleClose}
|
|
||||||
onConfirm={this.handleClick}
|
onConfirm={this.handleClick}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
|
import { closeModal } from '../../actions/modal'
|
||||||
|
import { changeSetting, saveSettings } from '../../actions/settings'
|
||||||
|
import ModalLayout from './modal_layout'
|
||||||
|
import Button from '../button'
|
||||||
|
import SettingSwitch from '../setting_switch'
|
||||||
|
import Text from '../text'
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
title: { id: 'community_timeline_settings', defaultMessage: 'Community Timeline Settings' },
|
||||||
|
saveAndClose: { id: 'saveClose', defaultMessage: 'Save & Close' },
|
||||||
|
onlyMedia: { id: 'community.column_settings.media_only', defaultMessage: 'Media Only' },
|
||||||
|
showInSidebar: { id: 'show_in_sidebar', defaultMessage: 'Show in Sidebar' },
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
settings: state.getIn(['settings', 'community']),
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
onChange(key, checked) {
|
||||||
|
dispatch(changeSetting(['community', ...key], checked))
|
||||||
|
},
|
||||||
|
onSave() {
|
||||||
|
dispatch(saveSettings())
|
||||||
|
dispatch(closeModal())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default
|
||||||
|
@connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
@injectIntl
|
||||||
|
class CommunityTimelineSettingsModal extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
settings: ImmutablePropTypes.map.isRequired,
|
||||||
|
onChange: PropTypes.func.isRequired,
|
||||||
|
onSave: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSaveAndClose = () => {
|
||||||
|
this.props.onSave()
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { intl, settings, onChange } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalLayout
|
||||||
|
width='320'
|
||||||
|
title={intl.formatMessage(messages.title)}
|
||||||
|
>
|
||||||
|
|
||||||
|
<div className={[_s.default, _s.pb10].join(' ')}>
|
||||||
|
<SettingSwitch
|
||||||
|
prefix='community_timeline'
|
||||||
|
settings={settings}
|
||||||
|
settingPath={['shows', 'inSidebar']}
|
||||||
|
onChange={onChange}
|
||||||
|
label={intl.formatMessage(messages.showInSidebar)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingSwitch
|
||||||
|
prefix='community_timeline'
|
||||||
|
settings={settings}
|
||||||
|
settingPath={['shows', 'onlyMedia']}
|
||||||
|
onChange={onChange}
|
||||||
|
label={intl.formatMessage(messages.onlyMedia)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
centered
|
||||||
|
backgroundColor='brand'
|
||||||
|
color='white'
|
||||||
|
className={_s.justifyContentCenter}
|
||||||
|
onClick={this.handleSaveAndClose}
|
||||||
|
>
|
||||||
|
<Text color='inherit' weight='bold' align='center'>
|
||||||
|
{intl.formatMessage(messages.saveAndClose)}
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</ModalLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,72 +0,0 @@
|
||||||
import { injectIntl, defineMessages } from 'react-intl'
|
|
||||||
import { muteAccount } from '../../actions/accounts'
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
muteMessage: { id: 'confirmations.mute.message', defaultMessage: 'Are you sure you want to mute {name}?' },
|
|
||||||
cancel: { id: 'confirmation_modal.cancel', defaultMessage: 'Cancel' },
|
|
||||||
confirm: { id: 'confirmations.mute.confirm', defaultMessage: 'Mute' },
|
|
||||||
})
|
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
|
||||||
return {
|
|
||||||
isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']),
|
|
||||||
account: state.getIn(['mutes', 'new', 'account']),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
|
||||||
return {
|
|
||||||
onConfirm(account, notifications) {
|
|
||||||
dispatch(muteAccount(account.get('id'), notifications))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default
|
|
||||||
@connect(mapStateToProps, mapDispatchToProps)
|
|
||||||
@injectIntl
|
|
||||||
class UnfollowModal extends PureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
isSubmitting: PropTypes.bool.isRequired,
|
|
||||||
account: PropTypes.object.isRequired,
|
|
||||||
onConfirm: PropTypes.func.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.button.focus()
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClick = () => {
|
|
||||||
this.props.onClose()
|
|
||||||
this.props.onConfirm(this.props.account, this.props.notifications)
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCancel = () => {
|
|
||||||
this.props.onClose()
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { account, intl } = this.props
|
|
||||||
|
|
||||||
// , {
|
|
||||||
// message: <FormattedMessage id='confirmations.unfollow.message' defaultMessage='Are you sure you want to unfollow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
|
||||||
// confirm: intl.formatMessage(messages.unfollowConfirm),
|
|
||||||
// onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
|
|
||||||
// }));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ConfirmationModal
|
|
||||||
title={`Mute @${account.get('acct')}`}
|
|
||||||
message={<FormattedMessage id='confirmations.mute.message' defaultMessage='Are you sure you want to mute @{name}?' values={{ name: account.get('acct') }} />}
|
|
||||||
confirm={<FormattedMessage id='mute' defaultMessage='Mute' />}
|
|
||||||
onConfirm={() => {
|
|
||||||
// dispatch(blockDomain(domain))
|
|
||||||
// dispatch(blockDomain(domain))
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
|
import ModalLayout from './modal_layout'
|
||||||
|
import GroupCreate from '../../features/group_create'
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
title: { id: 'create_group', defaultMessage: 'Create Group' },
|
||||||
|
})
|
||||||
|
|
||||||
|
export default
|
||||||
|
@injectIntl
|
||||||
|
class GroupCreateModal extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { intl } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalLayout
|
||||||
|
title={intl.formatMessage(messages.title)}
|
||||||
|
width='440'
|
||||||
|
>
|
||||||
|
<GroupCreate />
|
||||||
|
</ModalLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
import { injectIntl, defineMessages } from 'react-intl'
|
||||||
|
import { makeGetAccount } from '../../selectors'
|
||||||
|
import { blockAccount } from '../../actions/accounts'
|
||||||
|
import ConfirmationModal from './confirmation_modal'
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
title: { id: 'group_delete_title', defaultMessage: 'Delete "{group}"' },
|
||||||
|
groupMessage: { id: 'confirmations.group_delete.message', defaultMessage: 'Are you sure you want to delete "{group}"?' },
|
||||||
|
delete: { id: 'delete', defaultMessage: 'Delete' },
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
onConfirm(account) {
|
||||||
|
// dispatch(blockAccount(account.get('id')))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default
|
||||||
|
@connect(null, mapDispatchToProps)
|
||||||
|
@injectIntl
|
||||||
|
class GroupDeleteModal extends PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
group: PropTypes.object.isRequired,
|
||||||
|
onConfirm: PropTypes.func.isRequired,
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClick = () => {
|
||||||
|
this.props.onConfirm(this.props.account)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { group, intl } = this.props
|
||||||
|
|
||||||
|
const title = intl.formatMessage(messages.title, {
|
||||||
|
group: !!group ? account.get('title') : '',
|
||||||
|
})
|
||||||
|
const message = intl.formatMessage(messages.groupMessage, {
|
||||||
|
group: !!group ? account.get('title') : '',
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfirmationModal
|
||||||
|
title={title}
|
||||||
|
message={message}
|
||||||
|
confirm={intl.formatMessage(messages.delete)}
|
||||||
|
onConfirm={this.handleClick}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -59,7 +59,7 @@ class HomeTimelineSettingsModal extends ImmutablePureComponent {
|
||||||
title={intl.formatMessage(messages.title)}
|
title={intl.formatMessage(messages.title)}
|
||||||
>
|
>
|
||||||
|
|
||||||
<div className={[_s.default, _s.my10, _s.pb10].join(' ')}>
|
<div className={[_s.default, _s.pb10].join(' ')}>
|
||||||
<SettingSwitch
|
<SettingSwitch
|
||||||
prefix='home_timeline'
|
prefix='home_timeline'
|
||||||
settings={settings}
|
settings={settings}
|
||||||
|
|
|
@ -26,7 +26,6 @@ const messages = defineMessages({
|
||||||
unfocus: { id: 'keyboard_shortcuts.unfocus', defaultMessage: 'un-focus compose textarea/search' },
|
unfocus: { id: 'keyboard_shortcuts.unfocus', defaultMessage: 'un-focus compose textarea/search' },
|
||||||
home: { id: 'keyboard_shortcuts.home', defaultMessage: 'open home timeline' },
|
home: { id: 'keyboard_shortcuts.home', defaultMessage: 'open home timeline' },
|
||||||
notifications: { id: 'keyboard_shortcuts.notifications', defaultMessage: 'open notifications column' },
|
notifications: { id: 'keyboard_shortcuts.notifications', defaultMessage: 'open notifications column' },
|
||||||
direct: { id: 'keyboard_shortcuts.direct', defaultMessage: 'open direct messages column' },
|
|
||||||
start: { id: 'keyboard_shortcuts.start', defaultMessage: 'open "get started" column' },
|
start: { id: 'keyboard_shortcuts.start', defaultMessage: 'open "get started" column' },
|
||||||
favorites: { id: 'keyboard_shortcuts.favorites', defaultMessage: 'open favorites list' },
|
favorites: { id: 'keyboard_shortcuts.favorites', defaultMessage: 'open favorites list' },
|
||||||
pinned: { id: 'keyboard_shortcuts.pinned', defaultMessage: 'open pinned gabs list' },
|
pinned: { id: 'keyboard_shortcuts.pinned', defaultMessage: 'open pinned gabs list' },
|
||||||
|
@ -93,7 +92,6 @@ class HotkeysModal extends ImmutablePureComponent {
|
||||||
<HotKeysModalRow hotkey='esc' action={intl.formatMessage(messages.unfocus)} />
|
<HotKeysModalRow hotkey='esc' action={intl.formatMessage(messages.unfocus)} />
|
||||||
<HotKeysModalRow hotkey='g + h' action={intl.formatMessage(messages.home)} />
|
<HotKeysModalRow hotkey='g + h' action={intl.formatMessage(messages.home)} />
|
||||||
<HotKeysModalRow hotkey='g + n' action={intl.formatMessage(messages.notifications)} />
|
<HotKeysModalRow hotkey='g + n' action={intl.formatMessage(messages.notifications)} />
|
||||||
<HotKeysModalRow hotkey='g + d' action={intl.formatMessage(messages.direct)} />
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<table>
|
<table>
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
import { injectIntl, defineMessages } from 'react-intl'
|
|
||||||
import { muteAccount } from '../../actions/accounts'
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
muteMessage: { id: 'confirmations.mute.message', defaultMessage: 'Are you sure you want to mute {name}?' },
|
|
||||||
cancel: { id: 'confirmation_modal.cancel', defaultMessage: 'Cancel' },
|
|
||||||
confirm: { id: 'confirmations.mute.confirm', defaultMessage: 'Mute' },
|
|
||||||
})
|
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
|
||||||
return {
|
|
||||||
isSubmitting: state.getIn(['reports', 'new', 'isSubmitting']),
|
|
||||||
account: state.getIn(['mutes', 'new', 'account']),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
|
||||||
return {
|
|
||||||
onConfirm(account, notifications) {
|
|
||||||
dispatch(muteAccount(account.get('id'), notifications))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default
|
|
||||||
@connect(mapStateToProps, mapDispatchToProps)
|
|
||||||
@injectIntl
|
|
||||||
class UnfollowModal extends PureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
isSubmitting: PropTypes.bool.isRequired,
|
|
||||||
account: PropTypes.object.isRequired,
|
|
||||||
onConfirm: PropTypes.func.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.button.focus()
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClick = () => {
|
|
||||||
this.props.onClose()
|
|
||||||
this.props.onConfirm(this.props.account, this.props.notifications)
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCancel = () => {
|
|
||||||
this.props.onClose()
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { account, intl } = this.props
|
|
||||||
|
|
||||||
// , {
|
|
||||||
// message: <FormattedMessage id='confirmations.unfollow.message' defaultMessage='Are you sure you want to unfollow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
|
||||||
// confirm: intl.formatMessage(messages.unfollowConfirm),
|
|
||||||
// onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
|
|
||||||
// }));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ConfirmationModal
|
|
||||||
title={`Mute @${account.get('acct')}`}
|
|
||||||
message={<FormattedMessage id='confirmations.mute.message' defaultMessage='Are you sure you want to mute @{name}?' values={{ name: account.get('acct') }} />}
|
|
||||||
confirm={<FormattedMessage id='mute' defaultMessage='Mute' />}
|
|
||||||
onConfirm={() => {
|
|
||||||
// dispatch(blockDomain(domain))
|
|
||||||
// dispatch(blockDomain(domain))
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
|
import ModalLayout from './modal_layout'
|
||||||
|
import ListCreate from '../../features/list_create'
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
title: { id: 'create_list', defaultMessage: 'Create List' },
|
||||||
|
})
|
||||||
|
|
||||||
|
export default
|
||||||
|
@injectIntl
|
||||||
|
class ListCreateModal extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { intl } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalLayout
|
||||||
|
title={intl.formatMessage(messages.title)}
|
||||||
|
width='500'
|
||||||
|
>
|
||||||
|
<ListCreate />
|
||||||
|
</ModalLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
import { injectIntl, defineMessages } from 'react-intl'
|
||||||
|
import { makeGetAccount } from '../../selectors'
|
||||||
|
import { blockAccount } from '../../actions/accounts'
|
||||||
|
import ConfirmationModal from './confirmation_modal'
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
title: { id: 'list_delete_title', defaultMessage: 'Delete "{list}"' },
|
||||||
|
listMessage: { id: 'confirmations.list_delete.message', defaultMessage: 'Are you sure you want to delete "{list}"?' },
|
||||||
|
delete: { id: 'delete', defaultMessage: 'Delete' },
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
onConfirm(account) {
|
||||||
|
// dispatch(blockAccount(account.get('id')))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default
|
||||||
|
@connect(null, mapDispatchToProps)
|
||||||
|
@injectIntl
|
||||||
|
class ListDeleteModal extends PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
list: PropTypes.object.isRequired,
|
||||||
|
onConfirm: PropTypes.func.isRequired,
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClick = () => {
|
||||||
|
this.props.onConfirm(this.props.account)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { list, intl } = this.props
|
||||||
|
|
||||||
|
const title = intl.formatMessage(messages.title, {
|
||||||
|
list: !!list ? account.get('title') : '',
|
||||||
|
})
|
||||||
|
const message = intl.formatMessage(messages.listMessage, {
|
||||||
|
list: !!list ? account.get('title') : '',
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ConfirmationModal
|
||||||
|
title={title}
|
||||||
|
message={message}
|
||||||
|
confirm={intl.formatMessage(messages.delete)}
|
||||||
|
onConfirm={this.handleClick}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
|
import { closeModal } from '../../actions/modal'
|
||||||
|
import { changeSetting, saveSettings } from '../../actions/settings'
|
||||||
|
import ModalLayout from './modal_layout'
|
||||||
|
import Button from '../button'
|
||||||
|
import SettingSwitch from '../setting_switch'
|
||||||
|
import Text from '../text'
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
title: { id: 'list_timeline_settings', defaultMessage: 'List Timeline Settings' },
|
||||||
|
saveAndClose: { id: 'saveClose', defaultMessage: 'Save & Close' },
|
||||||
|
showVideos: { id: 'home.column_settings.show_videos', defaultMessage: 'Show videos' },
|
||||||
|
showPhotos: { id: 'home.column_settings.show_photos', defaultMessage: 'Show photos' },
|
||||||
|
showPolls: { id: 'home.column_settings.show_polls', defaultMessage: 'Show polls' },
|
||||||
|
showReposts: { id: 'home.column_settings.show_reposts', defaultMessage: 'Show comments' },
|
||||||
|
showReplies: { id: 'home.column_settings.show_replies', defaultMessage: 'Show replies' },
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapStateToProps = state => ({
|
||||||
|
settings: state.getIn(['settings', 'list']),
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
onChange(key, checked) {
|
||||||
|
dispatch(changeSetting(['list', ...key], checked))
|
||||||
|
},
|
||||||
|
onSave() {
|
||||||
|
dispatch(saveSettings())
|
||||||
|
dispatch(closeModal())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default
|
||||||
|
@connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
@injectIntl
|
||||||
|
class ListTimelineSettingsModal extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
settings: ImmutablePropTypes.map.isRequired,
|
||||||
|
onChange: PropTypes.func.isRequired,
|
||||||
|
onSave: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSaveAndClose = () => {
|
||||||
|
this.props.onSave()
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { intl, settings, onChange } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalLayout
|
||||||
|
width='320'
|
||||||
|
title={intl.formatMessage(messages.title)}
|
||||||
|
>
|
||||||
|
|
||||||
|
<div className={[_s.default, _s.pb10].join(' ')}>
|
||||||
|
<SettingSwitch
|
||||||
|
prefix='list_timeline'
|
||||||
|
settings={settings}
|
||||||
|
settingPath={['shows', 'polls']}
|
||||||
|
onChange={onChange}
|
||||||
|
label={intl.formatMessage(messages.showPolls)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingSwitch
|
||||||
|
prefix='list_timeline'
|
||||||
|
settings={settings}
|
||||||
|
settingPath={['shows', 'photos']}
|
||||||
|
onChange={onChange}
|
||||||
|
label={intl.formatMessage(messages.showPhotos)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingSwitch
|
||||||
|
prefix='list_timeline'
|
||||||
|
settings={settings}
|
||||||
|
settingPath={['shows', 'videos']}
|
||||||
|
onChange={onChange}
|
||||||
|
label={intl.formatMessage(messages.showVideos)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingSwitch
|
||||||
|
prefix='list_timeline'
|
||||||
|
settings={settings}
|
||||||
|
settingPath={['shows', 'repost']}
|
||||||
|
onChange={onChange}
|
||||||
|
label={intl.formatMessage(messages.showReposts)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SettingSwitch
|
||||||
|
prefix='list_timeline'
|
||||||
|
settings={settings}
|
||||||
|
settingPath={['shows', 'reply']}
|
||||||
|
onChange={onChange}
|
||||||
|
label={intl.formatMessage(messages.showReplies)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
centered
|
||||||
|
backgroundColor='brand'
|
||||||
|
color='white'
|
||||||
|
className={_s.justifyContentCenter}
|
||||||
|
onClick={this.handleSaveAndClose}
|
||||||
|
>
|
||||||
|
<Text color='inherit' weight='bold' align='center'>
|
||||||
|
{intl.formatMessage(messages.saveAndClose)}
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</ModalLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import { defineMessages, injectIntl } from 'react-intl'
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
import classNames from 'classnames/bind'
|
import classNames from 'classnames/bind'
|
||||||
|
import { closeModal } from '../../actions/modal'
|
||||||
import Button from '../button'
|
import Button from '../button'
|
||||||
import Block from '../block'
|
import Block from '../block'
|
||||||
import Heading from '../heading'
|
import Heading from '../heading'
|
||||||
|
@ -10,13 +11,23 @@ const messages = defineMessages({
|
||||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
handleCloseModal() {
|
||||||
|
dispatch(closeModal())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default
|
export default
|
||||||
|
@connect(null, mapDispatchToProps)
|
||||||
@injectIntl
|
@injectIntl
|
||||||
class ModalLayout extends PureComponent {
|
class ModalLayout extends PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
onClose: PropTypes.func.isRequired,
|
onClose: PropTypes.func.isRequired,
|
||||||
|
handleCloseModal: PropTypes.func.isRequired,
|
||||||
width: PropTypes.number,
|
width: PropTypes.number,
|
||||||
hideClose: PropTypes.bool,
|
hideClose: PropTypes.bool,
|
||||||
noPadding: PropTypes.bool,
|
noPadding: PropTypes.bool,
|
||||||
|
@ -26,12 +37,19 @@ class ModalLayout extends PureComponent {
|
||||||
width: 600,
|
width: 600,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onHandleCloseModal = () => {
|
||||||
|
if (this.props.onClose) {
|
||||||
|
this.props.onClose();
|
||||||
|
} else {
|
||||||
|
this.props.handleCloseModal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
children,
|
children,
|
||||||
intl,
|
intl,
|
||||||
onClose,
|
|
||||||
width,
|
width,
|
||||||
hideClose,
|
hideClose,
|
||||||
noPadding
|
noPadding
|
||||||
|
@ -39,6 +57,8 @@ class ModalLayout extends PureComponent {
|
||||||
|
|
||||||
const childrenContainerClasses = cx({
|
const childrenContainerClasses = cx({
|
||||||
default: 1,
|
default: 1,
|
||||||
|
heightMax80VH: 1,
|
||||||
|
overflowScroll: 1,
|
||||||
px15: !noPadding,
|
px15: !noPadding,
|
||||||
py10: !noPadding,
|
py10: !noPadding,
|
||||||
})
|
})
|
||||||
|
@ -56,7 +76,7 @@ class ModalLayout extends PureComponent {
|
||||||
backgroundColor='none'
|
backgroundColor='none'
|
||||||
title={intl.formatMessage(messages.close)}
|
title={intl.formatMessage(messages.close)}
|
||||||
className={_s.marginLeftAuto}
|
className={_s.marginLeftAuto}
|
||||||
onClick={onClose}
|
onClick={this.onHandleCloseModal}
|
||||||
icon='close'
|
icon='close'
|
||||||
iconWidth='10px'
|
iconWidth='10px'
|
||||||
iconWidth='10px'
|
iconWidth='10px'
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
// ListEditor,
|
// ListEditor,
|
||||||
// ListAdder,
|
// ListAdder,
|
||||||
StatusRevisionModal,
|
StatusRevisionModal,
|
||||||
} from '../../features/ui/util/async-components'
|
} from '../../features/ui/util/async_components'
|
||||||
|
|
||||||
import ModalBase from './modal_base'
|
import ModalBase from './modal_base'
|
||||||
import BundleModalError from '../bundle_modal_error'
|
import BundleModalError from '../bundle_modal_error'
|
||||||
|
@ -17,14 +17,18 @@ import ActionsModal from './actions_modal'
|
||||||
import BlockAccountModal from './block_account_modal'
|
import BlockAccountModal from './block_account_modal'
|
||||||
import BlockDomainModal from './block_domain_modal'
|
import BlockDomainModal from './block_domain_modal'
|
||||||
import BoostModal from './boost_modal'
|
import BoostModal from './boost_modal'
|
||||||
|
import CommunityTimelineSettingsModal from './community_timeline_settings_modal'
|
||||||
import ComposeModal from './compose_modal'
|
import ComposeModal from './compose_modal'
|
||||||
import ConfirmationModal from './confirmation_modal'
|
import ConfirmationModal from './confirmation_modal'
|
||||||
import GroupAdderModal from './group_adder_modal'
|
import GroupCreateModal from './group_create_modal'
|
||||||
|
import GroupDeleteModal from './group_delete_modal'
|
||||||
import GroupEditorModal from './group_editor_modal'
|
import GroupEditorModal from './group_editor_modal'
|
||||||
import HomeTimelineSettingsModal from './home_timeline_settings_modal'
|
import HomeTimelineSettingsModal from './home_timeline_settings_modal'
|
||||||
import HotkeysModal from './hotkeys_modal'
|
import HotkeysModal from './hotkeys_modal'
|
||||||
import ListAdderModal from './list_adder_modal'
|
import ListCreateModal from './list_create_modal'
|
||||||
|
import ListDeleteModal from './list_delete_modal'
|
||||||
import ListEditorModal from './list_editor_modal'
|
import ListEditorModal from './list_editor_modal'
|
||||||
|
import ListTimelineSettingsModal from './list_timeline_settings_modal'
|
||||||
import MediaModal from './media_modal'
|
import MediaModal from './media_modal'
|
||||||
import ModalLoading from './modal_loading'
|
import ModalLoading from './modal_loading'
|
||||||
import ProUpgradeModal from './pro_upgrade_modal'
|
import ProUpgradeModal from './pro_upgrade_modal'
|
||||||
|
@ -37,15 +41,19 @@ const MODAL_COMPONENTS = {
|
||||||
BLOCK_ACCOUNT: () => Promise.resolve({ default: BlockAccountModal }),
|
BLOCK_ACCOUNT: () => Promise.resolve({ default: BlockAccountModal }),
|
||||||
BLOCK_DOMAIN: () => Promise.resolve({ default: BlockDomainModal }),
|
BLOCK_DOMAIN: () => Promise.resolve({ default: BlockDomainModal }),
|
||||||
BOOST: () => Promise.resolve({ default: BoostModal }),
|
BOOST: () => Promise.resolve({ default: BoostModal }),
|
||||||
|
COMMUNITY_TIMELINE_SETTINGS: () => Promise.resolve({ default: CommunityTimelineSettingsModal }),
|
||||||
COMPOSE: () => Promise.resolve({ default: ComposeModal }),
|
COMPOSE: () => Promise.resolve({ default: ComposeModal }),
|
||||||
CONFIRM: () => Promise.resolve({ default: ConfirmationModal }),
|
CONFIRM: () => Promise.resolve({ default: ConfirmationModal }),
|
||||||
EMBED: () => Promise.resolve({ default: EmbedModal }),
|
EMBED: () => Promise.resolve({ default: EmbedModal }),
|
||||||
|
GROUP_CREATE: () => Promise.resolve({ default: GroupCreateModal }),
|
||||||
|
GROUP_DELETE: () => Promise.resolve({ default: GroupDeleteModal }),
|
||||||
GROUP_EDITOR: () => Promise.resolve({ default: GroupEditorModal }),
|
GROUP_EDITOR: () => Promise.resolve({ default: GroupEditorModal }),
|
||||||
GROUP_ADDER: () => Promise.resolve({ default: GroupAdderModal }),
|
|
||||||
HOME_TIMELINE_SETTINGS: () => Promise.resolve({ default: HomeTimelineSettingsModal }),
|
HOME_TIMELINE_SETTINGS: () => Promise.resolve({ default: HomeTimelineSettingsModal }),
|
||||||
HOTKEYS: () => Promise.resolve({ default: HotkeysModal }),
|
HOTKEYS: () => Promise.resolve({ default: HotkeysModal }),
|
||||||
|
LIST_CREATE: () => Promise.resolve({ default: ListCreateModal }),
|
||||||
|
LIST_DELETE: () => Promise.resolve({ default: ListDeleteModal }),
|
||||||
LIST_EDITOR: () => Promise.resolve({ default: ListEditorModal }),
|
LIST_EDITOR: () => Promise.resolve({ default: ListEditorModal }),
|
||||||
LIST_ADDER: () => Promise.resolve({ default: ListAdderModal }),
|
LIST_TIMELINE_SETTINGS: () => Promise.resolve({ default: ListTimelineSettingsModal }),
|
||||||
MEDIA: () => Promise.resolve({ default: MediaModal }),
|
MEDIA: () => Promise.resolve({ default: MediaModal }),
|
||||||
'MUTE': MuteModal,
|
'MUTE': MuteModal,
|
||||||
PRO_UPGRADE: () => Promise.resolve({ default: ProUpgradeModal }),
|
PRO_UPGRADE: () => Promise.resolve({ default: ProUpgradeModal }),
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { injectIntl, defineMessages } from 'react-intl'
|
import { injectIntl, defineMessages } from 'react-intl'
|
||||||
import { makeGetAccount } from '../../selectors'
|
import { makeGetAccount } from '../../selectors'
|
||||||
import { closeModal } from '../../actions/modal'
|
|
||||||
import { muteAccount } from '../../actions/accounts'
|
import { muteAccount } from '../../actions/accounts'
|
||||||
import ConfirmationModal from './confirmation_modal'
|
import ConfirmationModal from './confirmation_modal'
|
||||||
|
|
||||||
|
@ -21,12 +20,8 @@ const mapStateToProps = (state, { accountId }) => {
|
||||||
const mapDispatchToProps = dispatch => {
|
const mapDispatchToProps = dispatch => {
|
||||||
return {
|
return {
|
||||||
onConfirm(account, notifications) {
|
onConfirm(account, notifications) {
|
||||||
dispatch(closeModal())
|
|
||||||
dispatch(muteAccount(account.get('id'), notifications))
|
dispatch(muteAccount(account.get('id'), notifications))
|
||||||
},
|
},
|
||||||
onClose() {
|
|
||||||
dispatch(closeModal())
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +33,6 @@ class MuteModal extends PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
account: PropTypes.object.isRequired,
|
account: PropTypes.object.isRequired,
|
||||||
onConfirm: PropTypes.func.isRequired,
|
onConfirm: PropTypes.func.isRequired,
|
||||||
onClose: PropTypes.func.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,10 +40,6 @@ class MuteModal extends PureComponent {
|
||||||
this.props.onConfirm(this.props.account)
|
this.props.onConfirm(this.props.account)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClose = () => {
|
|
||||||
this.props.onClose()
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { account, intl } = this.props
|
const { account, intl } = this.props
|
||||||
|
|
||||||
|
@ -65,7 +55,6 @@ class MuteModal extends PureComponent {
|
||||||
title={title}
|
title={title}
|
||||||
message={message}
|
message={message}
|
||||||
confirm={intl.formatMessage(messages.mute)}
|
confirm={intl.formatMessage(messages.mute)}
|
||||||
onClose={this.handleClose}
|
|
||||||
onConfirm={this.handleClick}
|
onConfirm={this.handleClick}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
|
@ -22,7 +22,7 @@ class ProUpgradeModal extends ImmutablePureComponent {
|
||||||
const { intl } = this.props
|
const { intl } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalLayout title={intl.formatMessage(messages.title)}>
|
<ModalLayout title={intl.formatMessage(messages.title)} width='460'>
|
||||||
<Text>
|
<Text>
|
||||||
{intl.formatMessage(messages.text)}
|
{intl.formatMessage(messages.text)}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
|
@ -1,24 +1,31 @@
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
import { fetchSuggestions, dismissSuggestion } from '../../actions/suggestions';
|
import { fetchSuggestions, dismissSuggestion } from '../../actions/suggestions'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import PanelLayout from './panel_layout';
|
import PanelLayout from './panel_layout'
|
||||||
|
import Avatar from '../avatar'
|
||||||
|
import Divider from '../divider'
|
||||||
|
import Icon from '../icon'
|
||||||
|
import Heading from '../heading'
|
||||||
|
import Text from '../text'
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' },
|
dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' },
|
||||||
title: { id: 'lists.panel_title', defaultMessage: 'On This List ({count})' },
|
memberCount: { id: 'lists.panel_members', defaultMessage: 'Members: {count}' },
|
||||||
show_all: { id: 'groups.sidebar-panel.show_all', defaultMessage: 'Show all' },
|
createdAt: { id: 'lists.panel_created', defaultMessage: 'Created: {date}' },
|
||||||
});
|
title: { id: 'lists_information', defaultMessage: 'List Information' },
|
||||||
|
edit: { id: 'edit', defaultMessage: 'Edit' },
|
||||||
|
})
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
// accountIds: state.getIn(['listEditor', 'accounts', 'items']),
|
// accountIds: state.getIn(['listEditor', 'accounts', 'items']),
|
||||||
});
|
})
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
const mapDispatchToProps = dispatch => {
|
||||||
return {
|
return {
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export default
|
export default
|
||||||
@connect(mapStateToProps, mapDispatchToProps)
|
@connect(mapStateToProps, mapDispatchToProps)
|
||||||
|
@ -27,27 +34,77 @@ class ListDetailsPanel extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
};
|
}
|
||||||
|
|
||||||
handleShowAllLists() {
|
handleShowAllLists() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { intl } = this.props;
|
const { intl } = this.props
|
||||||
|
|
||||||
const count = 10
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PanelLayout
|
<PanelLayout
|
||||||
title={intl.formatMessage(messages.title, { count })}
|
title={intl.formatMessage(messages.title)}
|
||||||
headerButtonTitle={intl.formatMessage(messages.show_all)}
|
headerButtonTitle={intl.formatMessage(messages.edit)}
|
||||||
headerButtonAction={this.handleShowAllLists}
|
headerButtonAction={this.handleShowAllLists}
|
||||||
>
|
>
|
||||||
<div className={_s.default}>
|
<div className={_s.default}>
|
||||||
|
|
||||||
|
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter,].join(' ')}>
|
||||||
|
<Text weight='medium'>
|
||||||
|
Some List Title
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Divider small />
|
||||||
|
|
||||||
|
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter].join(' ')}>
|
||||||
|
<Icon id='calendar' width='12px' height='12px' className={_s.fillColorSecondary} />
|
||||||
|
<Text
|
||||||
|
size='small'
|
||||||
|
color='secondary'
|
||||||
|
className={_s.ml5}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
intl.formatMessage(messages.createdAt, {
|
||||||
|
date: '12-25-2019'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Divider small />
|
||||||
|
|
||||||
|
<div className={[_s.default].join(' ')}>
|
||||||
|
<div className={[_s.default, _s.flexRow, _s.alignItemsCenter].join(' ')}>
|
||||||
|
<Icon id='group' width='12px' height='12px' className={_s.fillColorSecondary} />
|
||||||
|
<Text
|
||||||
|
size='small'
|
||||||
|
color='secondary'
|
||||||
|
className={_s.ml5}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
intl.formatMessage(messages.memberCount, {
|
||||||
|
count: 10
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<div className={[_s.default, _s.flexRow, _s.flexWrap, _s.pt10].join(' ')}>
|
||||||
|
|
||||||
|
{
|
||||||
|
[1, 2, 3, 4, 5, 6, 7, 8, 9].map(item => (
|
||||||
|
<div className={[_s.default, _s.mr5].join(' ')}>
|
||||||
|
<Avatar size='26' />
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</PanelLayout>
|
</PanelLayout>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
};
|
}
|
|
@ -123,6 +123,9 @@ class PopoverBase extends ImmutablePureComponent {
|
||||||
displayNone: !visible,
|
displayNone: !visible,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log("targetRef:", targetRef)
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Manager>
|
<Manager>
|
||||||
<Popper
|
<Popper
|
||||||
|
|
|
@ -10,8 +10,9 @@ import ProfileOptionsPopover from './profile_options_popover'
|
||||||
import SearchPopover from './search_popover'
|
import SearchPopover from './search_popover'
|
||||||
import SidebarMorePopover from './sidebar_more_popover'
|
import SidebarMorePopover from './sidebar_more_popover'
|
||||||
import StatusOptionsPopover from './status_options_popover'
|
import StatusOptionsPopover from './status_options_popover'
|
||||||
import UserInfoPopover from './user_info_popover'
|
import StatusSharePopover from './status_share_popover'
|
||||||
import StatusVisibilityPopover from './status_visibility_popover'
|
import StatusVisibilityPopover from './status_visibility_popover'
|
||||||
|
import UserInfoPopover from './user_info_popover'
|
||||||
|
|
||||||
const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false
|
const listenerOptions = detectPassiveEvents.hasSupport ? { passive: true } : false
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@ const POPOVER_COMPONENTS = {
|
||||||
SEARCH: () => Promise.resolve({ default: SearchPopover }),
|
SEARCH: () => Promise.resolve({ default: SearchPopover }),
|
||||||
SIDEBAR_MORE: () => Promise.resolve({ default: SidebarMorePopover }),
|
SIDEBAR_MORE: () => Promise.resolve({ default: SidebarMorePopover }),
|
||||||
STATUS_OPTIONS: () => Promise.resolve({ default: StatusOptionsPopover }),
|
STATUS_OPTIONS: () => Promise.resolve({ default: StatusOptionsPopover }),
|
||||||
|
STATUS_SHARE: () => Promise.resolve({ default: StatusSharePopover }),
|
||||||
STATUS_VISIBILITY: () => Promise.resolve({ default: StatusVisibilityPopover }),
|
STATUS_VISIBILITY: () => Promise.resolve({ default: StatusVisibilityPopover }),
|
||||||
USER_INFO: () => Promise.resolve({ default: UserInfoPopover }),
|
USER_INFO: () => Promise.resolve({ default: UserInfoPopover }),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
import {
|
import {
|
||||||
followAccount,
|
followAccount,
|
||||||
unfollowAccount,
|
unfollowAccount,
|
||||||
|
|
|
@ -1,43 +1,84 @@
|
||||||
|
import PopoverLayout from './popover_layout'
|
||||||
|
import List from '../list'
|
||||||
|
|
||||||
export default class StatusOptionsPopover extends PureComponent {
|
export default class StatusOptionsPopover extends PureComponent {
|
||||||
render() {
|
_makeMenu = (publicStatus) => {
|
||||||
|
// const { status, intl: { formatMessage }, withDismiss, withGroupAdmin } = this.props
|
||||||
|
// const mutingConversation = status.get('muted')
|
||||||
|
|
||||||
|
let menu = [];
|
||||||
|
|
||||||
|
// menu.push({ text: formatMessage(messages.open), action: this.handleOpen });
|
||||||
|
|
||||||
// if (publicStatus) {
|
// if (publicStatus) {
|
||||||
// menu.push({ text: intl.formatMessage(messages.copy), action: this.handleCopy });
|
// menu.push({ text: formatMessage(messages.copy), action: this.handleCopy });
|
||||||
// menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed });
|
// menu.push({ text: formatMessage(messages.embed), action: this.handleEmbed });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (!me) return menu
|
||||||
|
|
||||||
|
// menu.push(null);
|
||||||
|
|
||||||
|
// if (status.getIn(['account', 'id']) === me || withDismiss) {
|
||||||
|
// menu.push({ text: formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick });
|
||||||
// menu.push(null);
|
// menu.push(null);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// if (me === status.getIn(['account', 'id'])) {
|
// if (status.getIn(['account', 'id']) === me) {
|
||||||
// if (publicStatus) {
|
// if (publicStatus) {
|
||||||
// menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });
|
// menu.push({ text: formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });
|
||||||
// } else {
|
// } else {
|
||||||
// if (status.get('visibility') === 'private') {
|
// if (status.get('visibility') === 'private') {
|
||||||
// menu.push({ text: intl.formatMessage(status.get('reblogged') ? messages.cancel_repost_private : messages.repost_private), action: this.handleRepostClick });
|
// menu.push({ text: formatMessage(status.get('reblogged') ? messages.cancel_repost_private : messages.repost_private), action: this.handleRepostClick });
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
// menu.push({ text: formatMessage(messages.delete), action: this.handleDeleteClick });
|
||||||
// menu.push(null);
|
// menu.push({ text: formatMessage(messages.edit), action: this.handleEditClick });
|
||||||
// menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick });
|
|
||||||
// menu.push(null);
|
|
||||||
// menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick });
|
|
||||||
// menu.push({ text: intl.formatMessage(messages.edit), action: this.handleEditClick });
|
|
||||||
// } else {
|
// } else {
|
||||||
// menu.push({ text: intl.formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });
|
// menu.push({ text: formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });
|
||||||
// menu.push(null);
|
// menu.push(null);
|
||||||
// menu.push({ text: intl.formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
|
// menu.push({ text: formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
|
||||||
// menu.push({ text: intl.formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
|
// menu.push({ text: formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
|
||||||
// menu.push({ text: intl.formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
|
// menu.push({ text: formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
|
||||||
|
|
||||||
// if (isStaff) {
|
// if (isStaff) {
|
||||||
// menu.push(null);
|
// menu.push(null);
|
||||||
// menu.push({ text: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` });
|
// menu.push({ text: formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` });
|
||||||
// menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` });
|
// menu.push({ text: formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (withGroupAdmin) {
|
||||||
|
// menu.push(null);
|
||||||
|
// menu.push({ text: formatMessage(messages.group_remove_account), action: this.handleGroupRemoveAccount });
|
||||||
|
// menu.push({ text: formatMessage(messages.group_remove_post), action: this.handleGroupRemovePost });
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<PopoverLayout className={_s.width240PX}>
|
||||||
{ /* */ }
|
<List
|
||||||
</div>
|
scrollKey='profile_options'
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
title: 'Help',
|
||||||
|
href: 'https://help.gab.com',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Settings',
|
||||||
|
href: '/settings',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Log Out',
|
||||||
|
href: '/auth/log_out',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
small
|
||||||
|
/>
|
||||||
|
</PopoverLayout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
|
import PopoverLayout from './popover_layout'
|
||||||
|
import List from '../list'
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
embed: { id: 'status.embed', defaultMessage: 'Embed gab' },
|
||||||
|
email: { id: 'status.email', defaultMessage: 'Email gab' },
|
||||||
|
copy: { id: 'status.copy', defaultMessage: 'Copy link to gab' },
|
||||||
|
});
|
||||||
|
|
||||||
|
// const makeMapStateToProps = () => {
|
||||||
|
// const getAccount = makeGetAccount();
|
||||||
|
|
||||||
|
// const mapStateToProps = (state, { account }) => ({
|
||||||
|
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return mapStateToProps;
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
|
|
||||||
|
// });
|
||||||
|
|
||||||
|
export default
|
||||||
|
@injectIntl
|
||||||
|
// @connect(makeMapStateToProps, mapDispatchToProps)
|
||||||
|
class StatusSharePopover extends ImmutablePureComponent {
|
||||||
|
static propTypes = {
|
||||||
|
status: ImmutablePropTypes.map,
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEmbed = () => {
|
||||||
|
// this.props.onEmbed(this.props.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCopy = () => {
|
||||||
|
// const url = this.props.status.get('url');
|
||||||
|
// const textarea = document.createElement('textarea');
|
||||||
|
|
||||||
|
// textarea.textContent = url;
|
||||||
|
// textarea.style.position = 'fixed';
|
||||||
|
|
||||||
|
// document.body.appendChild(textarea);
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// textarea.select();
|
||||||
|
// document.execCommand('copy');
|
||||||
|
// } catch (e) {
|
||||||
|
// //
|
||||||
|
// } finally {
|
||||||
|
// document.body.removeChild(textarea);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { intl } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PopoverLayout className={_s.width250PX}>
|
||||||
|
<List
|
||||||
|
scrollKey='status_share_options'
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
icon: 'copy',
|
||||||
|
hideArrow: true,
|
||||||
|
title: intl.formatMessage(messages.copy),
|
||||||
|
onClick: this.handleCopy,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'envelope',
|
||||||
|
hideArrow: true,
|
||||||
|
title: intl.formatMessage(messages.email),
|
||||||
|
href: 'mailto:',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'embed',
|
||||||
|
hideArrow: true,
|
||||||
|
title: intl.formatMessage(messages.embed),
|
||||||
|
onClick: this.handleEmbed,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
small
|
||||||
|
/>
|
||||||
|
</PopoverLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,6 +40,7 @@ const mapStateToProps = state => {
|
||||||
sidebarOpen: state.get('sidebar').sidebarOpen,
|
sidebarOpen: state.get('sidebar').sidebarOpen,
|
||||||
notificationCount: state.getIn(['notifications', 'unread']),
|
notificationCount: state.getIn(['notifications', 'unread']),
|
||||||
homeItemsQueueCount: state.getIn(['timelines', 'home', 'totalQueuedItemsCount']),
|
homeItemsQueueCount: state.getIn(['timelines', 'home', 'totalQueuedItemsCount']),
|
||||||
|
showCommunityTimeline: state.getIn(['settings', 'community', 'shows', 'inSidebar']),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +65,7 @@ class Sidebar extends ImmutablePureComponent {
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
account: ImmutablePropTypes.map,
|
account: ImmutablePropTypes.map,
|
||||||
sidebarOpen: PropTypes.bool,
|
sidebarOpen: PropTypes.bool,
|
||||||
|
showCommunityTimeline: PropTypes.bool,
|
||||||
onClose: PropTypes.func.isRequired,
|
onClose: PropTypes.func.isRequired,
|
||||||
onOpenComposeModal: PropTypes.func.isRequired,
|
onOpenComposeModal: PropTypes.func.isRequired,
|
||||||
openSidebarMorePopover: PropTypes.func.isRequired,
|
openSidebarMorePopover: PropTypes.func.isRequired,
|
||||||
|
@ -115,7 +117,14 @@ class Sidebar extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { sidebarOpen, intl, account, notificationCount, homeItemsQueueCount } = this.props
|
const {
|
||||||
|
sidebarOpen,
|
||||||
|
intl,
|
||||||
|
account,
|
||||||
|
notificationCount,
|
||||||
|
homeItemsQueueCount,
|
||||||
|
showCommunityTimeline
|
||||||
|
} = this.props
|
||||||
const { moreOpen } = this.state
|
const { moreOpen } = this.state
|
||||||
|
|
||||||
// : todo :
|
// : todo :
|
||||||
|
@ -127,6 +136,8 @@ class Sidebar extends ImmutablePureComponent {
|
||||||
const moreIcon = moreOpen ? 'minus' : 'plus'
|
const moreIcon = moreOpen ? 'minus' : 'plus'
|
||||||
const moreContainerStyle = { display: moreOpen ? 'block' : 'none' }
|
const moreContainerStyle = { display: moreOpen ? 'block' : 'none' }
|
||||||
|
|
||||||
|
console.log("showCommunityTimeline:", showCommunityTimeline)
|
||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{
|
{
|
||||||
title: 'Home',
|
title: 'Home',
|
||||||
|
@ -134,18 +145,24 @@ class Sidebar extends ImmutablePureComponent {
|
||||||
to: '/',
|
to: '/',
|
||||||
count: homeItemsQueueCount,
|
count: homeItemsQueueCount,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Community',
|
||||||
|
icon: 'community',
|
||||||
|
to: '/timeline/all',
|
||||||
|
hidden: !showCommunityTimeline,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Notifications',
|
title: 'Notifications',
|
||||||
icon: 'notifications',
|
icon: 'notifications',
|
||||||
to: '/notifications',
|
to: '/notifications',
|
||||||
count: notificationCount,
|
count: notificationCount,
|
||||||
},
|
},
|
||||||
// : todo : show only when search on top is not visible
|
{
|
||||||
// {
|
title: 'Search',
|
||||||
// title: 'Search',
|
icon: 'search-alt',
|
||||||
// icon: 'search-alt',
|
to: '/search',
|
||||||
// to: '/search',
|
hidden: true, // : todo : show only when search on top is not visible
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
title: 'Groups',
|
title: 'Groups',
|
||||||
icon: 'group',
|
icon: 'group',
|
||||||
|
@ -169,11 +186,6 @@ class Sidebar extends ImmutablePureComponent {
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
// more modal:
|
|
||||||
// settings/preferences
|
|
||||||
// help
|
|
||||||
// logout
|
|
||||||
|
|
||||||
const shortcutItems = [
|
const shortcutItems = [
|
||||||
{
|
{
|
||||||
title: 'Meme Group',
|
title: 'Meme Group',
|
||||||
|
@ -223,9 +235,13 @@ class Sidebar extends ImmutablePureComponent {
|
||||||
<nav aria-label='Primary' role='navigation' className={[_s.default, _s.width100PC, _s.mb15].join(' ')}>
|
<nav aria-label='Primary' role='navigation' className={[_s.default, _s.width100PC, _s.mb15].join(' ')}>
|
||||||
<SidebarSectionTitle>Menu</SidebarSectionTitle>
|
<SidebarSectionTitle>Menu</SidebarSectionTitle>
|
||||||
{
|
{
|
||||||
menuItems.map((menuItem, i) => (
|
menuItems.map((menuItem, i) => {
|
||||||
<SidebarSectionItem {...menuItem} key={`sidebar-item-menu-${i}`} />
|
if (menuItem.hidden) return null
|
||||||
))
|
|
||||||
|
return (
|
||||||
|
<SidebarSectionItem {...menuItem} key={`sidebar-item-menu-${i}`} />
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
<SidebarSectionTitle>Shortcuts</SidebarSectionTitle>
|
<SidebarSectionTitle>Shortcuts</SidebarSectionTitle>
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { HotKeys } from 'react-hotkeys';
|
||||||
import classNames from 'classnames/bind'
|
import classNames from 'classnames/bind'
|
||||||
import { displayMedia } from '../../initial_state';
|
import { displayMedia } from '../../initial_state';
|
||||||
import Card from '../../features/status/components/card';
|
import Card from '../../features/status/components/card';
|
||||||
import { MediaGallery, Video } from '../../features/ui/util/async-components';
|
import { MediaGallery, Video } from '../../features/ui/util/async_components';
|
||||||
import ComposeFormContainer from '../../features/compose/containers/compose_form_container'
|
import ComposeFormContainer from '../../features/compose/containers/compose_form_container'
|
||||||
import Avatar from '../avatar';
|
import Avatar from '../avatar';
|
||||||
import StatusQuote from '../status_quote';
|
import StatusQuote from '../status_quote';
|
||||||
|
@ -81,7 +81,6 @@ class Status extends ImmutablePureComponent {
|
||||||
onRepost: PropTypes.func,
|
onRepost: PropTypes.func,
|
||||||
onDelete: PropTypes.func,
|
onDelete: PropTypes.func,
|
||||||
onEdit: PropTypes.func,
|
onEdit: PropTypes.func,
|
||||||
onDirect: PropTypes.func,
|
|
||||||
onMention: PropTypes.func,
|
onMention: PropTypes.func,
|
||||||
onPin: PropTypes.func,
|
onPin: PropTypes.func,
|
||||||
onOpenMedia: PropTypes.func,
|
onOpenMedia: PropTypes.func,
|
||||||
|
|
|
@ -3,14 +3,14 @@ import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import { defineMessages, injectIntl } from 'react-intl'
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
import classNames from 'classnames/bind'
|
import classNames from 'classnames/bind'
|
||||||
import { openModal } from '../actions/modal'
|
import { openModal } from '../actions/modal'
|
||||||
import { me, isStaff } from '../initial_state'
|
import { openPopover } from '../actions/popover'
|
||||||
|
import { me } from '../initial_state'
|
||||||
import Text from './text'
|
import Text from './text'
|
||||||
import StatusActionBarItem from './status_action_bar_item'
|
import StatusActionBarItem from './status_action_bar_item'
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
delete: { id: 'status.delete', defaultMessage: 'Delete' },
|
||||||
edit: { id: 'status.edit', defaultMessage: 'Edit' },
|
edit: { id: 'status.edit', defaultMessage: 'Edit' },
|
||||||
direct: { id: 'status.direct', defaultMessage: 'Direct message @{name}' },
|
|
||||||
mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },
|
mention: { id: 'status.mention', defaultMessage: 'Mention @{name}' },
|
||||||
mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },
|
mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },
|
||||||
block: { id: 'account.block', defaultMessage: 'Block @{name}' },
|
block: { id: 'account.block', defaultMessage: 'Block @{name}' },
|
||||||
|
@ -44,6 +44,14 @@ const mapDispatchToProps = (dispatch) => ({
|
||||||
onOpenUnauthorizedModal() {
|
onOpenUnauthorizedModal() {
|
||||||
dispatch(openModal('UNAUTHORIZED'))
|
dispatch(openModal('UNAUTHORIZED'))
|
||||||
},
|
},
|
||||||
|
onOpenStatusSharePopover(targetRef, status) {
|
||||||
|
console.log("targetRef, status:", targetRef, status)
|
||||||
|
dispatch(openPopover('STATUS_SHARE', {
|
||||||
|
status,
|
||||||
|
targetRef,
|
||||||
|
position: 'top',
|
||||||
|
}))
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const cx = classNames.bind(_s)
|
const cx = classNames.bind(_s)
|
||||||
|
@ -60,6 +68,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
status: ImmutablePropTypes.map.isRequired,
|
status: ImmutablePropTypes.map.isRequired,
|
||||||
onOpenUnauthorizedModal: PropTypes.func.isRequired,
|
onOpenUnauthorizedModal: PropTypes.func.isRequired,
|
||||||
|
onOpenStatusSharePopover: PropTypes.func.isRequired,
|
||||||
onReply: PropTypes.func,
|
onReply: PropTypes.func,
|
||||||
onQuote: PropTypes.func,
|
onQuote: PropTypes.func,
|
||||||
onFavorite: PropTypes.func,
|
onFavorite: PropTypes.func,
|
||||||
|
@ -117,7 +126,12 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleShareClick = () => {
|
handleShareClick = () => {
|
||||||
//
|
console.log("handleShareClick:", this.shareButton, this.props.status)
|
||||||
|
this.props.onOpenStatusSharePopover(this.shareButton, this.props.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
setShareButton = (n) => {
|
||||||
|
this.shareButton = n
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -222,6 +236,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
onClick={this.handleRepostClick}
|
onClick={this.handleRepostClick}
|
||||||
/>
|
/>
|
||||||
<StatusActionBarItem
|
<StatusActionBarItem
|
||||||
|
buttonRef={this.setShareButton}
|
||||||
title={formatMessage(messages.share)}
|
title={formatMessage(messages.share)}
|
||||||
icon='share'
|
icon='share'
|
||||||
onClick={this.handleShareClick}
|
onClick={this.handleShareClick}
|
||||||
|
|
|
@ -10,10 +10,18 @@ export default class StatusActionBarItem extends PureComponent {
|
||||||
icon: PropTypes.string.isRequired,
|
icon: PropTypes.string.isRequired,
|
||||||
active: PropTypes.bool,
|
active: PropTypes.bool,
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
|
buttonRef: PropTypes.node,
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { title, onClick, icon, active, disabled } = this.props
|
const {
|
||||||
|
title,
|
||||||
|
onClick,
|
||||||
|
icon,
|
||||||
|
active,
|
||||||
|
disabled,
|
||||||
|
buttonRef
|
||||||
|
} = this.props
|
||||||
|
|
||||||
const btnClasses = cx({
|
const btnClasses = cx({
|
||||||
default: 1,
|
default: 1,
|
||||||
|
@ -38,6 +46,7 @@ export default class StatusActionBarItem extends PureComponent {
|
||||||
return (
|
return (
|
||||||
<div className={[_s.default, _s.flexGrow1, _s.px10].join(' ')}>
|
<div className={[_s.default, _s.flexGrow1, _s.px10].join(' ')}>
|
||||||
<button
|
<button
|
||||||
|
ref={buttonRef}
|
||||||
className={btnClasses}
|
className={btnClasses}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
active={active}
|
active={active}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { Set as ImmutableSet } from 'immutable';
|
import { Set as ImmutableSet } from 'immutable';
|
||||||
import noop from 'lodash/noop';
|
import noop from 'lodash/noop';
|
||||||
import { toggleStatusReport } from '../actions/reports';
|
import { toggleStatusReport } from '../actions/reports';
|
||||||
import { MediaGallery, Video } from '../features/ui/util/async-components';
|
import { MediaGallery, Video } from '../features/ui/util/async_components';
|
||||||
import Bundle from '../features/ui/util/bundle';
|
import Bundle from '../features/ui/util/bundle';
|
||||||
import StatusContent from './status_content';
|
import StatusContent from './status_content';
|
||||||
import Switch from './switch';
|
import Switch from './switch';
|
||||||
|
|
|
@ -159,6 +159,8 @@ class StatusContent extends ImmutablePureComponent {
|
||||||
const { status, intl, isComment } = this.props
|
const { status, intl, isComment } = this.props
|
||||||
const { collapsed } = this.state
|
const { collapsed } = this.state
|
||||||
|
|
||||||
|
console.log("status content", status.get('content'))
|
||||||
|
|
||||||
if (status.get('content').length === 0) return null;
|
if (status.get('content').length === 0) return null;
|
||||||
|
|
||||||
const hidden = this.props.onExpandedToggle ? !this.props.expanded : this.state.hidden;
|
const hidden = this.props.onExpandedToggle ? !this.props.expanded : this.state.hidden;
|
||||||
|
|
|
@ -2,6 +2,8 @@ import { Fragment } from 'react'
|
||||||
import { NavLink } from 'react-router-dom'
|
import { NavLink } from 'react-router-dom'
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
|
import { openPopover } from '../actions/popover'
|
||||||
|
import { openModal } from '../actions/modal'
|
||||||
import RelativeTimestamp from './relative_timestamp'
|
import RelativeTimestamp from './relative_timestamp'
|
||||||
import DisplayName from './display_name'
|
import DisplayName from './display_name'
|
||||||
import Text from './text'
|
import Text from './text'
|
||||||
|
@ -10,18 +12,30 @@ import Icon from './icon'
|
||||||
import Button from './button'
|
import Button from './button'
|
||||||
import Avatar from './avatar'
|
import Avatar from './avatar'
|
||||||
|
|
||||||
export default class StatusHeader extends ImmutablePureComponent {
|
export default
|
||||||
|
@connect(null, null)
|
||||||
|
class StatusHeader extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
status: ImmutablePropTypes.map,
|
status: ImmutablePropTypes.map,
|
||||||
}
|
}
|
||||||
|
|
||||||
handleStatusOptionsClick() {
|
handleStatusOptionsClick() {
|
||||||
console.log("handleStatusOptionsClick")
|
console.log("handleStatusOptionsClick:", this.props)
|
||||||
|
this.props.dispatch(openPopover('STATUS_OPTIONS', {
|
||||||
|
targetRef: this.statusOptionsButton,
|
||||||
|
position: 'top',
|
||||||
|
status: this.props.status,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
handleOpenStatusEdits() {
|
handleOpenStatusEdits() {
|
||||||
console.log("handleOpenStatusEdits")
|
// : todo :
|
||||||
|
this.props.dispatch(openPopover('REPOST', {
|
||||||
|
targetRef: this.statusOptionsButton,
|
||||||
|
position: 'top',
|
||||||
|
status: this.props.status,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDeleteClick = () => {
|
handleDeleteClick = () => {
|
||||||
|
@ -95,59 +109,8 @@ export default class StatusHeader extends ImmutablePureComponent {
|
||||||
this.props.onGroupRemoveStatus(status.getIn(['group', 'id']), status.get('id'));
|
this.props.onGroupRemoveStatus(status.getIn(['group', 'id']), status.get('id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
_makeMenu = (publicStatus) => {
|
setStatusOptionsButton = n => {
|
||||||
const { status, intl: { formatMessage }, withDismiss, withGroupAdmin } = this.props;
|
this.statusOptionsButton = n
|
||||||
const mutingConversation = status.get('muted');
|
|
||||||
|
|
||||||
let menu = [];
|
|
||||||
|
|
||||||
menu.push({ text: formatMessage(messages.open), action: this.handleOpen });
|
|
||||||
|
|
||||||
if (publicStatus) {
|
|
||||||
menu.push({ text: formatMessage(messages.copy), action: this.handleCopy });
|
|
||||||
menu.push({ text: formatMessage(messages.embed), action: this.handleEmbed });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!me) return menu
|
|
||||||
|
|
||||||
menu.push(null);
|
|
||||||
|
|
||||||
if (status.getIn(['account', 'id']) === me || withDismiss) {
|
|
||||||
menu.push({ text: formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick });
|
|
||||||
menu.push(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status.getIn(['account', 'id']) === me) {
|
|
||||||
if (publicStatus) {
|
|
||||||
menu.push({ text: formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });
|
|
||||||
} else {
|
|
||||||
if (status.get('visibility') === 'private') {
|
|
||||||
menu.push({ text: formatMessage(status.get('reblogged') ? messages.cancel_repost_private : messages.repost_private), action: this.handleRepostClick });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
menu.push({ text: formatMessage(messages.delete), action: this.handleDeleteClick });
|
|
||||||
menu.push({ text: formatMessage(messages.edit), action: this.handleEditClick });
|
|
||||||
} else {
|
|
||||||
menu.push({ text: formatMessage(messages.mention, { name: status.getIn(['account', 'username']) }), action: this.handleMentionClick });
|
|
||||||
menu.push(null);
|
|
||||||
menu.push({ text: formatMessage(messages.mute, { name: status.getIn(['account', 'username']) }), action: this.handleMuteClick });
|
|
||||||
menu.push({ text: formatMessage(messages.block, { name: status.getIn(['account', 'username']) }), action: this.handleBlockClick });
|
|
||||||
menu.push({ text: formatMessage(messages.report, { name: status.getIn(['account', 'username']) }), action: this.handleReport });
|
|
||||||
|
|
||||||
if (isStaff) {
|
|
||||||
menu.push(null);
|
|
||||||
menu.push({ text: formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` });
|
|
||||||
menu.push({ text: formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses/${status.get('id')}` });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (withGroupAdmin) {
|
|
||||||
menu.push(null);
|
|
||||||
menu.push({ text: formatMessage(messages.group_remove_account), action: this.handleGroupRemoveAccount });
|
|
||||||
menu.push({ text: formatMessage(messages.group_remove_post), action: this.handleGroupRemovePost });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return menu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -155,18 +118,6 @@ export default class StatusHeader extends ImmutablePureComponent {
|
||||||
|
|
||||||
const statusUrl = `/${status.getIn(['account', 'acct'])}/posts/${status.get('id')}`;
|
const statusUrl = `/${status.getIn(['account', 'acct'])}/posts/${status.get('id')}`;
|
||||||
|
|
||||||
// const menu = this._makeMenu(publicStatus);
|
|
||||||
// <div className='status-action-bar__dropdown'>
|
|
||||||
// <DropdownMenuContainer
|
|
||||||
// status={status}
|
|
||||||
// items={menu}
|
|
||||||
// icon='ellipsis-h'
|
|
||||||
// size={18}
|
|
||||||
// direction='right'
|
|
||||||
// title={formatMessage(messages.more)}
|
|
||||||
// />
|
|
||||||
// </div>
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={[_s.default, _s.px15, _s.py10].join(' ')}>
|
<div className={[_s.default, _s.px15, _s.py10].join(' ')}>
|
||||||
<div className={[_s.default, _s.flexRow, _s.mt5].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.mt5].join(' ')}>
|
||||||
|
@ -200,6 +151,7 @@ export default class StatusHeader extends ImmutablePureComponent {
|
||||||
iconClassName={_s.fillColorSecondary}
|
iconClassName={_s.fillColorSecondary}
|
||||||
className={_s.marginLeftAuto}
|
className={_s.marginLeftAuto}
|
||||||
onClick={this.handleStatusOptionsClick}
|
onClick={this.handleStatusOptionsClick}
|
||||||
|
buttonRef={this.setStatusOptionsButton}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ export default class StatusList extends ImmutablePureComponent {
|
||||||
|
|
||||||
let scrollableContent = (isLoading || statusIds.size > 0) ? (
|
let scrollableContent = (isLoading || statusIds.size > 0) ? (
|
||||||
statusIds.map((statusId, index) => statusId === null ? (
|
statusIds.map((statusId, index) => statusId === null ? (
|
||||||
<LoadGap
|
<div
|
||||||
key={'gap:' + statusIds.get(index + 1)}
|
key={'gap:' + statusIds.get(index + 1)}
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
maxId={index > 0 ? statusIds.get(index - 1) : null}
|
maxId={index > 0 ? statusIds.get(index - 1) : null}
|
||||||
|
|
|
@ -1,84 +1,7 @@
|
||||||
'use strict';
|
export const APP_NAME = 'Gab'
|
||||||
|
|
||||||
import WebSocketClient from 'websocket.js';
|
export const BREAKPOINT_EXTRA_LARGE = 1480
|
||||||
|
export const BREAKPOINT_LARGE = 1280
|
||||||
const randomIntUpTo = max => Math.floor(Math.random() * Math.floor(max));
|
export const BREAKPOINT_MEDIUM = 1160
|
||||||
|
export const BREAKPOINT_SMALL = 1080
|
||||||
export function connectStream(path, pollingRefresh = null, callbacks = () => ({ onConnect() { }, onDisconnect() { }, onReceive() { } })) {
|
export const BREAKPOINT_EXTRA_SMALL = 992
|
||||||
return (dispatch, getState) => {
|
|
||||||
const streamingAPIBaseURL = getState().getIn(['meta', 'streaming_api_base_url']);
|
|
||||||
const accessToken = getState().getIn(['meta', 'access_token']);
|
|
||||||
const { onConnect, onDisconnect, onReceive } = callbacks(dispatch, getState);
|
|
||||||
|
|
||||||
let polling = null;
|
|
||||||
|
|
||||||
const setupPolling = () => {
|
|
||||||
pollingRefresh(dispatch, () => {
|
|
||||||
polling = setTimeout(() => setupPolling(), 20000 + randomIntUpTo(20000));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const clearPolling = () => {
|
|
||||||
if (polling) {
|
|
||||||
clearTimeout(polling);
|
|
||||||
polling = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const subscription = getStream(streamingAPIBaseURL, accessToken, path, {
|
|
||||||
connected() {
|
|
||||||
if (pollingRefresh) {
|
|
||||||
clearPolling();
|
|
||||||
}
|
|
||||||
|
|
||||||
onConnect();
|
|
||||||
},
|
|
||||||
|
|
||||||
disconnected() {
|
|
||||||
if (pollingRefresh) {
|
|
||||||
polling = setTimeout(() => setupPolling(), randomIntUpTo(40000));
|
|
||||||
}
|
|
||||||
|
|
||||||
onDisconnect();
|
|
||||||
},
|
|
||||||
|
|
||||||
received(data) {
|
|
||||||
onReceive(data);
|
|
||||||
},
|
|
||||||
|
|
||||||
reconnected() {
|
|
||||||
if (pollingRefresh) {
|
|
||||||
clearPolling();
|
|
||||||
pollingRefresh(dispatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
onConnect();
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
const disconnect = () => {
|
|
||||||
if (subscription) {
|
|
||||||
subscription.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
clearPolling();
|
|
||||||
};
|
|
||||||
|
|
||||||
return disconnect;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default function getStream(streamingAPIBaseURL, accessToken, stream, { connected, received, disconnected, reconnected }) {
|
|
||||||
const params = [`stream=${stream}`];
|
|
||||||
|
|
||||||
const ws = new WebSocketClient(`${streamingAPIBaseURL}/api/v1/streaming/?${params.join('&')}`, accessToken);
|
|
||||||
|
|
||||||
ws.onopen = connected;
|
|
||||||
ws.onmessage = e => received(JSON.parse(e.data));
|
|
||||||
ws.onclose = disconnected;
|
|
||||||
ws.onreconnect = reconnected;
|
|
||||||
|
|
||||||
return ws;
|
|
||||||
};
|
|
|
@ -11,7 +11,6 @@ export default class Header extends ImmutablePureComponent {
|
||||||
onFollow: PropTypes.func.isRequired,
|
onFollow: PropTypes.func.isRequired,
|
||||||
onBlock: PropTypes.func.isRequired,
|
onBlock: PropTypes.func.isRequired,
|
||||||
onMention: PropTypes.func.isRequired,
|
onMention: PropTypes.func.isRequired,
|
||||||
onDirect: PropTypes.func.isRequired,
|
|
||||||
onRepostToggle: PropTypes.func.isRequired,
|
onRepostToggle: PropTypes.func.isRequired,
|
||||||
onReport: PropTypes.func.isRequired,
|
onReport: PropTypes.func.isRequired,
|
||||||
onMute: PropTypes.func.isRequired,
|
onMute: PropTypes.func.isRequired,
|
||||||
|
@ -39,10 +38,6 @@ export default class Header extends ImmutablePureComponent {
|
||||||
this.props.onMention(this.props.account, this.context.router.history);
|
this.props.onMention(this.props.account, this.context.router.history);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDirect = () => {
|
|
||||||
this.props.onDirect(this.props.account, this.context.router.history);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleReport = () => {
|
handleReport = () => {
|
||||||
this.props.onReport(this.props.account);
|
this.props.onReport(this.props.account);
|
||||||
}
|
}
|
||||||
|
@ -93,7 +88,6 @@ export default class Header extends ImmutablePureComponent {
|
||||||
onFollow={this.handleFollow}
|
onFollow={this.handleFollow}
|
||||||
onBlock={this.handleBlock}
|
onBlock={this.handleBlock}
|
||||||
onMention={this.handleMention}
|
onMention={this.handleMention}
|
||||||
onDirect={this.handleDirect}
|
|
||||||
onRepostToggle={this.handleRepostToggle}
|
onRepostToggle={this.handleRepostToggle}
|
||||||
onReport={this.handleReport}
|
onReport={this.handleReport}
|
||||||
onMute={this.handleMute}
|
onMute={this.handleMute}
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
|
import { expandCommunityTimeline } from '../actions/timelines'
|
||||||
|
import { connectCommunityStream } from '../actions/streaming'
|
||||||
|
import StatusListContainer from '../containers/status_list_container'
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
empty: { id: 'empty_column.community', defaultMessage: 'The community timeline is empty. Write something publicly to get the ball rolling!' },
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
const onlyMedia = state.getIn(['settings', 'community', 'other', 'onlyMedia'])
|
||||||
|
|
||||||
|
return {
|
||||||
|
onlyMedia,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default
|
||||||
|
@connect(mapStateToProps)
|
||||||
|
@injectIntl
|
||||||
|
class CommunityTimeline extends PureComponent {
|
||||||
|
|
||||||
|
static contextTypes = {
|
||||||
|
router: PropTypes.object,
|
||||||
|
}
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
dispatch: PropTypes.func.isRequired,
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
onlyMedia: PropTypes.bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
const { dispatch, onlyMedia } = this.props
|
||||||
|
|
||||||
|
dispatch(expandCommunityTimeline({ onlyMedia }))
|
||||||
|
this.disconnect = dispatch(connectCommunityStream({ onlyMedia }))
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate (prevProps) {
|
||||||
|
if (prevProps.onlyMedia !== this.props.onlyMedia) {
|
||||||
|
const { dispatch, onlyMedia } = this.props
|
||||||
|
|
||||||
|
this.disconnect()
|
||||||
|
|
||||||
|
dispatch(expandCommunityTimeline({ onlyMedia }))
|
||||||
|
this.disconnect = dispatch(connectCommunityStream({ onlyMedia }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
if (this.disconnect) {
|
||||||
|
this.disconnect()
|
||||||
|
this.disconnect = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleLoadMore = maxId => {
|
||||||
|
const { dispatch, onlyMedia } = this.props
|
||||||
|
|
||||||
|
dispatch(expandCommunityTimeline({ maxId, onlyMedia }))
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { intl, onlyMedia } = this.props
|
||||||
|
|
||||||
|
const emptyMessage = intl.formatMessage(messages.empty)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StatusListContainer
|
||||||
|
scrollKey='community_timeline'
|
||||||
|
timelineId={`community${onlyMedia ? ':media' : ''}`}
|
||||||
|
onLoadMore={this.handleLoadMore}
|
||||||
|
emptyMessage={emptyMessage}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,109 +0,0 @@
|
||||||
import { defineMessages, injectIntl } from 'react-intl'
|
|
||||||
import {
|
|
||||||
expandCommunityTimeline,
|
|
||||||
expandPublicTimeline,
|
|
||||||
} from '../../actions/timelines'
|
|
||||||
import {
|
|
||||||
connectCommunityStream,
|
|
||||||
connectPublicStream,
|
|
||||||
} from '../../actions/streaming'
|
|
||||||
import StatusListContainer from '../../containers/status_list_container'
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
empty: { id: 'empty_column.community', defaultMessage: 'The community timeline is empty. Write something publicly to get the ball rolling!' },
|
|
||||||
})
|
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
|
||||||
const allFediverse = state.getIn(['settings', 'community', 'other', 'allFediverse'])
|
|
||||||
const onlyMedia = state.getIn(['settings', 'community', 'other', 'onlyMedia'])
|
|
||||||
|
|
||||||
const timelineId = allFediverse ? 'public' : 'community'
|
|
||||||
|
|
||||||
return {
|
|
||||||
timelineId,
|
|
||||||
allFediverse,
|
|
||||||
onlyMedia,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default
|
|
||||||
@connect(mapStateToProps)
|
|
||||||
@injectIntl
|
|
||||||
class CommunityTimeline extends PureComponent {
|
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
router: PropTypes.object,
|
|
||||||
}
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
dispatch: PropTypes.func.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
onlyMedia: PropTypes.bool,
|
|
||||||
allFediverse: PropTypes.bool,
|
|
||||||
timelineId: PropTypes.string,
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount () {
|
|
||||||
const { dispatch, onlyMedia, allFediverse } = this.props
|
|
||||||
|
|
||||||
if (allFediverse) {
|
|
||||||
dispatch(expandPublicTimeline({ onlyMedia }))
|
|
||||||
this.disconnect = dispatch(connectPublicStream({ onlyMedia }))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dispatch(expandCommunityTimeline({ onlyMedia }))
|
|
||||||
this.disconnect = dispatch(connectCommunityStream({ onlyMedia }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate (prevProps) {
|
|
||||||
if (prevProps.onlyMedia !== this.props.onlyMedia || prevProps.allFediverse !== this.props.allFediverse) {
|
|
||||||
const { dispatch, onlyMedia, allFediverse } = this.props
|
|
||||||
|
|
||||||
this.disconnect()
|
|
||||||
|
|
||||||
if (allFediverse) {
|
|
||||||
dispatch(expandPublicTimeline({ onlyMedia }))
|
|
||||||
this.disconnect = dispatch(connectPublicStream({ onlyMedia }))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dispatch(expandCommunityTimeline({ onlyMedia }))
|
|
||||||
this.disconnect = dispatch(connectCommunityStream({ onlyMedia }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount () {
|
|
||||||
if (this.disconnect) {
|
|
||||||
this.disconnect()
|
|
||||||
this.disconnect = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleLoadMore = maxId => {
|
|
||||||
const { dispatch, onlyMedia, allFediverse } = this.props
|
|
||||||
|
|
||||||
if (allFediverse) {
|
|
||||||
dispatch(expandPublicTimeline({ maxId, onlyMedia }))
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dispatch(expandCommunityTimeline({ maxId, onlyMedia }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { intl, onlyMedia, timelineId } = this.props
|
|
||||||
|
|
||||||
const emptyMessage = intl.formatMessage(messages.empty)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StatusListContainer
|
|
||||||
scrollKey={`${timelineId}_timeline`}
|
|
||||||
timelineId={`${timelineId}${onlyMedia ? ':media' : ''}`}
|
|
||||||
onLoadMore={this.handleLoadMore}
|
|
||||||
emptyMessage={emptyMessage}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
import SettingSwitch from '../../../../components/setting_switch';
|
|
||||||
import { changeSetting } from '../../../../actions/settings';
|
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
settings: state.getIn(['settings', 'community']),
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
|
||||||
return {
|
|
||||||
onChange(key, checked) {
|
|
||||||
dispatch(changeSetting(['community', ...key], checked));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default
|
|
||||||
@connect(mapStateToProps, mapDispatchToProps)
|
|
||||||
class ColumnSettings extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
settings: ImmutablePropTypes.map.isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { settings, onChange } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<SettingSwitch
|
|
||||||
settings={settings}
|
|
||||||
settingPath={['other', 'onlyMedia']}
|
|
||||||
onChange={onChange}
|
|
||||||
label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media Only' />}
|
|
||||||
/>
|
|
||||||
<SettingSwitch
|
|
||||||
settings={settings}
|
|
||||||
settingPath={['other', 'allFediverse']}
|
|
||||||
onChange={onChange}
|
|
||||||
label={<FormattedMessage id='community.column_settings.all_fediverse' defaultMessage='All Fediverse' />}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './column_settings'
|
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './community_timeline'
|
|
|
@ -4,7 +4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import detectPassiveEvents from 'detect-passive-events';
|
import detectPassiveEvents from 'detect-passive-events';
|
||||||
import Overlay from 'react-overlays/lib/Overlay';
|
import Overlay from 'react-overlays/lib/Overlay';
|
||||||
import { EmojiPicker as EmojiPickerAsync } from '../../../ui/util/async-components';
|
import { EmojiPicker as EmojiPickerAsync } from '../../../ui/util/async_components';
|
||||||
import { buildCustomEmojis } from '../../../../components/emoji/emoji';
|
import { buildCustomEmojis } from '../../../../components/emoji/emoji';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import { fetchGroups } from '../actions/groups'
|
import { fetchGroups } from '../actions/groups'
|
||||||
import Block from '../components/block'
|
import ScrollableList from '../components/scrollable_list'
|
||||||
import GroupCollectionItem from '../components/group_collection_item'
|
import GroupCollectionItem from '../components/group_collection_item'
|
||||||
|
|
||||||
const mapStateToProps = (state, { activeTab }) => ({
|
const mapStateToProps = (state, { activeTab }) => ({
|
||||||
|
@ -30,15 +30,19 @@ class GroupsCollection extends ImmutablePureComponent {
|
||||||
render() {
|
render() {
|
||||||
const { groupIds } = this.props
|
const { groupIds } = this.props
|
||||||
|
|
||||||
console.log("groupIds: ", groupIds)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={[_s.default, _s.flexRow, _s.flexWrap].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.flexWrap].join(' ')}>
|
||||||
{
|
<ScrollableList
|
||||||
groupIds.map((groupId, i) => (
|
scrollKey='groups_collection'
|
||||||
<GroupCollectionItem key={`group-collection-item-${i}`} id={groupId} />
|
emptyMessage={''}
|
||||||
))
|
>
|
||||||
}
|
{
|
||||||
|
groupIds.map((groupId, i) => (
|
||||||
|
<GroupCollectionItem key={`group-collection-item-${i}`} id={groupId} />
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ScrollableList>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { defineMessages, injectIntl } from 'react-intl'
|
import { defineMessages, injectIntl } from 'react-intl'
|
||||||
import { expandHomeTimeline } from '../../actions/timelines'
|
import { expandHomeTimeline } from '../actions/timelines'
|
||||||
import StatusListContainer from '../../containers/status_list_container'
|
import StatusListContainer from '../containers/status_list_container'
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
title: { id: 'column.home', defaultMessage: 'Home' },
|
title: { id: 'column.home', defaultMessage: 'Home' },
|
||||||
|
@ -72,4 +72,4 @@ class HomeTimeline extends PureComponent {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,55 +0,0 @@
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
import { changeSetting, saveSettings } from '../../../../actions/settings';
|
|
||||||
import SettingSwitch from '../../../../components/setting_switch';
|
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
|
||||||
settings: state.getIn(['settings', 'home']),
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
|
||||||
onChange(key, checked) {
|
|
||||||
dispatch(changeSetting(['home', ...key], checked));
|
|
||||||
},
|
|
||||||
onSave() {
|
|
||||||
dispatch(saveSettings());
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default
|
|
||||||
@connect(mapStateToProps, mapDispatchToProps)
|
|
||||||
class ColumnSettings extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
settings: ImmutablePropTypes.map.isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { settings, onChange } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<FormattedMessage id='home.column_settings.basic' defaultMessage='Basic' />
|
|
||||||
|
|
||||||
<SettingSwitch
|
|
||||||
prefix='home_timeline'
|
|
||||||
settings={settings}
|
|
||||||
settingPath={['shows', 'repost']}
|
|
||||||
onChange={onChange}
|
|
||||||
label={<FormattedMessage id='home.column_settings.show_reposts' defaultMessage='Show reposts' />}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SettingSwitch
|
|
||||||
prefix='home_timeline'
|
|
||||||
settings={settings}
|
|
||||||
settingPath={['shows', 'reply']}
|
|
||||||
onChange={onChange}
|
|
||||||
label={<FormattedMessage id='home.column_settings.show_replies' defaultMessage='Show replies' />}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export { default } from './column_settings'
|
|
|
@ -3,6 +3,8 @@ import classNames from 'classnames';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { closeOnboarding } from '../actions/onboarding';
|
import { closeOnboarding } from '../actions/onboarding';
|
||||||
|
|
||||||
|
// : todo :
|
||||||
|
|
||||||
class FrameWelcome extends Component {
|
class FrameWelcome extends Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
domain: PropTypes.string.isRequired,
|
domain: PropTypes.string.isRequired,
|
||||||
|
|
|
@ -61,6 +61,7 @@ class ListCreate extends PureComponent {
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className={_s.ml10}
|
className={_s.ml10}
|
||||||
|
type='submit'
|
||||||
>
|
>
|
||||||
<Text color='white'>
|
<Text color='white'>
|
||||||
{intl.formatMessage(messages.create)}
|
{intl.formatMessage(messages.create)}
|
||||||
|
|
|
@ -1,20 +1,16 @@
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { injectIntl, FormattedMessage } from 'react-intl'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash'
|
||||||
import { fetchMutes, expandMutes } from '../actions/mutes';
|
import { fetchMutes, expandMutes } from '../actions/mutes'
|
||||||
import AccountContainer from '../containers/account_container';
|
import AccountContainer from '../containers/account_container'
|
||||||
import ColumnIndicator from '../components/column_indicator';
|
import ColumnIndicator from '../components/column_indicator'
|
||||||
import ScrollableList from '../components/scrollable_list';
|
import ScrollableList from '../components/scrollable_list'
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
heading: { id: 'column.mutes', defaultMessage: 'Muted users' },
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
accountIds: state.getIn(['user_lists', 'mutes', 'items']),
|
accountIds: state.getIn(['user_lists', 'mutes', 'items']),
|
||||||
hasMore: !!state.getIn(['user_lists', 'mutes', 'next']),
|
hasMore: !!state.getIn(['user_lists', 'mutes', 'next']),
|
||||||
});
|
})
|
||||||
|
|
||||||
export default
|
export default
|
||||||
@connect(mapStateToProps)
|
@connect(mapStateToProps)
|
||||||
|
@ -26,19 +22,18 @@ class Mutes extends ImmutablePureComponent {
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
hasMore: PropTypes.bool,
|
hasMore: PropTypes.bool,
|
||||||
accountIds: ImmutablePropTypes.list,
|
accountIds: ImmutablePropTypes.list,
|
||||||
intl: PropTypes.object.isRequired,
|
}
|
||||||
};
|
|
||||||
|
|
||||||
componentWillMount() {
|
componentWillMount() {
|
||||||
this.props.dispatch(fetchMutes());
|
this.props.dispatch(fetchMutes())
|
||||||
}
|
}
|
||||||
|
|
||||||
handleLoadMore = debounce(() => {
|
handleLoadMore = debounce(() => {
|
||||||
this.props.dispatch(expandMutes());
|
this.props.dispatch(expandMutes())
|
||||||
}, 300, { leading: true });
|
}, 300, { leading: true })
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { intl, hasMore, accountIds } = this.props;
|
const { hasMore, accountIds } = this.props
|
||||||
|
|
||||||
if (!accountIds) {
|
if (!accountIds) {
|
||||||
return <ColumnIndicator type='loading' />
|
return <ColumnIndicator type='loading' />
|
||||||
|
@ -53,7 +48,7 @@ class Mutes extends ImmutablePureComponent {
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
accountIds.map(id =>
|
accountIds.map(id =>
|
||||||
<AccountContainer key={id} id={id} />
|
<AccountContainer key={`mutes-${id}`} id={id} compact />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</ScrollableList>
|
</ScrollableList>
|
||||||
|
|
|
@ -72,8 +72,6 @@ const makeMapStateToProps = () => {
|
||||||
|
|
||||||
// ONLY Direct descendants
|
// ONLY Direct descendants
|
||||||
descendantsIds = state.getIn(['contexts', 'replies', status.get('id')])
|
descendantsIds = state.getIn(['contexts', 'replies', status.get('id')])
|
||||||
|
|
||||||
console.log("descendantsIds:", descendantsIds)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -19,6 +19,9 @@ import ModalRoot from '../../components/modal/modal_root'
|
||||||
import PopoverRoot from '../../components/popover/popover_root'
|
import PopoverRoot from '../../components/popover/popover_root'
|
||||||
import UploadArea from '../../components/upload_area'
|
import UploadArea from '../../components/upload_area'
|
||||||
import ProfilePage from '../../pages/profile_page'
|
import ProfilePage from '../../pages/profile_page'
|
||||||
|
import CommunityPage from '../../pages/community_page'
|
||||||
|
import HashtagPage from '../../pages/hashtag_page'
|
||||||
|
import ShortcutsPage from '../../pages/shortcuts_page'
|
||||||
import GroupPage from '../../pages/group_page'
|
import GroupPage from '../../pages/group_page'
|
||||||
import GroupsPage from '../../pages/groups_page'
|
import GroupsPage from '../../pages/groups_page'
|
||||||
import SearchPage from '../../pages/search_page'
|
import SearchPage from '../../pages/search_page'
|
||||||
|
@ -60,8 +63,9 @@ import {
|
||||||
Notifications,
|
Notifications,
|
||||||
Reposts,
|
Reposts,
|
||||||
Search,
|
Search,
|
||||||
|
Shortcuts,
|
||||||
Status,
|
Status,
|
||||||
} from './util/async-components'
|
} from './util/async_components'
|
||||||
import { me, meUsername } from '../../initial_state'
|
import { me, meUsername } from '../../initial_state'
|
||||||
|
|
||||||
// Dummy import, to make sure that <Status /> ends up in the application bundle.
|
// Dummy import, to make sure that <Status /> ends up in the application bundle.
|
||||||
|
@ -141,7 +145,7 @@ class SwitchingArea extends PureComponent {
|
||||||
<Redirect from='/' to='/home' exact />
|
<Redirect from='/' to='/home' exact />
|
||||||
<WrappedRoute path='/home' exact page={HomePage} component={HomeTimeline} content={children} />
|
<WrappedRoute path='/home' exact page={HomePage} component={HomeTimeline} content={children} />
|
||||||
|
|
||||||
<WrappedRoute path='/timeline/all' exact page={BasicPage} component={CommunityTimeline} content={children} componentParams={{ title: 'Hashtag Timeline' }} />
|
<WrappedRoute path='/timeline/all' exact page={CommunityPage} component={CommunityTimeline} content={children} componentParams={{ title: 'Community Timeline' }} />
|
||||||
|
|
||||||
<WrappedRoute path='/groups' exact page={GroupsPage} component={GroupsCollection} content={children} componentParams={{ activeTab: 'featured' }} />
|
<WrappedRoute path='/groups' exact page={GroupsPage} component={GroupsCollection} content={children} componentParams={{ activeTab: 'featured' }} />
|
||||||
<WrappedRoute path='/groups/new' exact page={GroupsPage} component={GroupsCollection} content={children} componentParams={{ activeTab: 'new' }} />
|
<WrappedRoute path='/groups/new' exact page={GroupsPage} component={GroupsCollection} content={children} componentParams={{ activeTab: 'new' }} />
|
||||||
|
@ -154,7 +158,9 @@ class SwitchingArea extends PureComponent {
|
||||||
<WrappedRoute path='/groups/:id/edit' page={ModalPage} component={GroupCreate} content={children} componentParams={{ title: 'Edit Group' }} />
|
<WrappedRoute path='/groups/:id/edit' page={ModalPage} component={GroupCreate} content={children} componentParams={{ title: 'Edit Group' }} />
|
||||||
<WrappedRoute path='/groups/:id' page={GroupPage} component={GroupTimeline} content={children} />
|
<WrappedRoute path='/groups/:id' page={GroupPage} component={GroupTimeline} content={children} />
|
||||||
|
|
||||||
<WrappedRoute path='/tags/:id' publicRoute page={BasicPage} component={HashtagTimeline} content={children} componentParams={{ title: 'Hashtag' }} />
|
<WrappedRoute path='/tags/:id' publicRoute page={HashtagPage} component={HashtagTimeline} content={children} componentParams={{ title: 'Hashtag' }} />
|
||||||
|
|
||||||
|
<WrappedRoute path='/shortcuts' publicRoute page={ShortcutsPage} component={Shortcuts} content={children} />
|
||||||
|
|
||||||
<WrappedRoute path='/lists' exact page={ListsPage} component={ListsDirectory} content={children} />
|
<WrappedRoute path='/lists' exact page={ListsPage} component={ListsDirectory} content={children} />
|
||||||
<WrappedRoute path='/lists/create' exact page={ModalPage} component={ListCreate} content={children} componentParams={{ title: 'Create List' }} />
|
<WrappedRoute path='/lists/create' exact page={ModalPage} component={ListCreate} content={children} componentParams={{ title: 'Create List' }} />
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { getWindowDimension } from '../../../utils/is_mobile'
|
||||||
|
|
||||||
|
const initialState = getWindowDimension()
|
||||||
|
|
||||||
|
export default class Responsive extends PureComponent {
|
||||||
|
static propTypes = {
|
||||||
|
min: PropTypes.number,
|
||||||
|
max: PropTypes.number,
|
||||||
|
}
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
min: 0,
|
||||||
|
max: Infinity,
|
||||||
|
}
|
||||||
|
|
||||||
|
state = {
|
||||||
|
width: initialState.width,
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
window.addEventListener('resize', this.handleResize, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
window.removeEventListener('resize', this.handleResize, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleResize = () => {
|
||||||
|
const { width } = getWindowDimension()
|
||||||
|
|
||||||
|
this.setState({ width })
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldRender = (min, max, width) => {
|
||||||
|
return width > min && width < max
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { children, min, max } = this.props
|
||||||
|
const { width } = this.state
|
||||||
|
|
||||||
|
const shouldRender = this.shouldRender(min, max, width)
|
||||||
|
|
||||||
|
console.log("shouldRender:", min, max, width, shouldRender)
|
||||||
|
|
||||||
|
return shouldRender ? children : null
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,11 @@
|
||||||
import Sticky from 'react-stickynode'
|
import Sticky from 'react-stickynode'
|
||||||
|
import * as Constants from '../constants'
|
||||||
import Search from '../components/search'
|
import Search from '../components/search'
|
||||||
import ColumnHeader from '../components/column_header'
|
import ColumnHeader from '../components/column_header'
|
||||||
import Sidebar from '../components/sidebar'
|
import Sidebar from '../components/sidebar'
|
||||||
|
// import Header from '../components/header'
|
||||||
|
// import Footer from '../components/footer'
|
||||||
|
import Responsive from '../features/ui/util/responsive_component'
|
||||||
|
|
||||||
export default class DefaultLayout extends PureComponent {
|
export default class DefaultLayout extends PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -18,10 +22,14 @@ export default class DefaultLayout extends PureComponent {
|
||||||
// const shouldHideFAB = path => path.match(/^\/posts\/|^\/search|^\/getting-started/);
|
// const shouldHideFAB = path => path.match(/^\/posts\/|^\/search|^\/getting-started/);
|
||||||
// const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : <button key='floating-action-button' onClick={this.handleOpenComposeModal} className='floating-action-button' aria-label={intl.formatMessage(messages.publish)}></button>;
|
// const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null : <button key='floating-action-button' onClick={this.handleOpenComposeModal} className='floating-action-button' aria-label={intl.formatMessage(messages.publish)}></button>;
|
||||||
|
|
||||||
|
console.log("Constants.BREAKPOINT_EXTRA_SMALL:", Constants.BREAKPOINT_EXTRA_SMALL)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={[_s.default, _s.flexRow, _s.width100PC, _s.heightMin100VH, _s.backgroundColorSecondary3].join(' ')}>
|
<div className={[_s.default, _s.flexRow, _s.width100PC, _s.heightMin100VH, _s.backgroundColorSecondary3].join(' ')}>
|
||||||
|
|
||||||
<Sidebar />
|
<Responsive min={Constants.BREAKPOINT_EXTRA_SMALL}>
|
||||||
|
<Sidebar />
|
||||||
|
</Responsive>
|
||||||
|
|
||||||
<main role='main' className={[_s.default, _s.flexShrink1, _s.flexGrow1, _s.borderColorSecondary2, _s.borderLeft1PX].join(' ')}>
|
<main role='main' className={[_s.default, _s.flexShrink1, _s.flexGrow1, _s.borderColorSecondary2, _s.borderLeft1PX].join(' ')}>
|
||||||
|
|
||||||
|
@ -50,13 +58,16 @@ export default class DefaultLayout extends PureComponent {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={[_s.default, _s.width340PX].join(' ')}>
|
<Responsive min={Constants.BREAKPOINT_EXTRA_SMALL}>
|
||||||
<Sticky top={73} enabled>
|
<div className={[_s.default, _s.width340PX].join(' ')}>
|
||||||
<div className={[_s.default, _s.width340PX].join(' ')}>
|
<Sticky top={73} enabled>
|
||||||
{layout}
|
<div className={[_s.default, _s.width340PX].join(' ')}>
|
||||||
</div>
|
{layout}
|
||||||
</Sticky>
|
</div>
|
||||||
</div>
|
</Sticky>
|
||||||
|
</div>
|
||||||
|
</Responsive>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { Fragment } from 'react'
|
||||||
|
import { openModal } from '../actions/modal'
|
||||||
|
import GroupSidebarPanel from '../components/panel/groups_panel'
|
||||||
|
import LinkFooter from '../components/link_footer'
|
||||||
|
import WhoToFollowPanel from '../components/panel/who_to_follow_panel'
|
||||||
|
import ProgressPanel from '../components/panel/progress_panel'
|
||||||
|
import TrendsPanel from '../components/panel/trends_panel'
|
||||||
|
import HashtagsPanel from '../components/panel/hashtags_panel'
|
||||||
|
import DefaultLayout from '../layouts/default_layout'
|
||||||
|
import TimelineComposeBlock from '../components/timeline_compose_block'
|
||||||
|
import Divider from '../components/divider'
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
onOpenCommunityPageSettingsModal() {
|
||||||
|
dispatch(openModal('COMMUNITY_TIMELINE_SETTINGS'))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default
|
||||||
|
@connect(null, mapDispatchToProps)
|
||||||
|
class CommunityPage extends PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
onOpenCommunityPageSettingsModal: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
document.title = '(1) Community - Gab'
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { children, onOpenCommunityPageSettingsModal } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DefaultLayout
|
||||||
|
title='Community Timeline'
|
||||||
|
actions={[
|
||||||
|
{
|
||||||
|
icon: 'ellipsis',
|
||||||
|
onClick: onOpenCommunityPageSettingsModal,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
layout={(
|
||||||
|
<Fragment>
|
||||||
|
<ProgressPanel />
|
||||||
|
<TrendsPanel />
|
||||||
|
<HashtagsPanel />
|
||||||
|
<WhoToFollowPanel />
|
||||||
|
<GroupSidebarPanel />
|
||||||
|
<LinkFooter />
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<TimelineComposeBlock autoFocus={false} />
|
||||||
|
<Divider />
|
||||||
|
{children}
|
||||||
|
</DefaultLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,24 @@
|
||||||
import { Fragment } from 'react'
|
import { Fragment } from 'react'
|
||||||
|
import { openModal } from '../actions/modal'
|
||||||
import LinkFooter from '../components/link_footer'
|
import LinkFooter from '../components/link_footer'
|
||||||
import GroupsPanel from '../components/panel/groups_panel'
|
import GroupsPanel from '../components/panel/groups_panel'
|
||||||
|
import WhoToFollowPanel from '../components/panel/who_to_follow_panel'
|
||||||
import DefaultLayout from '../layouts/default_layout'
|
import DefaultLayout from '../layouts/default_layout'
|
||||||
|
|
||||||
export default class GroupsPage extends PureComponent {
|
|
||||||
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
onOpenGroupCreateModal() {
|
||||||
|
dispatch(openModal('GROUP_CREATE'))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default
|
||||||
|
@connect(null, mapDispatchToProps)
|
||||||
|
class GroupsPage extends PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
onOpenGroupCreateModal: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
document.title = 'Groups - Gab'
|
document.title = 'Groups - Gab'
|
||||||
|
@ -18,7 +33,7 @@ export default class GroupsPage extends PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { children } = this.props
|
const { children, onOpenGroupCreateModal } = this.props
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{
|
{
|
||||||
|
@ -44,12 +59,13 @@ export default class GroupsPage extends PureComponent {
|
||||||
title='Groups'
|
title='Groups'
|
||||||
actions={[
|
actions={[
|
||||||
{
|
{
|
||||||
icon: 'list-delete',
|
icon: 'group-add',
|
||||||
onClick: this.handleClickEditLists
|
onClick: onOpenGroupCreateModal
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
layout={(
|
layout={(
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
<WhoToFollowPanel />
|
||||||
<GroupsPanel slim />
|
<GroupsPanel slim />
|
||||||
<LinkFooter />
|
<LinkFooter />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { Fragment } from 'react'
|
||||||
|
import { openModal } from '../actions/modal'
|
||||||
|
import GroupSidebarPanel from '../components/panel/groups_panel'
|
||||||
|
import LinkFooter from '../components/link_footer'
|
||||||
|
import WhoToFollowPanel from '../components/panel/who_to_follow_panel'
|
||||||
|
import ProgressPanel from '../components/panel/progress_panel'
|
||||||
|
import UserPanel from '../components/panel/user_panel'
|
||||||
|
import TrendsPanel from '../components/panel/trends_panel'
|
||||||
|
import HashtagsPanel from '../components/panel/hashtags_panel'
|
||||||
|
import DefaultLayout from '../layouts/default_layout'
|
||||||
|
import TimelineComposeBlock from '../components/timeline_compose_block'
|
||||||
|
import Divider from '../components/divider'
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
onOpenHashtagPageSettingsModal(hashtag) {
|
||||||
|
dispatch(openModal('HASHTAG_TIMELINE_SETTINGS', {
|
||||||
|
hashtag,
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default
|
||||||
|
@connect(null, mapDispatchToProps)
|
||||||
|
class HashtagPage extends PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
onOpenHashtagPageSettingsModal: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
document.title = '(1) Tag - Gab'
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { children, onOpenHashtagPageSettingsModal } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DefaultLayout
|
||||||
|
title='Hashtag'
|
||||||
|
actions={[
|
||||||
|
{
|
||||||
|
icon: 'ellipsis',
|
||||||
|
onClick: onOpenHashtagPageSettingsModal,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
layout={(
|
||||||
|
<Fragment>
|
||||||
|
<ProgressPanel />
|
||||||
|
<TrendsPanel />
|
||||||
|
<HashtagsPanel />
|
||||||
|
<WhoToFollowPanel />
|
||||||
|
<GroupSidebarPanel />
|
||||||
|
<LinkFooter />
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</DefaultLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,21 +1,37 @@
|
||||||
import { Fragment } from 'react'
|
import { Fragment } from 'react'
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||||||
|
import { openModal } from '../actions/modal'
|
||||||
import LinkFooter from '../components/link_footer'
|
import LinkFooter from '../components/link_footer'
|
||||||
import DefaultLayout from '../layouts/default_layout'
|
import DefaultLayout from '../layouts/default_layout'
|
||||||
import ListDetailsPanel from '../components/panel/list_details_panel'
|
import ListDetailsPanel from '../components/panel/list_details_panel'
|
||||||
|
import WhoToFollowPanel from '../components/panel/who_to_follow_panel'
|
||||||
|
import TrendsPanel from '../components/panel/trends_panel'
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => ({
|
const mapStateToProps = (state, props) => ({
|
||||||
list: state.getIn(['lists', props.params.id]),
|
list: state.getIn(['lists', props.params.id]),
|
||||||
});
|
})
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch, { list }) => ({
|
||||||
|
onOpenListEditModal() {
|
||||||
|
dispatch(openModal('GROUP_DELETE', {
|
||||||
|
list,
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
onOpenListTimelineSettingsModal() {
|
||||||
|
dispatch(openModal('LIST_TIMELINE_SETTINGS'))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
export default
|
export default
|
||||||
@connect(mapStateToProps)
|
@connect(mapStateToProps, mapDispatchToProps)
|
||||||
class ListPage extends ImmutablePureComponent {
|
class ListPage extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
list: ImmutablePropTypes.map,
|
list: ImmutablePropTypes.map,
|
||||||
};
|
onOpenListEditModal: PropTypes.func.isRequired,
|
||||||
|
onOpenListTimelineSettingsModal: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { list } = this.props
|
const { list } = this.props
|
||||||
|
@ -23,27 +39,34 @@ class ListPage extends ImmutablePureComponent {
|
||||||
document.title = `List / ${listTitle} - Gab`
|
document.title = `List / ${listTitle} - Gab`
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEditListTimeline () {
|
|
||||||
console.log("handleEditListTimeline")
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { children, list } = this.props
|
const {
|
||||||
|
children,
|
||||||
|
list,
|
||||||
|
onOpenListEditModal,
|
||||||
|
onOpenListTimelineSettingsModal
|
||||||
|
} = this.props
|
||||||
|
|
||||||
const title = list ? list.get('title') : ''
|
const title = !!list ? list.get('title') : ''
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DefaultLayout
|
<DefaultLayout
|
||||||
title={title}
|
title={title}
|
||||||
actions={[
|
actions={[
|
||||||
|
{
|
||||||
|
icon: 'list-edit',
|
||||||
|
onClick: onOpenListEditModal,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
icon: 'ellipsis',
|
icon: 'ellipsis',
|
||||||
onClick: this.handleEditListTimeline
|
onClick: onOpenListTimelineSettingsModal,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
layout={(
|
layout={(
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<ListDetailsPanel />
|
<ListDetailsPanel />
|
||||||
|
<TrendsPanel />
|
||||||
|
<WhoToFollowPanel />
|
||||||
<LinkFooter />
|
<LinkFooter />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,37 +1,38 @@
|
||||||
import { Fragment } from 'react'
|
import { Fragment } from 'react'
|
||||||
|
import { openModal } from '../actions/modal';
|
||||||
import LinkFooter from '../components/link_footer'
|
import LinkFooter from '../components/link_footer'
|
||||||
import WhoToFollowPanel from '../components/panel/who_to_follow_panel'
|
import WhoToFollowPanel from '../components/panel/who_to_follow_panel'
|
||||||
import TrendsPanel from '../components/panel/trends_panel'
|
import TrendsPanel from '../components/panel/trends_panel'
|
||||||
import DefaultLayout from '../layouts/default_layout'
|
import DefaultLayout from '../layouts/default_layout'
|
||||||
|
|
||||||
export default class ListsPage extends PureComponent {
|
const mapDispatchToProps = dispatch => ({
|
||||||
|
onOpenListCreateModal() {
|
||||||
|
dispatch(openModal('LIST_CREATE'))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default
|
||||||
|
@connect(null, mapDispatchToProps)
|
||||||
|
class ListsPage extends PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
onOpenListCreateModal: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
document.title = 'Lists - Gab'
|
document.title = 'Lists - Gab'
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClickNewList () {
|
|
||||||
console.log("handleClickNewList")
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClickEditLists () {
|
|
||||||
console.log("handleClickEditLists")
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { children } = this.props
|
const { children, onOpenListCreateModal } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DefaultLayout
|
<DefaultLayout
|
||||||
title='Lists'
|
title='Lists'
|
||||||
actions={[
|
actions={[
|
||||||
{
|
|
||||||
icon: 'list-delete',
|
|
||||||
onClick: this.handleClickEditLists
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
icon: 'list-add',
|
icon: 'list-add',
|
||||||
onClick: this.handleClickNewList
|
onClick: onOpenListCreateModal
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
layout={(
|
layout={(
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
import { Fragment } from 'react'
|
||||||
|
import { openModal } from '../actions/modal'
|
||||||
|
import GroupSidebarPanel from '../components/panel/groups_panel'
|
||||||
|
import LinkFooter from '../components/link_footer'
|
||||||
|
import WhoToFollowPanel from '../components/panel/who_to_follow_panel'
|
||||||
|
import ProgressPanel from '../components/panel/progress_panel'
|
||||||
|
import UserPanel from '../components/panel/user_panel'
|
||||||
|
import TrendsPanel from '../components/panel/trends_panel'
|
||||||
|
import HashtagsPanel from '../components/panel/hashtags_panel'
|
||||||
|
import DefaultLayout from '../layouts/default_layout'
|
||||||
|
import TimelineComposeBlock from '../components/timeline_compose_block'
|
||||||
|
import Divider from '../components/divider'
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
onOpenHomePageSettingsModal() {
|
||||||
|
dispatch(openModal('HOME_TIMELINE_SETTINGS'))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default
|
||||||
|
@connect(null, mapDispatchToProps)
|
||||||
|
class ShortcutsPage extends PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
onOpenHomePageSettingsModal: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
document.title = '(1) Home - Gab'
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { children, onOpenHomePageSettingsModal } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DefaultLayout
|
||||||
|
title='Shortcuts'
|
||||||
|
actions={[
|
||||||
|
{
|
||||||
|
icon: 'ellipsis',
|
||||||
|
onClick: onOpenHomePageSettingsModal,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
layout={(
|
||||||
|
<Fragment>
|
||||||
|
<UserPanel />
|
||||||
|
<ProgressPanel />
|
||||||
|
<TrendsPanel />
|
||||||
|
<HashtagsPanel />
|
||||||
|
<WhoToFollowPanel />
|
||||||
|
<GroupSidebarPanel />
|
||||||
|
<LinkFooter />
|
||||||
|
</Fragment>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<TimelineComposeBlock autoFocus={false} />
|
||||||
|
<Divider />
|
||||||
|
{children}
|
||||||
|
</DefaultLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ import {
|
||||||
COMPOSE_REPLY,
|
COMPOSE_REPLY,
|
||||||
COMPOSE_REPLY_CANCEL,
|
COMPOSE_REPLY_CANCEL,
|
||||||
COMPOSE_QUOTE,
|
COMPOSE_QUOTE,
|
||||||
COMPOSE_DIRECT,
|
|
||||||
COMPOSE_MENTION,
|
COMPOSE_MENTION,
|
||||||
COMPOSE_SUBMIT_REQUEST,
|
COMPOSE_SUBMIT_REQUEST,
|
||||||
COMPOSE_SUBMIT_SUCCESS,
|
COMPOSE_SUBMIT_SUCCESS,
|
||||||
|
@ -325,14 +324,6 @@ export default function compose(state = initialState, action) {
|
||||||
map.set('caretPosition', null);
|
map.set('caretPosition', null);
|
||||||
map.set('idempotencyKey', uuid());
|
map.set('idempotencyKey', uuid());
|
||||||
});
|
});
|
||||||
case COMPOSE_DIRECT:
|
|
||||||
return state.withMutations(map => {
|
|
||||||
map.update('text', text => [text.trim(), `@${action.account.get('acct')} `].filter((str) => str.length !== 0).join(' '));
|
|
||||||
map.set('privacy', 'direct');
|
|
||||||
map.set('focusDate', new Date());
|
|
||||||
map.set('caretPosition', null);
|
|
||||||
map.set('idempotencyKey', uuid());
|
|
||||||
});
|
|
||||||
case COMPOSE_SUGGESTIONS_CLEAR:
|
case COMPOSE_SUGGESTIONS_CLEAR:
|
||||||
return state.update('suggestions', ImmutableList(), list => list.clear()).set('suggestion_token', null);
|
return state.update('suggestions', ImmutableList(), list => list.clear()).set('suggestion_token', null);
|
||||||
case COMPOSE_SUGGESTIONS_READY:
|
case COMPOSE_SUGGESTIONS_READY:
|
||||||
|
|
|
@ -7,7 +7,6 @@ import {
|
||||||
import {
|
import {
|
||||||
COMPOSE_MENTION,
|
COMPOSE_MENTION,
|
||||||
COMPOSE_REPLY,
|
COMPOSE_REPLY,
|
||||||
COMPOSE_DIRECT,
|
|
||||||
} from '../actions/compose';
|
} from '../actions/compose';
|
||||||
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
|
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
|
||||||
|
|
||||||
|
@ -36,7 +35,6 @@ export default function search(state = initialState, action) {
|
||||||
return state.set('hidden', false);
|
return state.set('hidden', false);
|
||||||
case COMPOSE_REPLY:
|
case COMPOSE_REPLY:
|
||||||
case COMPOSE_MENTION:
|
case COMPOSE_MENTION:
|
||||||
case COMPOSE_DIRECT:
|
|
||||||
return state.set('hidden', true);
|
return state.set('hidden', true);
|
||||||
case SEARCH_FETCH_SUCCESS:
|
case SEARCH_FETCH_SUCCESS:
|
||||||
return state.set('results', ImmutableMap({
|
return state.set('results', ImmutableMap({
|
||||||
|
|
|
@ -15,18 +15,31 @@ const initialState = ImmutableMap({
|
||||||
|
|
||||||
home: ImmutableMap({
|
home: ImmutableMap({
|
||||||
shows: ImmutableMap({
|
shows: ImmutableMap({
|
||||||
repost: true,
|
photos: true,
|
||||||
|
polls: true,
|
||||||
reply: true,
|
reply: true,
|
||||||
}),
|
repost: true,
|
||||||
|
videos: true,
|
||||||
regex: ImmutableMap({
|
|
||||||
body: '',
|
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
group: ImmutableMap({
|
lists: ImmutableMap({
|
||||||
shows: ImmutableMap({
|
shows: ImmutableMap({
|
||||||
|
photos: true,
|
||||||
|
polls: true,
|
||||||
reply: true,
|
reply: true,
|
||||||
|
repost: true,
|
||||||
|
videos: true,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
|
||||||
|
groups: ImmutableMap({
|
||||||
|
shows: ImmutableMap({
|
||||||
|
photos: true,
|
||||||
|
polls: true,
|
||||||
|
reply: true,
|
||||||
|
repost: true,
|
||||||
|
videos: true,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
@ -63,29 +76,10 @@ const initialState = ImmutableMap({
|
||||||
}),
|
}),
|
||||||
|
|
||||||
community: ImmutableMap({
|
community: ImmutableMap({
|
||||||
other: ImmutableMap({
|
shows: ImmutableMap({
|
||||||
allFediverse: false,
|
inSidebar: false,
|
||||||
onlyMedia: false,
|
onlyMedia: false,
|
||||||
}),
|
}),
|
||||||
regex: ImmutableMap({
|
|
||||||
body: '',
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
public: ImmutableMap({
|
|
||||||
regex: ImmutableMap({
|
|
||||||
body: '',
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
direct: ImmutableMap({
|
|
||||||
regex: ImmutableMap({
|
|
||||||
body: '',
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
trends: ImmutableMap({
|
|
||||||
show: true,
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,12 @@ const BREAKPOINT_MEDIUM = 1160
|
||||||
const BREAKPOINT_SMALL = 1080
|
const BREAKPOINT_SMALL = 1080
|
||||||
const BREAKPOINT_EXTRA_SMALL = 992
|
const BREAKPOINT_EXTRA_SMALL = 992
|
||||||
|
|
||||||
|
const LAYOUT_BREAKPOINT = 630
|
||||||
|
|
||||||
|
export function isMobile(width) {
|
||||||
|
return width <= LAYOUT_BREAKPOINT
|
||||||
|
}
|
||||||
|
|
||||||
export function breakpointExtraLarge(width) {
|
export function breakpointExtraLarge(width) {
|
||||||
return width > BREAKPOINT_EXTRA_LARGE
|
return width > BREAKPOINT_EXTRA_LARGE
|
||||||
}
|
}
|
||||||
|
@ -42,12 +48,11 @@ export function getScreenBreakpoint(width) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
export const getWindowDimension = () => {
|
||||||
|
const width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
|
||||||
const LAYOUT_BREAKPOINT = 630
|
const height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
|
||||||
|
|
||||||
export function isMobile(width) {
|
return { width, height }
|
||||||
return width <= LAYOUT_BREAKPOINT
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream
|
const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class REST::ListSerializer < ActiveModel::Serializer
|
class REST::ListSerializer < ActiveModel::Serializer
|
||||||
attributes :id, :title
|
attributes :id, :title, :created_at
|
||||||
|
|
||||||
def id
|
def id
|
||||||
object.id.to_s
|
object.id.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -93,6 +93,7 @@
|
||||||
"cssnano": "^4.1.10",
|
"cssnano": "^4.1.10",
|
||||||
"detect-passive-events": "^1.0.2",
|
"detect-passive-events": "^1.0.2",
|
||||||
"dotenv": "^8.0.0",
|
"dotenv": "^8.0.0",
|
||||||
|
"draft-js": "^0.11.4",
|
||||||
"emoji-mart": "Gargron/emoji-mart#build",
|
"emoji-mart": "Gargron/emoji-mart#build",
|
||||||
"es6-symbol": "^3.1.1",
|
"es6-symbol": "^3.1.1",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
|
|
Loading…
Reference in New Issue