mirror of
https://github.com/glitch-soc/mastodon.git
synced 2026-03-29 19:21:36 +02:00
Compare commits
19 Commits
unify-time
...
more-front
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da2b6dda6a | ||
|
|
ed82421870 | ||
|
|
b3904c2553 | ||
|
|
101a4c6913 | ||
|
|
11da74dbb7 | ||
|
|
51a86b32c3 | ||
|
|
51b783cdbc | ||
|
|
3915f06b02 | ||
|
|
07b1171c73 | ||
|
|
571576d6f7 | ||
|
|
7151ec7680 | ||
|
|
a4b3009c1c | ||
|
|
ef30a92c71 | ||
|
|
613aa55e03 | ||
|
|
88a08d54b6 | ||
|
|
3a69d70eae | ||
|
|
9c778f4abf | ||
|
|
ac61ce5826 | ||
|
|
73d6da32be |
1
.babelrc
1
.babelrc
@@ -15,7 +15,6 @@
|
||||
"plugins": [
|
||||
"syntax-dynamic-import",
|
||||
["transform-object-rest-spread", { "useBuiltIns": true }],
|
||||
"transform-decorators-legacy",
|
||||
"transform-class-properties",
|
||||
[
|
||||
"react-intl",
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
---
|
||||
root: true
|
||||
|
||||
env:
|
||||
browser: true
|
||||
node: true
|
||||
node: false
|
||||
es6: true
|
||||
|
||||
parser: babel-eslint
|
||||
@@ -54,14 +52,8 @@ rules:
|
||||
no-mixed-spaces-and-tabs: warn
|
||||
no-nested-ternary: warn
|
||||
no-trailing-spaces: warn
|
||||
no-undef: error
|
||||
no-unreachable: error
|
||||
no-unused-expressions: error
|
||||
no-unused-vars:
|
||||
- error
|
||||
- vars: all
|
||||
args: after-used
|
||||
ignoreRestSiblings: true
|
||||
object-curly-spacing:
|
||||
- error
|
||||
- always
|
||||
@@ -89,10 +81,7 @@ rules:
|
||||
- 2
|
||||
react/jsx-no-bind: error
|
||||
react/jsx-no-duplicate-props: error
|
||||
react/jsx-no-undef: error
|
||||
react/jsx-tag-spacing: error
|
||||
react/jsx-uses-react: error
|
||||
react/jsx-uses-vars: error
|
||||
react/jsx-wrap-multilines: error
|
||||
react/no-multi-comp: off
|
||||
react/no-string-refs: error
|
||||
|
||||
@@ -7,7 +7,7 @@ cache:
|
||||
- public/assets
|
||||
- public/packs-test
|
||||
dist: trusty
|
||||
sudo: required
|
||||
sudo: false
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
5
Vagrantfile
vendored
5
Vagrantfile
vendored
@@ -42,12 +42,9 @@ sudo apt-get install \
|
||||
# Install rvm
|
||||
read RUBY_VERSION < .ruby-version
|
||||
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
|
||||
curl -sSL https://raw.githubusercontent.com/rvm/rvm/stable/binscripts/rvm-installer | bash -s stable --ruby=$RUBY_VERSION
|
||||
curl -sSL https://get.rvm.io | bash -s stable --ruby=$RUBY_VERSION
|
||||
source /home/vagrant/.rvm/scripts/rvm
|
||||
|
||||
# Install Ruby
|
||||
rvm install ruby-$RUBY_VERSION
|
||||
|
||||
# Configure database
|
||||
sudo -u postgres createuser -U postgres vagrant -s
|
||||
sudo -u postgres createdb -U postgres mastodon_development
|
||||
|
||||
@@ -9,6 +9,7 @@ class HomeController < ApplicationController
|
||||
@web_settings = Web::Setting.find_by(user: current_user)&.data || {}
|
||||
@admin = Account.find_local(Setting.site_contact_username)
|
||||
@streaming_api_base_url = Rails.configuration.x.streaming_api_base_url
|
||||
@frontend = (params[:frontend] and Rails.configuration.x.available_frontends.include? params[:frontend] + '.js') ? params[:frontend] : 'mastodon'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import api, { getLinks } from '../api';
|
||||
import Immutable from 'immutable';
|
||||
|
||||
export const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST';
|
||||
export const ACCOUNT_FETCH_SUCCESS = 'ACCOUNT_FETCH_SUCCESS';
|
||||
@@ -596,7 +597,7 @@ export function authorizeFollowRequest(id) {
|
||||
|
||||
api(getState)
|
||||
.post(`/api/v1/follow_requests/${id}/authorize`)
|
||||
.then(() => dispatch(authorizeFollowRequestSuccess(id)))
|
||||
.then(response => dispatch(authorizeFollowRequestSuccess(id)))
|
||||
.catch(error => dispatch(authorizeFollowRequestFail(id, error)));
|
||||
};
|
||||
};
|
||||
@@ -630,7 +631,7 @@ export function rejectFollowRequest(id) {
|
||||
|
||||
api(getState)
|
||||
.post(`/api/v1/follow_requests/${id}/reject`)
|
||||
.then(() => dispatch(rejectFollowRequestSuccess(id)))
|
||||
.then(response => dispatch(rejectFollowRequestSuccess(id)))
|
||||
.catch(error => dispatch(rejectFollowRequestFail(id, error)));
|
||||
};
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ export function blockDomain(domain, accountId) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(blockDomainRequest(domain));
|
||||
|
||||
api(getState).post('/api/v1/domain_blocks', { domain }).then(() => {
|
||||
api(getState).post('/api/v1/domain_blocks', { domain }).then(response => {
|
||||
dispatch(blockDomainSuccess(domain, accountId));
|
||||
}).catch(err => {
|
||||
dispatch(blockDomainFail(domain, err));
|
||||
@@ -51,7 +51,7 @@ export function unblockDomain(domain, accountId) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(unblockDomainRequest(domain));
|
||||
|
||||
api(getState).delete('/api/v1/domain_blocks', { params: { domain } }).then(() => {
|
||||
api(getState).delete('/api/v1/domain_blocks', { params: { domain } }).then(response => {
|
||||
dispatch(unblockDomainSuccess(domain, accountId));
|
||||
}).catch(err => {
|
||||
dispatch(unblockDomainFail(domain, err));
|
||||
|
||||
@@ -17,7 +17,7 @@ export const NOTIFICATIONS_EXPAND_FAIL = 'NOTIFICATIONS_EXPAND_FAIL';
|
||||
export const NOTIFICATIONS_CLEAR = 'NOTIFICATIONS_CLEAR';
|
||||
export const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP';
|
||||
|
||||
defineMessages({
|
||||
const messages = defineMessages({
|
||||
mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' },
|
||||
});
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ export function deleteStatus(id) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(deleteStatusRequest(id));
|
||||
|
||||
api(getState).delete(`/api/v1/statuses/${id}`).then(() => {
|
||||
api(getState).delete(`/api/v1/statuses/${id}`).then(response => {
|
||||
dispatch(deleteStatusSuccess(id));
|
||||
dispatch(deleteFromTimelines(id));
|
||||
}).catch(error => {
|
||||
@@ -152,7 +152,7 @@ export function muteStatus(id) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(muteStatusRequest(id));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${id}/mute`).then(() => {
|
||||
api(getState).post(`/api/v1/statuses/${id}/mute`).then(response => {
|
||||
dispatch(muteStatusSuccess(id));
|
||||
}).catch(error => {
|
||||
dispatch(muteStatusFail(id, error));
|
||||
@@ -186,7 +186,7 @@ export function unmuteStatus(id) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(unmuteStatusRequest(id));
|
||||
|
||||
api(getState).post(`/api/v1/statuses/${id}/unmute`).then(() => {
|
||||
api(getState).post(`/api/v1/statuses/${id}/unmute`).then(response => {
|
||||
dispatch(unmuteStatusSuccess(id));
|
||||
}).catch(error => {
|
||||
dispatch(unmuteStatusFail(id, error));
|
||||
|
||||
@@ -16,8 +16,7 @@ const messages = defineMessages({
|
||||
unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class Account extends ImmutablePureComponent {
|
||||
class Account extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
@@ -83,3 +82,5 @@ export default class Account extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(Account);
|
||||
|
||||
@@ -4,7 +4,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
const filename = url => url.split('/').pop().split('#')[0].split('?')[0];
|
||||
|
||||
export default class AttachmentList extends ImmutablePureComponent {
|
||||
class AttachmentList extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
media: ImmutablePropTypes.list.isRequired,
|
||||
@@ -31,3 +31,5 @@ export default class AttachmentList extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AttachmentList;
|
||||
|
||||
@@ -31,7 +31,7 @@ const textAtCursorMatchesToken = (str, caretPosition) => {
|
||||
}
|
||||
};
|
||||
|
||||
export default class AutosuggestTextarea extends ImmutablePureComponent {
|
||||
class AutosuggestTextarea extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
value: PropTypes.string,
|
||||
@@ -196,3 +196,5 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AutosuggestTextarea;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class Avatar extends React.PureComponent {
|
||||
class Avatar extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
src: PropTypes.string.isRequired,
|
||||
@@ -66,3 +66,5 @@ export default class Avatar extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Avatar;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class AvatarOverlay extends React.PureComponent {
|
||||
class AvatarOverlay extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
staticSrc: PropTypes.string.isRequired,
|
||||
@@ -28,3 +28,5 @@ export default class AvatarOverlay extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AvatarOverlay;
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export default class Button extends React.PureComponent {
|
||||
class Button extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
text: PropTypes.node,
|
||||
@@ -61,3 +61,5 @@ export default class Button extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Button;
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import scrollTop from '../scroll';
|
||||
|
||||
export default class Column extends React.PureComponent {
|
||||
class Column extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
children: PropTypes.node,
|
||||
@@ -41,3 +41,5 @@ export default class Column extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Column;
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class ColumnBackButton extends React.PureComponent {
|
||||
class ColumnBackButton extends React.PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
@@ -23,3 +23,5 @@ export default class ColumnBackButton extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ColumnBackButton;
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class ColumnBackButtonSlim extends React.PureComponent {
|
||||
class ColumnBackButtonSlim extends React.PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
@@ -25,3 +25,5 @@ export default class ColumnBackButtonSlim extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ColumnBackButtonSlim;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class ColumnCollapsable extends React.PureComponent {
|
||||
class ColumnCollapsable extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
icon: PropTypes.string.isRequired,
|
||||
@@ -48,3 +48,5 @@ export default class ColumnCollapsable extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ColumnCollapsable;
|
||||
|
||||
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
export default class ColumnHeader extends React.PureComponent {
|
||||
class ColumnHeader extends React.PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
@@ -141,3 +141,5 @@ export default class ColumnHeader extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ColumnHeader;
|
||||
|
||||
@@ -3,7 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import escapeTextContentForBrowser from 'escape-html';
|
||||
import emojify from '../emoji';
|
||||
|
||||
export default class DisplayName extends React.PureComponent {
|
||||
class DisplayName extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
@@ -21,3 +21,5 @@ export default class DisplayName extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DisplayName;
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import Dropdown, { DropdownTrigger, DropdownContent } from 'react-simple-dropdown';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class DropdownMenu extends React.PureComponent {
|
||||
class DropdownMenu extends React.PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
@@ -56,7 +56,7 @@ export default class DropdownMenu extends React.PureComponent {
|
||||
return <li key={`sep-${i}`} className='dropdown__sep' />;
|
||||
}
|
||||
|
||||
const { text, href = '#' } = item;
|
||||
const { text, action, href = '#' } = item;
|
||||
|
||||
return (
|
||||
<li className='dropdown__content-list-item' key={`${text}-${i}`}>
|
||||
@@ -92,3 +92,5 @@ export default class DropdownMenu extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DropdownMenu;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class ExtendedVideoPlayer extends React.PureComponent {
|
||||
class ExtendedVideoPlayer extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
src: PropTypes.string.isRequired,
|
||||
@@ -44,3 +44,5 @@ export default class ExtendedVideoPlayer extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ExtendedVideoPlayer;
|
||||
|
||||
@@ -3,7 +3,7 @@ import Motion from 'react-motion/lib/Motion';
|
||||
import spring from 'react-motion/lib/spring';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class IconButton extends React.PureComponent {
|
||||
class IconButton extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
className: PropTypes.string,
|
||||
@@ -87,3 +87,5 @@ export default class IconButton extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default IconButton;
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class LoadMore extends React.PureComponent {
|
||||
class LoadMore extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
onClick: PropTypes.func,
|
||||
@@ -17,3 +17,5 @@ export default class LoadMore extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default LoadMore;
|
||||
|
||||
@@ -123,8 +123,7 @@ class Item extends React.PureComponent {
|
||||
|
||||
}
|
||||
|
||||
@injectIntl
|
||||
export default class MediaGallery extends React.PureComponent {
|
||||
class MediaGallery extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
sensitive: PropTypes.bool,
|
||||
@@ -139,7 +138,7 @@ export default class MediaGallery extends React.PureComponent {
|
||||
visible: !this.props.sensitive,
|
||||
};
|
||||
|
||||
handleOpen = () => {
|
||||
handleOpen = (e) => {
|
||||
this.setState({ visible: !this.state.visible });
|
||||
}
|
||||
|
||||
@@ -184,3 +183,5 @@ export default class MediaGallery extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(MediaGallery);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class Permalink extends React.PureComponent {
|
||||
class Permalink extends React.PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
@@ -32,3 +32,5 @@ export default class Permalink extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Permalink;
|
||||
|
||||
@@ -11,8 +11,7 @@ const dateFormatOptions = {
|
||||
minute: '2-digit',
|
||||
};
|
||||
|
||||
@injectIntl
|
||||
export default class RelativeTimestamp extends React.Component {
|
||||
class RelativeTimestamp extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
@@ -38,3 +37,5 @@ export default class RelativeTimestamp extends React.Component {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(RelativeTimestamp);
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
export default class SettingText extends React.PureComponent {
|
||||
class SettingText extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
@@ -29,3 +29,5 @@ export default class SettingText extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default SettingText;
|
||||
|
||||
@@ -6,6 +6,7 @@ import AvatarOverlay from './avatar_overlay';
|
||||
import DisplayName from './display_name';
|
||||
import MediaGallery from './media_gallery';
|
||||
import VideoPlayer from './video_player';
|
||||
import AttachmentList from './attachment_list';
|
||||
import StatusContent from './status_content';
|
||||
import StatusActionBar from './status_action_bar';
|
||||
import IconButton from './icon_button';
|
||||
@@ -20,7 +21,7 @@ const messages = defineMessages({
|
||||
uncollapse: { id: 'status.uncollapse', defaultMessage: 'Uncollapse' },
|
||||
});
|
||||
|
||||
class StatusUnextended extends ImmutablePureComponent {
|
||||
class Status extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
@@ -103,7 +104,7 @@ class StatusUnextended extends ImmutablePureComponent {
|
||||
this.handleIntersection
|
||||
);
|
||||
|
||||
if (node.clientHeight > 400 && !(this.props.status.get('reblog', null) !== null && typeof this.props.status.get('reblog') === 'object')) this.setState({ isCollapsed: true });
|
||||
if (node.clientHeight > 400) this.setState({ isCollapsed: true });
|
||||
|
||||
this.componentMounted = true;
|
||||
}
|
||||
@@ -176,10 +177,7 @@ class StatusUnextended extends ImmutablePureComponent {
|
||||
render () {
|
||||
let media = null;
|
||||
let statusAvatar;
|
||||
|
||||
// Exclude intersectionObserverWrapper from `other` variable
|
||||
// because intersection is managed in here.
|
||||
const { status, account, intersectionObserverWrapper, intl, ...other } = this.props;
|
||||
const { status, account, intl, ...other } = this.props;
|
||||
const { isExpanded, isIntersecting, isHidden, isCollapsed } = this.state;
|
||||
|
||||
if (status === null) {
|
||||
@@ -259,12 +257,11 @@ class StatusUnextended extends ImmutablePureComponent {
|
||||
|
||||
{isCollapsed ? null : media}
|
||||
|
||||
{isCollapsed ? null : <StatusActionBar status={status} account={account} {...other} />}
|
||||
{isCollapsed ? null : <StatusActionBar {...this.props} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const Status = injectIntl(StatusUnextended);
|
||||
export default Status;
|
||||
export default injectIntl(Status);
|
||||
|
||||
@@ -23,8 +23,7 @@ const messages = defineMessages({
|
||||
unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class StatusActionBar extends ImmutablePureComponent {
|
||||
class StatusActionBar extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
@@ -153,3 +152,5 @@ export default class StatusActionBar extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(StatusActionBar);
|
||||
|
||||
@@ -7,7 +7,7 @@ import { isRtl } from '../rtl';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import Permalink from './permalink';
|
||||
|
||||
export default class StatusContent extends React.PureComponent {
|
||||
class StatusContent extends React.PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
@@ -32,6 +32,7 @@ export default class StatusContent extends React.PureComponent {
|
||||
for (var i = 0; i < links.length; ++i) {
|
||||
let link = links[i];
|
||||
let mention = this.props.status.get('mentions').find(item => link.href === item.get('url'));
|
||||
let media = this.props.status.get('media_attachments').find(item => link.href === item.get('text_url') || (item.get('remote_url').length > 0 && link.href === item.get('remote_url')));
|
||||
|
||||
if (mention) {
|
||||
link.addEventListener('click', this.onMentionClick.bind(this, mention), false);
|
||||
@@ -135,7 +136,7 @@ export default class StatusContent extends React.PureComponent {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='status__content status__content--with-action' ref={this.setRef} onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp}>
|
||||
<div className='status__content status__content--with_action' ref={this.setRef} onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp}>
|
||||
<p style={{ marginBottom: hidden && status.get('mentions').isEmpty() ? '0px' : null }}>
|
||||
<span dangerouslySetInnerHTML={spoilerContent} />
|
||||
{' '}
|
||||
@@ -171,3 +172,5 @@ export default class StatusContent extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default StatusContent;
|
||||
|
||||
@@ -8,7 +8,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import IntersectionObserverWrapper from '../features/ui/util/intersection_observer_wrapper';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
export default class StatusList extends ImmutablePureComponent {
|
||||
class StatusList extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
scrollKey: PropTypes.string.isRequired,
|
||||
@@ -99,7 +99,7 @@ export default class StatusList extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { statusIds, scrollKey, trackScroll, shouldUpdateScroll, isLoading, hasMore, prepend, emptyMessage } = this.props;
|
||||
const { statusIds, onScrollToBottom, scrollKey, trackScroll, shouldUpdateScroll, isLoading, hasMore, prepend, emptyMessage } = this.props;
|
||||
|
||||
let loadMore = null;
|
||||
let scrollableArea = null;
|
||||
@@ -142,3 +142,5 @@ export default class StatusList extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default StatusList;
|
||||
|
||||
@@ -11,8 +11,7 @@ const messages = defineMessages({
|
||||
expand_video: { id: 'video_player.expand', defaultMessage: 'Expand video' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class VideoPlayer extends React.PureComponent {
|
||||
class VideoPlayer extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
media: ImmutablePropTypes.map.isRequired,
|
||||
@@ -194,3 +193,5 @@ export default class VideoPlayer extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(VideoPlayer);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Provider } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import configureStore from '../store/configureStore';
|
||||
import {
|
||||
refreshTimelineSuccess,
|
||||
updateTimeline,
|
||||
deleteFromTimelines,
|
||||
refreshHomeTimeline,
|
||||
@@ -26,11 +27,7 @@ const store = configureStore();
|
||||
const initialState = JSON.parse(document.getElementById('initial-state').textContent);
|
||||
store.dispatch(hydrateStore(initialState));
|
||||
|
||||
export default class Mastodon extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.string.isRequired,
|
||||
};
|
||||
class Mastodon extends React.PureComponent {
|
||||
|
||||
componentDidMount() {
|
||||
const { locale } = this.props;
|
||||
@@ -121,3 +118,9 @@ export default class Mastodon extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Mastodon.propTypes = {
|
||||
locale: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default Mastodon;
|
||||
|
||||
@@ -19,6 +19,8 @@ import {
|
||||
import { muteStatus, unmuteStatus, deleteStatus } from '../actions/statuses';
|
||||
import { initReport } from '../actions/reports';
|
||||
import { openModal } from '../actions/modal';
|
||||
import { createSelector } from 'reselect';
|
||||
import { isMobile } from '../is_mobile';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
const messages = defineMessages({
|
||||
|
||||
@@ -21,8 +21,7 @@ const messages = defineMessages({
|
||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class ActionBar extends React.PureComponent {
|
||||
class ActionBar extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
@@ -106,3 +105,5 @@ export default class ActionBar extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(ActionBar);
|
||||
|
||||
@@ -5,7 +5,9 @@ import emojify from '../../../emoji';
|
||||
import escapeTextContentForBrowser from 'escape-html';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import IconButton from '../../../components/icon_button';
|
||||
import Avatar from '../../../components/avatar';
|
||||
import Motion from 'react-motion/lib/Motion';
|
||||
import spring from 'react-motion/lib/spring';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -39,40 +41,94 @@ const messages = defineMessages({
|
||||
@kibi@glitch.social <3
|
||||
*/
|
||||
|
||||
const NEW_LINE = /(?:^|\r?\n|<br\s*\/?>)/g;
|
||||
const NEW_LINE = /(?:^|\r?\n|<br\s*\/?>)/g
|
||||
const YAML_OPENER = /---/;
|
||||
const YAML_CLOSER = /(?:---|\.\.\.)/;
|
||||
const YAML_STRING = /(?:"(?:[^"\n]){1,32}"|'(?:[^'\n]){1,32}'|(?:[^'":\n]){1,32})/g;
|
||||
const YAML_LINE = new RegExp('\\s*' + YAML_STRING.source + '\\s*:\\s*' + YAML_STRING.source + '\\s*', 'g');
|
||||
const BIO_REGEX = new RegExp(NEW_LINE.source + '*' + YAML_OPENER.source + NEW_LINE.source + '+(?:' + YAML_LINE.source + NEW_LINE.source + '+){0,4}' + YAML_CLOSER.source + NEW_LINE.source + '*');
|
||||
const YAML_LINE = new RegExp("\\s*" + YAML_STRING.source + "\\s*:\\s*" + YAML_STRING.source + "\\s*", "g");
|
||||
const BIO_REGEX = new RegExp(NEW_LINE.source + "*" + YAML_OPENER.source + NEW_LINE.source + "+(?:" + YAML_LINE.source + NEW_LINE.source + "+){0,4}" + YAML_CLOSER.source + NEW_LINE.source + "*");
|
||||
|
||||
const processBio = (data) => {
|
||||
let props = { text: data, metadata: [] };
|
||||
let props = {text: data, metadata: []};
|
||||
let yaml = data.match(BIO_REGEX);
|
||||
if (!yaml) return props;
|
||||
else yaml = yaml[0];
|
||||
let start = props.text.indexOf(yaml);
|
||||
let end = start + yaml.length;
|
||||
props.text = props.text.substr(0, start) + props.text.substr(end);
|
||||
yaml = yaml.replace(NEW_LINE, '\n');
|
||||
yaml = yaml.replace(NEW_LINE, "\n");
|
||||
let metadata = (yaml ? yaml.match(YAML_LINE) : []) || [];
|
||||
for (let i = 0; i < metadata.length; i++) {
|
||||
let result = metadata[i].match(YAML_STRING);
|
||||
if (result[0][0] === '"' || result[0][0] === '\'') result[0] = result[0].substr(1, result[0].length - 2);
|
||||
if (result[1][0] === '"' || result[1][0] === '\'') result[0] = result[1].substr(1, result[1].length - 2);
|
||||
if (result[0][0] === '"' || result[0][0] === "'") result[0] = result[0].substr(1, result[0].length - 2);
|
||||
if (result[1][0] === '"' || result[1][0] === "'") result[0] = result[1].substr(1, result[1].length - 2);
|
||||
props.metadata.push(result);
|
||||
}
|
||||
return props;
|
||||
};
|
||||
|
||||
@injectIntl
|
||||
export default class Header extends ImmutablePureComponent {
|
||||
const makeMapStateToProps = () => {
|
||||
const mapStateToProps = (state, props) => ({
|
||||
autoPlayGif: state.getIn(['meta', 'auto_play_gif']),
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
class Avatar extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
autoPlayGif: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
state = {
|
||||
isHovered: false,
|
||||
};
|
||||
|
||||
handleMouseOver = () => {
|
||||
if (this.state.isHovered) return;
|
||||
this.setState({ isHovered: true });
|
||||
}
|
||||
|
||||
handleMouseOut = () => {
|
||||
if (!this.state.isHovered) return;
|
||||
this.setState({ isHovered: false });
|
||||
}
|
||||
|
||||
render () {
|
||||
const { account, autoPlayGif } = this.props;
|
||||
const { isHovered } = this.state;
|
||||
|
||||
return (
|
||||
<Motion defaultStyle={{ radius: 90 }} style={{ radius: spring(isHovered ? 30 : 90, { stiffness: 180, damping: 12 }) }}>
|
||||
{({ radius }) =>
|
||||
<a // eslint-disable-line jsx-a11y/anchor-has-content
|
||||
href={account.get('url')}
|
||||
className='account__header__avatar'
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
style={{ borderRadius: `${radius}px`, backgroundImage: `url(${autoPlayGif || isHovered ? account.get('avatar') : account.get('avatar_static')})` }}
|
||||
onMouseOver={this.handleMouseOver}
|
||||
onMouseOut={this.handleMouseOut}
|
||||
onFocus={this.handleMouseOver}
|
||||
onBlur={this.handleMouseOut}
|
||||
/>
|
||||
}
|
||||
</Motion>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Header extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map,
|
||||
me: PropTypes.number.isRequired,
|
||||
onFollow: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
autoPlayGif: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
render () {
|
||||
@@ -122,12 +178,11 @@ export default class Header extends ImmutablePureComponent {
|
||||
<div className='account__header__wrapper'>
|
||||
<div className='account__header' style={{ backgroundImage: `url(${account.get('header')})` }}>
|
||||
<div>
|
||||
<a href={account.get('url')} target='_blank' rel='noopener'>
|
||||
<span className='account__header__avatar'><Avatar src={account.get('avatar')} animate size={90} /></span>
|
||||
<span className='account__header__display-name' dangerouslySetInnerHTML={displayNameHTML} />
|
||||
</a>
|
||||
<Avatar account={account} autoPlayGif={this.props.autoPlayGif} />
|
||||
|
||||
<span className='account__header__display-name' dangerouslySetInnerHTML={displayNameHTML} />
|
||||
<span className='account__header__username'>@{account.get('acct')} {lockedIcon}</span>
|
||||
<div className='account__header__content' dangerouslySetInnerHTML={{ __html: emojify(text) }} />
|
||||
<div className='account__header__content' dangerouslySetInnerHTML={{__html: emojify(text)}} />
|
||||
|
||||
{info}
|
||||
{actionBtn}
|
||||
@@ -142,11 +197,11 @@ export default class Header extends ImmutablePureComponent {
|
||||
data.push(
|
||||
<div
|
||||
className='account__metadata-item'
|
||||
title={metadata[i][0] + ':' + metadata[i][1]}
|
||||
title={metadata[i][0] + ":" + metadata[i][1]}
|
||||
key={i}
|
||||
>
|
||||
<span dangerouslySetInnerHTML={{ __html: emojify(metadata[i][0]) }} />
|
||||
<strong dangerouslySetInnerHTML={{ __html: emojify(metadata[i][1]) }} />
|
||||
<span dangerouslySetInnerHTML={{__html: emojify(metadata[i][0])}} />
|
||||
<strong dangerouslySetInnerHTML={{__html: emojify(metadata[i][1])}} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -159,3 +214,5 @@ export default class Header extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(makeMapStateToProps)(injectIntl(Header));
|
||||
|
||||
@@ -3,7 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import Permalink from '../../../components/permalink';
|
||||
|
||||
export default class MediaItem extends ImmutablePureComponent {
|
||||
class MediaItem extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
media: ImmutablePropTypes.map.isRequired,
|
||||
@@ -37,3 +37,5 @@ export default class MediaItem extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default MediaItem;
|
||||
|
||||
@@ -7,6 +7,7 @@ import { refreshAccountMediaTimeline, expandAccountMediaTimeline } from '../../a
|
||||
import LoadingIndicator from '../../components/loading_indicator';
|
||||
import Column from '../ui/components/column';
|
||||
import ColumnBackButton from '../../components/column_back_button';
|
||||
import Immutable from 'immutable';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { getAccountGallery } from '../../selectors';
|
||||
import MediaItem from './components/media_item';
|
||||
@@ -22,8 +23,7 @@ const mapStateToProps = (state, props) => ({
|
||||
autoPlayGif: state.getIn(['meta', 'auto_play_gif']),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export default class AccountGallery extends ImmutablePureComponent {
|
||||
class AccountGallery extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
@@ -112,3 +112,5 @@ export default class AccountGallery extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(AccountGallery);
|
||||
|
||||
@@ -6,7 +6,7 @@ import ActionBar from '../../account/components/action_bar';
|
||||
import MissingIndicator from '../../../components/missing_indicator';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
export default class Header extends ImmutablePureComponent {
|
||||
class Header extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map,
|
||||
@@ -91,3 +91,5 @@ export default class Header extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Header;
|
||||
|
||||
@@ -19,8 +19,7 @@ const mapStateToProps = (state, props) => ({
|
||||
me: state.getIn(['meta', 'me']),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export default class AccountTimeline extends ImmutablePureComponent {
|
||||
class AccountTimeline extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
@@ -78,3 +77,5 @@ export default class AccountTimeline extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(AccountTimeline);
|
||||
|
||||
@@ -19,9 +19,7 @@ const mapStateToProps = state => ({
|
||||
accountIds: state.getIn(['user_lists', 'blocks', 'items']),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
export default class Blocks extends ImmutablePureComponent {
|
||||
class Blocks extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
@@ -68,3 +66,5 @@ export default class Blocks extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(Blocks));
|
||||
|
||||
@@ -2,6 +2,8 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ColumnCollapsable from '../../../components/column_collapsable';
|
||||
import SettingToggle from '../../notifications/components/setting_toggle';
|
||||
import SettingText from '../../../components/setting_text';
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -9,17 +11,17 @@ const messages = defineMessages({
|
||||
settings: { id: 'home.settings', defaultMessage: 'Column settings' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class ColumnSettings extends React.PureComponent {
|
||||
class ColumnSettings extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onSave: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { settings, onChange, intl } = this.props;
|
||||
const { settings, onChange, onSave, intl } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -33,3 +35,5 @@ export default class ColumnSettings extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(ColumnSettings);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { connect } from 'react-redux';
|
||||
import ColumnSettings from '../components/column_settings';
|
||||
import { changeSetting } from '../../../actions/settings';
|
||||
import { changeSetting, saveSettings } from '../../../actions/settings';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
settings: state.getIn(['settings', 'community']),
|
||||
@@ -12,6 +12,10 @@ const mapDispatchToProps = dispatch => ({
|
||||
dispatch(changeSetting(['community', ...key], checked));
|
||||
},
|
||||
|
||||
onSave () {
|
||||
dispatch(saveSettings());
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings);
|
||||
|
||||
@@ -1,45 +1,146 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
import Column from '../../components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import {
|
||||
refreshCommunityTimeline,
|
||||
expandCommunityTimeline,
|
||||
updateTimeline,
|
||||
deleteFromTimelines,
|
||||
connectTimeline,
|
||||
disconnectTimeline,
|
||||
} from '../../actions/timelines';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
import Timeline from '../timeline';
|
||||
import createStream from '../../stream';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.community', defaultMessage: 'Local timeline' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class CommunityTimeline extends React.PureComponent {
|
||||
const mapStateToProps = state => ({
|
||||
hasUnread: state.getIn(['timelines', 'community', 'unread']) > 0,
|
||||
streamingAPIBaseURL: state.getIn(['meta', 'streaming_api_base_url']),
|
||||
accessToken: state.getIn(['meta', 'access_token']),
|
||||
});
|
||||
|
||||
class CommunityTimeline extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
intl: PropTypes.object.isRequired,
|
||||
streamingAPIBaseURL: PropTypes.string.isRequired,
|
||||
accessToken: PropTypes.string.isRequired,
|
||||
hasUnread: PropTypes.bool,
|
||||
multiColumn: PropTypes.bool,
|
||||
};
|
||||
|
||||
handlePin = () => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('COMMUNITY', {}));
|
||||
}
|
||||
}
|
||||
|
||||
handleMove = (dir) => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
dispatch(moveColumn(columnId, dir));
|
||||
}
|
||||
|
||||
handleHeaderClick = () => {
|
||||
this.column.scrollTop();
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch, streamingAPIBaseURL, accessToken } = this.props;
|
||||
|
||||
dispatch(refreshCommunityTimeline());
|
||||
|
||||
if (typeof this._subscription !== 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
this._subscription = createStream(streamingAPIBaseURL, accessToken, 'public:local', {
|
||||
|
||||
connected () {
|
||||
dispatch(connectTimeline('community'));
|
||||
},
|
||||
|
||||
reconnected () {
|
||||
dispatch(connectTimeline('community'));
|
||||
},
|
||||
|
||||
disconnected () {
|
||||
dispatch(disconnectTimeline('community'));
|
||||
},
|
||||
|
||||
received (data) {
|
||||
switch(data.event) {
|
||||
case 'update':
|
||||
dispatch(updateTimeline('community', JSON.parse(data.payload)));
|
||||
break;
|
||||
case 'delete':
|
||||
dispatch(deleteFromTimelines(data.payload));
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
if (typeof this._subscription !== 'undefined') {
|
||||
this._subscription.close();
|
||||
this._subscription = null;
|
||||
}
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.column = c;
|
||||
}
|
||||
|
||||
handleLoadMore = () => {
|
||||
this.props.dispatch(expandCommunityTimeline());
|
||||
}
|
||||
|
||||
render () {
|
||||
const { intl, columnId, multiColumn } = this.props;
|
||||
const { intl, hasUnread, columnId, multiColumn } = this.props;
|
||||
const pinned = !!columnId;
|
||||
|
||||
return (
|
||||
<Timeline
|
||||
expand={expandCommunityTimeline}
|
||||
refresh={refreshCommunityTimeline}
|
||||
streamId='public:local'
|
||||
columnName='COMMUNITY'
|
||||
columnId={columnId}
|
||||
mulitColumn={multiColumn}
|
||||
emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
|
||||
icon='users'
|
||||
title={intl.formatMessage(messages.title)}
|
||||
settings={<ColumnSettingsContainer />}
|
||||
scrollName='community_timeline'
|
||||
timelineId='community'
|
||||
/>
|
||||
<Column ref={this.setRef}>
|
||||
<ColumnHeader
|
||||
icon='users'
|
||||
active={hasUnread}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
onClick={this.handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
>
|
||||
<ColumnSettingsContainer />
|
||||
</ColumnHeader>
|
||||
|
||||
<StatusListContainer
|
||||
trackScroll={!pinned}
|
||||
scrollKey={`community_timeline-${columnId}`}
|
||||
timelineId='community'
|
||||
loadMore={this.handleLoadMore}
|
||||
emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(CommunityTimeline));
|
||||
|
||||
@@ -4,7 +4,7 @@ import DisplayName from '../../../components/display_name';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
export default class AutosuggestAccount extends ImmutablePureComponent {
|
||||
class AutosuggestAccount extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
@@ -22,3 +22,5 @@ export default class AutosuggestAccount extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AutosuggestAccount;
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { length } from 'stringz';
|
||||
|
||||
export default class CharacterCounter extends React.PureComponent {
|
||||
class CharacterCounter extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
text: PropTypes.string.isRequired,
|
||||
@@ -23,3 +23,5 @@ export default class CharacterCounter extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CharacterCounter;
|
||||
|
||||
@@ -7,13 +7,15 @@ import ReplyIndicatorContainer from '../containers/reply_indicator_container';
|
||||
import AutosuggestTextarea from '../../../components/autosuggest_textarea';
|
||||
import { debounce } from 'lodash';
|
||||
import UploadButtonContainer from '../containers/upload_button_container';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import Toggle from 'react-toggle';
|
||||
import Collapsable from '../../../components/collapsable';
|
||||
import SpoilerButtonContainer from '../containers/spoiler_button_container';
|
||||
import PrivacyDropdownContainer from '../containers/privacy_dropdown_container';
|
||||
import SensitiveButtonContainer from '../containers/sensitive_button_container';
|
||||
import EmojiPickerDropdown from './emoji_picker_dropdown';
|
||||
import UploadFormContainer from '../containers/upload_form_container';
|
||||
import TextIconButton from './text_icon_button';
|
||||
import WarningContainer from '../containers/warning_container';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { length } from 'stringz';
|
||||
@@ -25,8 +27,7 @@ const messages = defineMessages({
|
||||
publishLoud: { id: 'compose_form.publish_loud', defaultMessage: '{publish}!' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class ComposeForm extends ImmutablePureComponent {
|
||||
class ComposeForm extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
@@ -140,6 +141,7 @@ export default class ComposeForm extends ImmutablePureComponent {
|
||||
const text = [this.props.spoiler_text, this.props.text].join('');
|
||||
|
||||
let publishText = '';
|
||||
let reply_to_other = false;
|
||||
|
||||
if (this.props.privacy === 'private' || this.props.privacy === 'direct') {
|
||||
publishText = <span className='compose-form__publish-private'><i className='fa fa-lock' /> {intl.formatMessage(messages.publish)}</span>;
|
||||
@@ -200,3 +202,5 @@ export default class ComposeForm extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(ComposeForm);
|
||||
|
||||
@@ -24,8 +24,7 @@ const settings = {
|
||||
|
||||
let EmojiPicker; // load asynchronously
|
||||
|
||||
@injectIntl
|
||||
export default class EmojiPickerDropdown extends React.PureComponent {
|
||||
class EmojiPickerDropdown extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
@@ -53,7 +52,7 @@ export default class EmojiPickerDropdown extends React.PureComponent {
|
||||
import(/* webpackChunkName: "emojione_picker" */ 'emojione-picker').then(TheEmojiPicker => {
|
||||
EmojiPicker = TheEmojiPicker.default;
|
||||
this.setState({ loading: false });
|
||||
}).catch(() => {
|
||||
}).catch(err => {
|
||||
// TODO: show the user an error?
|
||||
this.setState({ loading: false });
|
||||
});
|
||||
@@ -124,3 +123,5 @@ export default class EmojiPickerDropdown extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(EmojiPickerDropdown);
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import Avatar from '../../../components/avatar';
|
||||
import IconButton from '../../../components/icon_button';
|
||||
import DisplayName from '../../../components/display_name';
|
||||
import Permalink from '../../../components/permalink';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import Link from 'react-router-dom/Link';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
export default class NavigationBar extends ImmutablePureComponent {
|
||||
class NavigationBar extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
@@ -30,3 +33,5 @@ export default class NavigationBar extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default NavigationBar;
|
||||
|
||||
@@ -20,8 +20,7 @@ const iconStyle = {
|
||||
lineHeight: '27px',
|
||||
};
|
||||
|
||||
@injectIntl
|
||||
export default class PrivacyDropdown extends React.PureComponent {
|
||||
class PrivacyDropdown extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
@@ -65,7 +64,7 @@ export default class PrivacyDropdown extends React.PureComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { value, intl } = this.props;
|
||||
const { value, onChange, intl } = this.props;
|
||||
const { open } = this.state;
|
||||
|
||||
const options = [
|
||||
@@ -96,3 +95,5 @@ export default class PrivacyDropdown extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(PrivacyDropdown);
|
||||
|
||||
@@ -12,8 +12,7 @@ const messages = defineMessages({
|
||||
cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class ReplyIndicator extends ImmutablePureComponent {
|
||||
class ReplyIndicator extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
@@ -62,3 +61,5 @@ export default class ReplyIndicator extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(ReplyIndicator);
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
const messages = defineMessages({
|
||||
placeholder: { id: 'search.placeholder', defaultMessage: 'Search' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class Search extends React.PureComponent {
|
||||
class Search extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
@@ -71,3 +70,5 @@ export default class Search extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(Search);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import AccountContainer from '../../../containers/account_container';
|
||||
import StatusContainer from '../../../containers/status_container';
|
||||
import Link from 'react-router-dom/Link';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
export default class SearchResults extends ImmutablePureComponent {
|
||||
class SearchResults extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
results: ImmutablePropTypes.map.isRequired,
|
||||
@@ -63,3 +63,5 @@ export default class SearchResults extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default SearchResults;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class TextIconButton extends React.PureComponent {
|
||||
class TextIconButton extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
label: PropTypes.string.isRequired,
|
||||
@@ -27,3 +27,5 @@ export default class TextIconButton extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default TextIconButton;
|
||||
|
||||
@@ -11,7 +11,7 @@ const messages = defineMessages({
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state, props) => ({
|
||||
acceptContentTypes: state.getIn(['media_attachments', 'accept_content_types']),
|
||||
});
|
||||
|
||||
@@ -23,9 +23,7 @@ const iconStyle = {
|
||||
lineHeight: '27px',
|
||||
};
|
||||
|
||||
@connect(makeMapStateToProps)
|
||||
@injectIntl
|
||||
export default class UploadButton extends ImmutablePureComponent {
|
||||
class UploadButton extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
disabled: PropTypes.bool,
|
||||
@@ -72,3 +70,5 @@ export default class UploadButton extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(makeMapStateToProps)(injectIntl(UploadButton));
|
||||
|
||||
@@ -11,8 +11,7 @@ const messages = defineMessages({
|
||||
undo: { id: 'upload_form.undo', defaultMessage: 'Undo' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class UploadForm extends React.PureComponent {
|
||||
class UploadForm extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
media: ImmutablePropTypes.list.isRequired,
|
||||
@@ -49,3 +48,5 @@ export default class UploadForm extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(UploadForm);
|
||||
|
||||
@@ -4,7 +4,7 @@ import Motion from 'react-motion/lib/Motion';
|
||||
import spring from 'react-motion/lib/spring';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
export default class UploadProgress extends React.PureComponent {
|
||||
class UploadProgress extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
active: PropTypes.bool,
|
||||
@@ -40,3 +40,5 @@ export default class UploadProgress extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default UploadProgress;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class Warning extends React.PureComponent {
|
||||
class Warning extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
message: PropTypes.node.isRequired,
|
||||
@@ -18,3 +18,5 @@ export default class Warning extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Warning;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { connect } from 'react-redux';
|
||||
import NavigationBar from '../components/navigation_bar';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const mapStateToProps = (state, props) => {
|
||||
return {
|
||||
account: state.getIn(['accounts', state.getIn(['meta', 'me'])]),
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ import ReplyIndicator from '../components/reply_indicator';
|
||||
const makeMapStateToProps = () => {
|
||||
const getStatus = makeGetStatus();
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state, props) => ({
|
||||
status: getStatus(state, state.getIn(['compose', 'in_reply_to'])),
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { connect } from 'react-redux';
|
||||
import UploadForm from '../components/upload_form';
|
||||
import { undoUploadCompose } from '../../../actions/compose';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state, props) => ({
|
||||
media: state.getIn(['compose', 'media_attachments']),
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { connect } from 'react-redux';
|
||||
import UploadProgress from '../components/upload_progress';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state, props) => ({
|
||||
active: state.getIn(['compose', 'is_uploading']),
|
||||
progress: state.getIn(['compose', 'progress']),
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import ComposeFormContainer from './containers/compose_form_container';
|
||||
import UploadFormContainer from './containers/upload_form_container';
|
||||
import NavigationContainer from './containers/navigation_container';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
@@ -23,9 +24,7 @@ const mapStateToProps = state => ({
|
||||
showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
export default class Compose extends React.PureComponent {
|
||||
class Compose extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
@@ -84,3 +83,5 @@ export default class Compose extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(Compose));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import LoadingIndicator from '../../components/loading_indicator';
|
||||
import { fetchFavouritedStatuses, expandFavouritedStatuses } from '../../actions/favourites';
|
||||
import Column from '../ui/components/column';
|
||||
@@ -14,17 +15,19 @@ const messages = defineMessages({
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
statusIds: state.getIn(['status_lists', 'favourites', 'items']),
|
||||
loaded: state.getIn(['status_lists', 'favourites', 'loaded']),
|
||||
me: state.getIn(['meta', 'me']),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
export default class Favourites extends ImmutablePureComponent {
|
||||
class Favourites extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
statusIds: ImmutablePropTypes.list.isRequired,
|
||||
loaded: PropTypes.bool,
|
||||
intl: PropTypes.object.isRequired,
|
||||
me: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
@@ -36,7 +39,7 @@ export default class Favourites extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { loaded, intl } = this.props;
|
||||
const { statusIds, loaded, intl, me } = this.props;
|
||||
|
||||
if (!loaded) {
|
||||
return (
|
||||
@@ -55,3 +58,5 @@ export default class Favourites extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(Favourites));
|
||||
|
||||
@@ -14,8 +14,7 @@ const mapStateToProps = (state, props) => ({
|
||||
accountIds: state.getIn(['user_lists', 'favourited_by', Number(props.params.statusId)]),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export default class Favourites extends ImmutablePureComponent {
|
||||
class Favourites extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
@@ -58,3 +57,5 @@ export default class Favourites extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(Favourites);
|
||||
|
||||
@@ -14,8 +14,7 @@ const messages = defineMessages({
|
||||
reject: { id: 'follow_request.reject', defaultMessage: 'Reject' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class AccountAuthorize extends ImmutablePureComponent {
|
||||
class AccountAuthorize extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
account: ImmutablePropTypes.map.isRequired,
|
||||
@@ -48,3 +47,5 @@ export default class AccountAuthorize extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(AccountAuthorize);
|
||||
|
||||
@@ -14,11 +14,11 @@ const makeMapStateToProps = () => {
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { id }) => ({
|
||||
onAuthorize () {
|
||||
onAuthorize (account) {
|
||||
dispatch(authorizeFollowRequest(id));
|
||||
},
|
||||
|
||||
onReject () {
|
||||
onReject (account) {
|
||||
dispatch(rejectFollowRequest(id));
|
||||
},
|
||||
});
|
||||
|
||||
@@ -19,9 +19,7 @@ const mapStateToProps = state => ({
|
||||
accountIds: state.getIn(['user_lists', 'follow_requests', 'items']),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
export default class FollowRequests extends ImmutablePureComponent {
|
||||
class FollowRequests extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
@@ -69,3 +67,5 @@ export default class FollowRequests extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(FollowRequests));
|
||||
|
||||
@@ -21,8 +21,7 @@ const mapStateToProps = (state, props) => ({
|
||||
hasMore: !!state.getIn(['user_lists', 'followers', Number(props.params.accountId), 'next']),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export default class Followers extends ImmutablePureComponent {
|
||||
class Followers extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
@@ -91,3 +90,5 @@ export default class Followers extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(Followers);
|
||||
|
||||
@@ -21,8 +21,7 @@ const mapStateToProps = (state, props) => ({
|
||||
hasMore: !!state.getIn(['user_lists', 'following', Number(props.params.accountId), 'next']),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export default class Following extends ImmutablePureComponent {
|
||||
class Following extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
@@ -91,3 +90,5 @@ export default class Following extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(Following);
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import Column from '../ui/components/column';
|
||||
import ColumnLink from '../ui/components/column_link';
|
||||
import ColumnSubheading from '../ui/components/column_subheading';
|
||||
import Link from 'react-router-dom/Link';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
@@ -30,9 +31,7 @@ const mapStateToProps = state => ({
|
||||
columns: state.getIn(['settings', 'columns']),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
export default class GettingStarted extends ImmutablePureComponent {
|
||||
class GettingStarted extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
@@ -107,3 +106,5 @@ export default class GettingStarted extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(GettingStarted));
|
||||
|
||||
@@ -1,54 +1,141 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
import Column from '../../components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import {
|
||||
refreshHashtagTimeline,
|
||||
expandHashtagTimeline,
|
||||
updateTimeline,
|
||||
deleteFromTimelines,
|
||||
} from '../../actions/timelines';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import Timeline from '../timeline';
|
||||
import createStream from '../../stream';
|
||||
|
||||
export default class HashtagTimeline extends React.PureComponent {
|
||||
const mapStateToProps = state => ({
|
||||
hasUnread: state.getIn(['timelines', 'tag', 'unread']) > 0,
|
||||
streamingAPIBaseURL: state.getIn(['meta', 'streaming_api_base_url']),
|
||||
accessToken: state.getIn(['meta', 'access_token']),
|
||||
});
|
||||
|
||||
class HashtagTimeline extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
streamingAPIBaseURL: PropTypes.string.isRequired,
|
||||
accessToken: PropTypes.string.isRequired,
|
||||
hasUnread: PropTypes.bool,
|
||||
multiColumn: PropTypes.bool,
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
const id = this.props.params.id;
|
||||
this.expand = () => expandHashtagTimeline(id);
|
||||
this.refresh = () => refreshHashtagTimeline(id);
|
||||
handlePin = () => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('HASHTAG', { id: this.props.params.id }));
|
||||
}
|
||||
}
|
||||
|
||||
handleMove = (dir) => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
dispatch(moveColumn(columnId, dir));
|
||||
}
|
||||
|
||||
handleHeaderClick = () => {
|
||||
this.column.scrollTop();
|
||||
}
|
||||
|
||||
_subscribe (dispatch, id) {
|
||||
const { streamingAPIBaseURL, accessToken } = this.props;
|
||||
|
||||
this.subscription = createStream(streamingAPIBaseURL, accessToken, `hashtag&tag=${id}`, {
|
||||
|
||||
received (data) {
|
||||
switch(data.event) {
|
||||
case 'update':
|
||||
dispatch(updateTimeline(`hashtag:${id}`, JSON.parse(data.payload)));
|
||||
break;
|
||||
case 'delete':
|
||||
dispatch(deleteFromTimelines(data.payload));
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
_unsubscribe () {
|
||||
if (typeof this.subscription !== 'undefined') {
|
||||
this.subscription.close();
|
||||
this.subscription = null;
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch } = this.props;
|
||||
const { id } = this.props.params;
|
||||
|
||||
dispatch(refreshHashtagTimeline(id));
|
||||
this._subscribe(dispatch, id);
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (nextProps.params.id !== this.props.params.id) {
|
||||
const id = nextProps.params.id;
|
||||
this.expand = () => expandHashtagTimeline(id);
|
||||
this.refresh = () => refreshHashtagTimeline(id);
|
||||
this.props.dispatch(refreshHashtagTimeline(nextProps.params.id));
|
||||
this._unsubscribe();
|
||||
this._subscribe(this.props.dispatch, nextProps.params.id);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this._unsubscribe();
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.column = c;
|
||||
}
|
||||
|
||||
handleLoadMore = () => {
|
||||
this.props.dispatch(expandHashtagTimeline(this.props.params.id));
|
||||
}
|
||||
|
||||
render () {
|
||||
const { columnId, multiColumn } = this.props;
|
||||
const { hasUnread, columnId, multiColumn } = this.props;
|
||||
const { id } = this.props.params;
|
||||
const pinned = !!columnId;
|
||||
|
||||
return (
|
||||
<Timeline
|
||||
expand={this.expand}
|
||||
refresh={this.refresh}
|
||||
streamId={`hashtag&tag=${id}`}
|
||||
columnName='HASHTAG'
|
||||
columnProps={{ id }}
|
||||
columnId={columnId}
|
||||
mulitColumn={multiColumn}
|
||||
emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />}
|
||||
icon='hashtag'
|
||||
title={id}
|
||||
scrollName='hashtag_timeline'
|
||||
timelineId={`hashtag:${id}`}
|
||||
/>
|
||||
<Column ref={this.setRef}>
|
||||
<ColumnHeader
|
||||
icon='hashtag'
|
||||
active={hasUnread}
|
||||
title={id}
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
onClick={this.handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
showBackButton
|
||||
/>
|
||||
|
||||
<StatusListContainer
|
||||
trackScroll={!pinned}
|
||||
scrollKey={`hashtag_timeline-${columnId}`}
|
||||
timelineId={`hashtag:${id}`}
|
||||
loadMore={this.handleLoadMore}
|
||||
emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(HashtagTimeline);
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ColumnCollapsable from '../../../components/column_collapsable';
|
||||
import SettingToggle from '../../notifications/components/setting_toggle';
|
||||
import SettingText from '../../../components/setting_text';
|
||||
|
||||
@@ -10,37 +11,39 @@ const messages = defineMessages({
|
||||
settings: { id: 'home.settings', defaultMessage: 'Column settings' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class ColumnSettings extends React.PureComponent {
|
||||
class ColumnSettings extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onSave: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { settings, onChange, intl } = this.props;
|
||||
const { settings, onChange, onSave, intl } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<span className='column-settings__section'><FormattedMessage id='home.column_settings.basic' defaultMessage='Basic' /></span>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle prefix='home_timeline' settings={settings} settingKey={['shows', 'reblog']} onChange={onChange} label={<FormattedMessage id='home.column_settings.show_reblogs' defaultMessage='Show boosts' />} />
|
||||
<SettingToggle settings={settings} settingKey={['shows', 'reblog']} onChange={onChange} label={<FormattedMessage id='home.column_settings.show_reblogs' defaultMessage='Show boosts' />} />
|
||||
</div>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle prefix='home_timeline' settings={settings} settingKey={['shows', 'reply']} onChange={onChange} label={<FormattedMessage id='home.column_settings.show_replies' defaultMessage='Show replies' />} />
|
||||
<SettingToggle settings={settings} settingKey={['shows', 'reply']} onChange={onChange} label={<FormattedMessage id='home.column_settings.show_replies' defaultMessage='Show replies' />} />
|
||||
</div>
|
||||
|
||||
<span className='column-settings__section'><FormattedMessage id='home.column_settings.advanced' defaultMessage='Advanced' /></span>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingText prefix='home_timeline' settings={settings} settingKey={['regex', 'body']} onChange={onChange} label={intl.formatMessage(messages.filter_regex)} />
|
||||
<SettingText settings={settings} settingKey={['regex', 'body']} onChange={onChange} label={intl.formatMessage(messages.filter_regex)} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(ColumnSettings);
|
||||
|
||||
@@ -2,9 +2,12 @@ import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { expandHomeTimeline } from '../../actions/timelines';
|
||||
import PropTypes from 'prop-types';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
import Column from '../../components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
import Timeline from '../timeline';
|
||||
import Link from 'react-router-dom/Link';
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -12,22 +15,51 @@ const messages = defineMessages({
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
hasUnread: state.getIn(['timelines', 'home', 'unread']) > 0,
|
||||
hasFollows: state.getIn(['accounts_counters', state.getIn(['meta', 'me']), 'following_count']) > 0,
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
export default class HomeTimeline extends React.PureComponent {
|
||||
class HomeTimeline extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
hasUnread: PropTypes.bool,
|
||||
hasFollows: PropTypes.bool,
|
||||
columnId: PropTypes.string,
|
||||
multiColumn: PropTypes.bool,
|
||||
};
|
||||
|
||||
handlePin = () => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('HOME', {}));
|
||||
}
|
||||
}
|
||||
|
||||
handleMove = (dir) => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
dispatch(moveColumn(columnId, dir));
|
||||
}
|
||||
|
||||
handleHeaderClick = () => {
|
||||
this.column.scrollTop();
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.column = c;
|
||||
}
|
||||
|
||||
handleLoadMore = () => {
|
||||
this.props.dispatch(expandHomeTimeline());
|
||||
}
|
||||
|
||||
render () {
|
||||
const { intl, hasFollows, columnId, multiColumn } = this.props;
|
||||
const { intl, hasUnread, hasFollows, columnId, multiColumn } = this.props;
|
||||
const pinned = !!columnId;
|
||||
|
||||
let emptyMessage;
|
||||
|
||||
@@ -38,19 +70,31 @@ export default class HomeTimeline extends React.PureComponent {
|
||||
}
|
||||
|
||||
return (
|
||||
<Timeline
|
||||
expand={expandHomeTimeline}
|
||||
columnName='HOME'
|
||||
columnId={columnId}
|
||||
mulitColumn={multiColumn}
|
||||
emptyMessage={emptyMessage}
|
||||
icon='home'
|
||||
title={intl.formatMessage(messages.title)}
|
||||
settings={<ColumnSettingsContainer />}
|
||||
scrollName='home_timeline'
|
||||
timelineId='home'
|
||||
/>
|
||||
<Column ref={this.setRef}>
|
||||
<ColumnHeader
|
||||
icon='home'
|
||||
active={hasUnread}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
onClick={this.handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
>
|
||||
<ColumnSettingsContainer />
|
||||
</ColumnHeader>
|
||||
|
||||
<StatusListContainer
|
||||
trackScroll={!pinned}
|
||||
scrollKey={`home_timeline-${columnId}`}
|
||||
loadMore={this.handleLoadMore}
|
||||
timelineId='home'
|
||||
emptyMessage={emptyMessage}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(HomeTimeline));
|
||||
|
||||
@@ -19,16 +19,7 @@ const mapStateToProps = state => ({
|
||||
accountIds: state.getIn(['user_lists', 'mutes', 'items']),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
export default class Mutes extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
accountIds: ImmutablePropTypes.list,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
class Mutes extends ImmutablePureComponent {
|
||||
|
||||
componentWillMount () {
|
||||
this.props.dispatch(fetchMutes());
|
||||
@@ -68,3 +59,12 @@ export default class Mutes extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Mutes.propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
accountIds: ImmutablePropTypes.list,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(Mutes));
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
export default class ClearColumnButton extends React.Component {
|
||||
class ClearColumnButton extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
onClick: PropTypes.func.isRequired,
|
||||
@@ -15,3 +15,5 @@ export default class ClearColumnButton extends React.Component {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ClearColumnButton;
|
||||
|
||||
@@ -2,10 +2,11 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import ColumnCollapsable from '../../../components/column_collapsable';
|
||||
import ClearColumnButton from './clear_column_button';
|
||||
import SettingToggle from './setting_toggle';
|
||||
|
||||
export default class ColumnSettings extends React.PureComponent {
|
||||
class ColumnSettings extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
@@ -15,7 +16,7 @@ export default class ColumnSettings extends React.PureComponent {
|
||||
};
|
||||
|
||||
render () {
|
||||
const { settings, onChange, onClear } = this.props;
|
||||
const { settings, onChange, onSave, onClear } = this.props;
|
||||
|
||||
const alertStr = <FormattedMessage id='notifications.column_settings.alert' defaultMessage='Desktop notifications' />;
|
||||
const showStr = <FormattedMessage id='notifications.column_settings.show' defaultMessage='Show in column' />;
|
||||
@@ -30,36 +31,38 @@ export default class ColumnSettings extends React.PureComponent {
|
||||
<span className='column-settings__section'><FormattedMessage id='notifications.column_settings.follow' defaultMessage='New followers:' /></span>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle prefix='notifications' settings={settings} settingKey={['alerts', 'follow']} onChange={onChange} label={alertStr} />
|
||||
<SettingToggle prefix='notifications' settings={settings} settingKey={['shows', 'follow']} onChange={onChange} label={showStr} />
|
||||
<SettingToggle prefix='notifications' settings={settings} settingKey={['sounds', 'follow']} onChange={onChange} label={soundStr} />
|
||||
<SettingToggle settings={settings} settingKey={['alerts', 'follow']} onChange={onChange} label={alertStr} />
|
||||
<SettingToggle settings={settings} settingKey={['shows', 'follow']} onChange={onChange} label={showStr} />
|
||||
<SettingToggle settings={settings} settingKey={['sounds', 'follow']} onChange={onChange} label={soundStr} />
|
||||
</div>
|
||||
|
||||
<span className='column-settings__section'><FormattedMessage id='notifications.column_settings.favourite' defaultMessage='Favourites:' /></span>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle prefix='notifications' settings={settings} settingKey={['alerts', 'favourite']} onChange={onChange} label={alertStr} />
|
||||
<SettingToggle prefix='notifications' settings={settings} settingKey={['shows', 'favourite']} onChange={onChange} label={showStr} />
|
||||
<SettingToggle prefix='notifications' settings={settings} settingKey={['sounds', 'favourite']} onChange={onChange} label={soundStr} />
|
||||
<SettingToggle settings={settings} settingKey={['alerts', 'favourite']} onChange={onChange} label={alertStr} />
|
||||
<SettingToggle settings={settings} settingKey={['shows', 'favourite']} onChange={onChange} label={showStr} />
|
||||
<SettingToggle settings={settings} settingKey={['sounds', 'favourite']} onChange={onChange} label={soundStr} />
|
||||
</div>
|
||||
|
||||
<span className='column-settings__section'><FormattedMessage id='notifications.column_settings.mention' defaultMessage='Mentions:' /></span>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle prefix='notifications' settings={settings} settingKey={['alerts', 'mention']} onChange={onChange} label={alertStr} />
|
||||
<SettingToggle prefix='notifications' settings={settings} settingKey={['shows', 'mention']} onChange={onChange} label={showStr} />
|
||||
<SettingToggle prefix='notifications' settings={settings} settingKey={['sounds', 'mention']} onChange={onChange} label={soundStr} />
|
||||
<SettingToggle settings={settings} settingKey={['alerts', 'mention']} onChange={onChange} label={alertStr} />
|
||||
<SettingToggle settings={settings} settingKey={['shows', 'mention']} onChange={onChange} label={showStr} />
|
||||
<SettingToggle settings={settings} settingKey={['sounds', 'mention']} onChange={onChange} label={soundStr} />
|
||||
</div>
|
||||
|
||||
<span className='column-settings__section'><FormattedMessage id='notifications.column_settings.reblog' defaultMessage='Boosts:' /></span>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle prefix='notifications' settings={settings} settingKey={['alerts', 'reblog']} onChange={onChange} label={alertStr} />
|
||||
<SettingToggle prefix='notifications' settings={settings} settingKey={['shows', 'reblog']} onChange={onChange} label={showStr} />
|
||||
<SettingToggle prefix='notifications' settings={settings} settingKey={['sounds', 'reblog']} onChange={onChange} label={soundStr} />
|
||||
<SettingToggle settings={settings} settingKey={['alerts', 'reblog']} onChange={onChange} label={alertStr} />
|
||||
<SettingToggle settings={settings} settingKey={['shows', 'reblog']} onChange={onChange} label={showStr} />
|
||||
<SettingToggle settings={settings} settingKey={['sounds', 'reblog']} onChange={onChange} label={soundStr} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ColumnSettings;
|
||||
|
||||
@@ -2,13 +2,14 @@ import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import StatusContainer from '../../../containers/status_container';
|
||||
import AccountContainer from '../../../containers/account_container';
|
||||
import Avatar from '../../../components/avatar';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import Permalink from '../../../components/permalink';
|
||||
import emojify from '../../../emoji';
|
||||
import escapeTextContentForBrowser from 'escape-html';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
export default class Notification extends ImmutablePureComponent {
|
||||
class Notification extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
notification: ImmutablePropTypes.map.isRequired,
|
||||
@@ -86,3 +87,5 @@ export default class Notification extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Notification;
|
||||
|
||||
@@ -3,23 +3,22 @@ import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import Toggle from 'react-toggle';
|
||||
|
||||
export default class SettingToggle extends React.PureComponent {
|
||||
class SettingToggle extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
prefix: PropTypes.string,
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
settingKey: PropTypes.array.isRequired,
|
||||
label: PropTypes.node.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
onChange = ({ target }) => {
|
||||
this.props.onChange(this.props.settingKey, target.checked);
|
||||
onChange = (e) => {
|
||||
this.props.onChange(this.props.settingKey, e.target.checked);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { prefix, settings, settingKey, label } = this.props;
|
||||
const id = ['setting-toggle', prefix, ...settingKey].filter(Boolean).join('-');
|
||||
const { settings, settingKey, label, onChange } = this.props;
|
||||
const id = `setting-toggle-${settingKey.join('-')}`;
|
||||
|
||||
return (
|
||||
<div className='setting-toggle'>
|
||||
@@ -30,3 +29,5 @@ export default class SettingToggle extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default SettingToggle;
|
||||
|
||||
@@ -30,9 +30,7 @@ const mapStateToProps = state => ({
|
||||
hasMore: !!state.getIn(['notifications', 'next']),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
export default class Notifications extends React.PureComponent {
|
||||
class Notifications extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
columnId: PropTypes.string,
|
||||
@@ -175,3 +173,5 @@ export default class Notifications extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(Notifications));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { connect } from 'react-redux';
|
||||
import ColumnSettings from '../../community_timeline/components/column_settings';
|
||||
import { changeSetting } from '../../../actions/settings';
|
||||
import { changeSetting, saveSettings } from '../../../actions/settings';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
settings: state.getIn(['settings', 'public']),
|
||||
@@ -12,6 +12,10 @@ const mapDispatchToProps = dispatch => ({
|
||||
dispatch(changeSetting(['public', ...key], checked));
|
||||
},
|
||||
|
||||
onSave () {
|
||||
dispatch(saveSettings());
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings);
|
||||
|
||||
@@ -1,45 +1,146 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
import Column from '../../components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import {
|
||||
refreshPublicTimeline,
|
||||
expandPublicTimeline,
|
||||
updateTimeline,
|
||||
deleteFromTimelines,
|
||||
connectTimeline,
|
||||
disconnectTimeline,
|
||||
} from '../../actions/timelines';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
import Timeline from '../timeline';
|
||||
import createStream from '../../stream';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.public', defaultMessage: 'Federated timeline' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class PublicTimeline extends React.PureComponent {
|
||||
const mapStateToProps = state => ({
|
||||
hasUnread: state.getIn(['timelines', 'public', 'unread']) > 0,
|
||||
streamingAPIBaseURL: state.getIn(['meta', 'streaming_api_base_url']),
|
||||
accessToken: state.getIn(['meta', 'access_token']),
|
||||
});
|
||||
|
||||
class PublicTimeline extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
multiColumn: PropTypes.bool,
|
||||
streamingAPIBaseURL: PropTypes.string.isRequired,
|
||||
accessToken: PropTypes.string.isRequired,
|
||||
hasUnread: PropTypes.bool,
|
||||
};
|
||||
|
||||
handlePin = () => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('PUBLIC', {}));
|
||||
}
|
||||
}
|
||||
|
||||
handleMove = (dir) => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
dispatch(moveColumn(columnId, dir));
|
||||
}
|
||||
|
||||
handleHeaderClick = () => {
|
||||
this.column.scrollTop();
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch, streamingAPIBaseURL, accessToken } = this.props;
|
||||
|
||||
dispatch(refreshPublicTimeline());
|
||||
|
||||
if (typeof this._subscription !== 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
this._subscription = createStream(streamingAPIBaseURL, accessToken, 'public', {
|
||||
|
||||
connected () {
|
||||
dispatch(connectTimeline('public'));
|
||||
},
|
||||
|
||||
reconnected () {
|
||||
dispatch(connectTimeline('public'));
|
||||
},
|
||||
|
||||
disconnected () {
|
||||
dispatch(disconnectTimeline('public'));
|
||||
},
|
||||
|
||||
received (data) {
|
||||
switch(data.event) {
|
||||
case 'update':
|
||||
dispatch(updateTimeline('public', JSON.parse(data.payload)));
|
||||
break;
|
||||
case 'delete':
|
||||
dispatch(deleteFromTimelines(data.payload));
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
if (typeof this._subscription !== 'undefined') {
|
||||
this._subscription.close();
|
||||
this._subscription = null;
|
||||
}
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.column = c;
|
||||
}
|
||||
|
||||
handleLoadMore = () => {
|
||||
this.props.dispatch(expandPublicTimeline());
|
||||
}
|
||||
|
||||
render () {
|
||||
const { intl, columnId, multiColumn } = this.props;
|
||||
const { intl, columnId, hasUnread, multiColumn } = this.props;
|
||||
const pinned = !!columnId;
|
||||
|
||||
return (
|
||||
<Timeline
|
||||
expand={expandPublicTimeline}
|
||||
refresh={refreshPublicTimeline}
|
||||
streamId='public'
|
||||
columnName='PUBLIC'
|
||||
columnId={columnId}
|
||||
mulitColumn={multiColumn}
|
||||
emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other instances to fill it up' />}
|
||||
icon='globe'
|
||||
title={intl.formatMessage(messages.title)}
|
||||
settings={<ColumnSettingsContainer />}
|
||||
scrollName='public_timeline'
|
||||
timelineId='public'
|
||||
/>
|
||||
<Column ref={this.setRef}>
|
||||
<ColumnHeader
|
||||
icon='globe'
|
||||
active={hasUnread}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
onClick={this.handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
>
|
||||
<ColumnSettingsContainer />
|
||||
</ColumnHeader>
|
||||
|
||||
<StatusListContainer
|
||||
timelineId='public'
|
||||
loadMore={this.handleLoadMore}
|
||||
trackScroll={!pinned}
|
||||
scrollKey={`public_timeline-${columnId}`}
|
||||
emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other instances to fill it up' />}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(PublicTimeline));
|
||||
|
||||
@@ -14,8 +14,7 @@ const mapStateToProps = (state, props) => ({
|
||||
accountIds: state.getIn(['user_lists', 'reblogged_by', Number(props.params.statusId)]),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export default class Reblogs extends ImmutablePureComponent {
|
||||
class Reblogs extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
@@ -58,3 +57,5 @@ export default class Reblogs extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(Reblogs);
|
||||
|
||||
@@ -4,7 +4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import emojify from '../../../emoji';
|
||||
import Toggle from 'react-toggle';
|
||||
|
||||
export default class StatusCheckBox extends React.PureComponent {
|
||||
class StatusCheckBox extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
@@ -36,3 +36,5 @@ export default class StatusCheckBox extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default StatusCheckBox;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { changeReportComment, submitReport } from '../../actions/reports';
|
||||
import { cancelReport, changeReportComment, submitReport } from '../../actions/reports';
|
||||
import { refreshAccountTimeline } from '../../actions/timelines';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
@@ -35,9 +35,7 @@ const makeMapStateToProps = () => {
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
@connect(makeMapStateToProps)
|
||||
@injectIntl
|
||||
export default class Report extends React.PureComponent {
|
||||
class Report extends React.PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
@@ -123,3 +121,5 @@ export default class Report extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(makeMapStateToProps)(injectIntl(Report));
|
||||
|
||||
@@ -15,8 +15,7 @@ const messages = defineMessages({
|
||||
report: { id: 'status.report', defaultMessage: 'Report @{name}' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class ActionBar extends React.PureComponent {
|
||||
class ActionBar extends React.PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
@@ -92,3 +91,5 @@ export default class ActionBar extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(ActionBar);
|
||||
|
||||
@@ -17,7 +17,7 @@ const getHostname = url => {
|
||||
return parser.hostname;
|
||||
};
|
||||
|
||||
export default class Card extends React.PureComponent {
|
||||
class Card extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
card: ImmutablePropTypes.map,
|
||||
@@ -97,3 +97,5 @@ export default class Card extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Card;
|
||||
|
||||
@@ -12,7 +12,7 @@ import { FormattedDate, FormattedNumber } from 'react-intl';
|
||||
import CardContainer from '../containers/card_container';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
export default class DetailedStatus extends ImmutablePureComponent {
|
||||
class DetailedStatus extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
@@ -87,3 +87,5 @@ export default class DetailedStatus extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DetailedStatus;
|
||||
|
||||
@@ -3,6 +3,8 @@ import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { fetchStatus } from '../../actions/statuses';
|
||||
import Immutable from 'immutable';
|
||||
import EmbeddedStatus from '../../components/status';
|
||||
import MissingIndicator from '../../components/missing_indicator';
|
||||
import DetailedStatus from './components/detailed_status';
|
||||
import ActionBar from './components/action_bar';
|
||||
@@ -19,12 +21,17 @@ import {
|
||||
} from '../../actions/compose';
|
||||
import { deleteStatus } from '../../actions/statuses';
|
||||
import { initReport } from '../../actions/reports';
|
||||
import { makeGetStatus } from '../../selectors';
|
||||
import {
|
||||
makeGetStatus,
|
||||
getStatusAncestors,
|
||||
getStatusDescendants,
|
||||
} from '../../selectors';
|
||||
import { ScrollContainer } from 'react-router-scroll';
|
||||
import ColumnBackButton from '../../components/column_back_button';
|
||||
import StatusContainer from '../../containers/status_container';
|
||||
import { openModal } from '../../actions/modal';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { isMobile } from '../../is_mobile';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -48,9 +55,7 @@ const makeMapStateToProps = () => {
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
@injectIntl
|
||||
@connect(makeMapStateToProps)
|
||||
export default class Status extends ImmutablePureComponent {
|
||||
class Status extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
@@ -154,6 +159,8 @@ export default class Status extends ImmutablePureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
const account = status.get('account');
|
||||
|
||||
if (ancestorsIds && ancestorsIds.size > 0) {
|
||||
ancestors = <div>{this.renderChildren(ancestorsIds)}</div>;
|
||||
}
|
||||
@@ -197,3 +204,5 @@ export default class Status extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(connect(makeMapStateToProps)(Status));
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
import Column from '../../components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import {
|
||||
updateTimeline,
|
||||
deleteFromTimelines,
|
||||
connectTimeline,
|
||||
disconnectTimeline,
|
||||
} from '../../actions/timelines';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import createStream from '../../stream';
|
||||
|
||||
const mapStateToProps = (state, ownprops) => ({
|
||||
streamingAPIBaseURL: state.getIn(['meta', 'streaming_api_base_url']),
|
||||
accessToken: state.getIn(['meta', 'access_token']),
|
||||
hasUnread: state.getIn(['timelines', ownprops.timelineId, 'unread']) > 0,
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export default class Timeline extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
streamingAPIBaseURL: PropTypes.string.isRequired,
|
||||
accessToken: PropTypes.string.isRequired,
|
||||
expand: PropTypes.func.isRequired,
|
||||
refresh: PropTypes.func,
|
||||
streamId: PropTypes.string,
|
||||
hasUnread: PropTypes.bool,
|
||||
columnName: PropTypes.string.isRequired,
|
||||
columnProps: PropTypes.object,
|
||||
columnId: PropTypes.string,
|
||||
multiColumn: PropTypes.bool,
|
||||
emptyMessage: PropTypes.oneOfType([
|
||||
PropTypes.element,
|
||||
PropTypes.string,
|
||||
]),
|
||||
icon: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
settings: PropTypes.element,
|
||||
scrollName: PropTypes.string.isRequired,
|
||||
timelineId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
handlePin = () => {
|
||||
const { columnName, columnProps, columnId, dispatch } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn(columnName, columnProps || {}));
|
||||
}
|
||||
}
|
||||
|
||||
handleMove = (dir) => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
dispatch(moveColumn(columnId, dir));
|
||||
}
|
||||
|
||||
handleHeaderClick = () => {
|
||||
this.column.scrollTop();
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.column = c;
|
||||
}
|
||||
|
||||
handleLoadMore = () => {
|
||||
this.props.dispatch(this.props.expand());
|
||||
}
|
||||
|
||||
_subscribe (dispatch, streamId, timelineId) {
|
||||
const { streamingAPIBaseURL, accessToken } = this.props;
|
||||
|
||||
if (!streamId || !timelineId) return;
|
||||
|
||||
this.subscription = createStream(streamingAPIBaseURL, accessToken, streamId, {
|
||||
|
||||
connected () {
|
||||
dispatch(connectTimeline(timelineId));
|
||||
},
|
||||
|
||||
reconnected () {
|
||||
dispatch(connectTimeline(timelineId));
|
||||
},
|
||||
|
||||
disconnected () {
|
||||
dispatch(disconnectTimeline(timelineId));
|
||||
},
|
||||
|
||||
received (data) {
|
||||
switch(data.event) {
|
||||
case 'update':
|
||||
dispatch(updateTimeline(timelineId, JSON.parse(data.payload)));
|
||||
break;
|
||||
case 'delete':
|
||||
dispatch(deleteFromTimelines(data.payload));
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
_unsubscribe () {
|
||||
if (typeof this.subscription !== 'undefined') {
|
||||
this.subscription.close();
|
||||
this.subscription = null;
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch, refresh, streamId, timelineId } = this.props;
|
||||
|
||||
if (typeof refresh !== 'function') return;
|
||||
|
||||
dispatch(refresh());
|
||||
this._subscribe(dispatch, streamId, timelineId);
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (nextProps.streamId !== this.props.streamId || nextProps.timelineId !== this.props.timelineId) {
|
||||
|
||||
if (typeof refresh !== 'function') return;
|
||||
|
||||
this.props.dispatch(this.props.refresh());
|
||||
this._unsubscribe();
|
||||
this._subscribe(this.props.dispatch, nextProps.streamId, nextProps.timelineId);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this._unsubscribe();
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
hasUnread,
|
||||
columnId,
|
||||
multiColumn,
|
||||
emptyMessage,
|
||||
icon,
|
||||
title,
|
||||
settings,
|
||||
scrollName,
|
||||
timelineId,
|
||||
} = this.props;
|
||||
const pinned = !!columnId;
|
||||
|
||||
return (
|
||||
<Column ref={this.setRef}>
|
||||
<ColumnHeader
|
||||
icon={icon}
|
||||
active={hasUnread}
|
||||
title={title}
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
onClick={this.handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
>
|
||||
{settings}
|
||||
</ColumnHeader>
|
||||
|
||||
<StatusListContainer
|
||||
trackScroll={!pinned}
|
||||
scrollKey={`${scrollName}-${columnId}`}
|
||||
loadMore={this.handleLoadMore}
|
||||
timelineId={timelineId}
|
||||
emptyMessage={emptyMessage}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import React from 'react';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PropTypes from 'prop-types';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import IconButton from '../../../components/icon_button';
|
||||
import Button from '../../../components/button';
|
||||
import StatusContent from '../../../components/status_content';
|
||||
import Avatar from '../../../components/avatar';
|
||||
@@ -13,8 +14,7 @@ const messages = defineMessages({
|
||||
reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class BoostModal extends ImmutablePureComponent {
|
||||
class BoostModal extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
@@ -49,7 +49,7 @@ export default class BoostModal extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { status, intl } = this.props;
|
||||
const { status, intl, onClose } = this.props;
|
||||
|
||||
return (
|
||||
<div className='modal-root__modal boost-modal'>
|
||||
@@ -82,3 +82,5 @@ export default class BoostModal extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(BoostModal);
|
||||
|
||||
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
|
||||
import { debounce } from 'lodash';
|
||||
import scrollTop from '../../../scroll';
|
||||
|
||||
export default class Column extends React.PureComponent {
|
||||
class Column extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
heading: PropTypes.string,
|
||||
@@ -59,3 +59,5 @@ export default class Column extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Column;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class ColumnHeader extends React.PureComponent {
|
||||
class ColumnHeader extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
icon: PropTypes.string,
|
||||
@@ -34,3 +34,5 @@ export default class ColumnHeader extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ColumnHeader;
|
||||
|
||||
@@ -2,14 +2,12 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ReactSwipeable from 'react-swipeable';
|
||||
import HomeTimeline from '../../home_timeline';
|
||||
import Notifications from '../../notifications';
|
||||
import PublicTimeline from '../../public_timeline';
|
||||
import CommunityTimeline from '../../community_timeline';
|
||||
import HashtagTimeline from '../../hashtag_timeline';
|
||||
import Compose from '../../compose';
|
||||
import { getPreviousLink, getNextLink } from './tabs_bar';
|
||||
|
||||
const componentMap = {
|
||||
'COMPOSE': Compose,
|
||||
@@ -20,11 +18,7 @@ const componentMap = {
|
||||
'HASHTAG': HashtagTimeline,
|
||||
};
|
||||
|
||||
export default class ColumnsArea extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object.isRequired,
|
||||
};
|
||||
class ColumnsArea extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
columns: ImmutablePropTypes.list.isRequired,
|
||||
@@ -32,30 +26,14 @@ export default class ColumnsArea extends ImmutablePureComponent {
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
handleRightSwipe = () => {
|
||||
const previousLink = getPreviousLink(this.context.router.history.location.pathname);
|
||||
|
||||
if (previousLink) {
|
||||
this.context.router.history.push(previousLink);
|
||||
}
|
||||
}
|
||||
|
||||
handleLeftSwipe = () => {
|
||||
const previousLink = getNextLink(this.context.router.history.location.pathname);
|
||||
|
||||
if (previousLink) {
|
||||
this.context.router.history.push(previousLink);
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
const { columns, children, singleColumn } = this.props;
|
||||
|
||||
if (singleColumn) {
|
||||
return (
|
||||
<ReactSwipeable onSwipedLeft={this.handleLeftSwipe} onSwipedRight={this.handleRightSwipe} className='columns-area'>
|
||||
<div className='columns-area'>
|
||||
{children}
|
||||
</ReactSwipeable>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -73,3 +51,5 @@ export default class ColumnsArea extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ColumnsArea;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import Button from '../../../components/button';
|
||||
|
||||
@injectIntl
|
||||
export default class ConfirmationModal extends React.PureComponent {
|
||||
class ConfirmationModal extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
message: PropTypes.node.isRequired,
|
||||
@@ -51,3 +50,5 @@ export default class ConfirmationModal extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(ConfirmationModal);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class ImageLoader extends React.PureComponent {
|
||||
class ImageLoader extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
alt: PropTypes.string,
|
||||
@@ -41,7 +41,7 @@ export default class ImageLoader extends React.PureComponent {
|
||||
|
||||
render() {
|
||||
const { alt, src, previewSrc, width, height } = this.props;
|
||||
const { loading } = this.state;
|
||||
const { loading, error } = this.state;
|
||||
|
||||
return (
|
||||
<div className='image-loader'>
|
||||
@@ -65,3 +65,5 @@ export default class ImageLoader extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ImageLoader;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import ReactSwipeable from 'react-swipeable';
|
||||
import LoadingIndicator from '../../../components/loading_indicator';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PropTypes from 'prop-types';
|
||||
import ExtendedVideoPlayer from '../../../components/extended_video_player';
|
||||
@@ -12,8 +12,7 @@ const messages = defineMessages({
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class MediaModal extends ImmutablePureComponent {
|
||||
class MediaModal extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
media: ImmutablePropTypes.list.isRequired,
|
||||
@@ -85,9 +84,7 @@ export default class MediaModal extends ImmutablePureComponent {
|
||||
|
||||
<div className='media-modal__content'>
|
||||
<IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' onClick={onClose} size={16} />
|
||||
<ReactSwipeable onSwipedRight={this.handlePrevClick} onSwipedLeft={this.handleNextClick}>
|
||||
{content}
|
||||
</ReactSwipeable>
|
||||
{content}
|
||||
</div>
|
||||
|
||||
{rightNav}
|
||||
@@ -96,3 +93,5 @@ export default class MediaModal extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(MediaModal);
|
||||
|
||||
@@ -16,7 +16,7 @@ const MODAL_COMPONENTS = {
|
||||
'CONFIRM': ConfirmationModal,
|
||||
};
|
||||
|
||||
export default class ModalRoot extends React.PureComponent {
|
||||
class ModalRoot extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
type: PropTypes.string,
|
||||
@@ -87,3 +87,5 @@ export default class ModalRoot extends React.PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ModalRoot;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user