[build] upgrade eslint to 9.37.0 (#88)
Co-authored-by: tobi <tobi.smethurst@protonmail.com> Reviewed-on: https://codeberg.org/superseriousbusiness/masto-fe-standalone/pulls/88 Co-authored-by: Zoë Bijl <moiety@noreply.codeberg.org> Co-committed-by: Zoë Bijl <moiety@noreply.codeberg.org>
This commit is contained in:
@@ -1,31 +1,31 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import classNames from "classnames";
|
||||
import { Helmet } from "react-helmet";
|
||||
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
import { List as ImmutableList } from "immutable";
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { fetchServer, fetchDomainBlocks } from 'flavours/glitch/actions/server';
|
||||
import Column from 'flavours/glitch/components/column';
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { ServerHeroImage } from 'flavours/glitch/components/server_hero_image';
|
||||
import { Skeleton } from 'flavours/glitch/components/skeleton';
|
||||
import Account from 'flavours/glitch/containers/account_container';
|
||||
import LinkFooter from 'flavours/glitch/features/ui/components/link_footer';
|
||||
import { fetchServer, fetchDomainBlocks } from "flavours/glitch/actions/server";
|
||||
import Column from "flavours/glitch/components/column";
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
import { ServerHeroImage } from "flavours/glitch/components/server_hero_image";
|
||||
import { Skeleton } from "flavours/glitch/components/skeleton";
|
||||
import Account from "flavours/glitch/containers/account_container";
|
||||
import LinkFooter from "flavours/glitch/features/ui/components/link_footer";
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.about', defaultMessage: 'About' },
|
||||
rules: { id: 'about.rules', defaultMessage: 'Server rules' },
|
||||
blocks: { id: 'about.blocks', defaultMessage: 'Moderated servers' },
|
||||
silenced: { id: 'about.domain_blocks.silenced.title', defaultMessage: 'Limited' },
|
||||
silencedExplanation: { id: 'about.domain_blocks.silenced.explanation', defaultMessage: 'You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.' },
|
||||
suspended: { id: 'about.domain_blocks.suspended.title', defaultMessage: 'Suspended' },
|
||||
suspendedExplanation: { id: 'about.domain_blocks.suspended.explanation', defaultMessage: 'No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.' },
|
||||
title: { id: "column.about", defaultMessage: "About" },
|
||||
rules: { id: "about.rules", defaultMessage: "Server rules" },
|
||||
blocks: { id: "about.blocks", defaultMessage: "Moderated servers" },
|
||||
silenced: { id: "about.domain_blocks.silenced.title", defaultMessage: "Limited" },
|
||||
silencedExplanation: { id: "about.domain_blocks.silenced.explanation", defaultMessage: "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following." },
|
||||
suspended: { id: "about.domain_blocks.suspended.title", defaultMessage: "Suspended" },
|
||||
suspendedExplanation: { id: "about.domain_blocks.suspended.explanation", defaultMessage: "No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible." },
|
||||
});
|
||||
|
||||
const severityMessages = {
|
||||
@@ -41,8 +41,8 @@ const severityMessages = {
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
server: state.getIn(['server', 'server']),
|
||||
domainBlocks: state.getIn(['server', 'domainBlocks']),
|
||||
server: state.getIn(["server", "server"]),
|
||||
domainBlocks: state.getIn(["server", "domainBlocks"]),
|
||||
});
|
||||
|
||||
class Section extends PureComponent {
|
||||
@@ -70,9 +70,9 @@ class Section extends PureComponent {
|
||||
const { collapsed } = this.state;
|
||||
|
||||
return (
|
||||
<div className={classNames('about__section', { active: !collapsed })}>
|
||||
<div className={classNames("about__section", { active: !collapsed })}>
|
||||
<div className='about__section__title' role='button' tabIndex={0} onClick={this.handleClick}>
|
||||
<Icon id={collapsed ? 'chevron-right' : 'chevron-down'} fixedWidth /> {title}
|
||||
<Icon id={collapsed ? "chevron-right" : "chevron-down"} fixedWidth /> {title}
|
||||
</div>
|
||||
|
||||
{!collapsed && (
|
||||
@@ -110,22 +110,22 @@ class About extends PureComponent {
|
||||
|
||||
render () {
|
||||
const { multiColumn, intl, server, domainBlocks } = this.props;
|
||||
const isLoading = server.get('isLoading');
|
||||
const isLoading = server.get("isLoading");
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}>
|
||||
<div className='scrollable about'>
|
||||
<div className='about__header'>
|
||||
<ServerHeroImage blurhash={server.getIn(['thumbnail', 'blurhash'])} src={server.getIn(['thumbnail', 'url'])} srcSet={server.getIn(['thumbnail', 'versions'])?.map((value, key) => `${value} ${key.replace('@', '')}`).join(', ')} className='about__header__hero' />
|
||||
<h1>{isLoading ? <Skeleton width='10ch' /> : server.get('domain')}</h1>
|
||||
<p><FormattedMessage id='about.powered_by' defaultMessage='Decentralized social media powered by {torment}' values={{ torment: <a href='https://doom.fandom.com/wiki/Argent_Energy' className='about__mail' target='_blank'>torment</a> }} /></p>
|
||||
<ServerHeroImage blurhash={server.getIn(["thumbnail", "blurhash"])} src={server.getIn(["thumbnail", "url"])} srcSet={server.getIn(["thumbnail", "versions"])?.map((value, key) => `${value} ${key.replace("@", "")}`).join(", ")} className='about__header__hero' />
|
||||
<h1>{isLoading ? <Skeleton width='10ch' /> : server.get("domain")}</h1>
|
||||
<p><FormattedMessage id='about.powered_by' defaultMessage='Decentralized social media powered by {torment}' values={{ torment: <a href='https://doom.fandom.com/wiki/Argent_Energy' className='about__mail' target='_blank' rel="noreferrer">torment</a> }} /></p>
|
||||
</div>
|
||||
|
||||
<div className='about__meta'>
|
||||
<div className='about__meta__column'>
|
||||
<h4><FormattedMessage id='server_banner.administered_by' defaultMessage='Administered by:' /></h4>
|
||||
|
||||
<Account id={server.getIn(['contact', 'account', 'id'])} size={36} />
|
||||
<Account id={server.getIn(["contact", "account", "id"])} size={36} />
|
||||
</div>
|
||||
|
||||
<hr className='about__meta__divider' />
|
||||
@@ -133,7 +133,7 @@ class About extends PureComponent {
|
||||
<div className='about__meta__column'>
|
||||
<h4><FormattedMessage id='about.contact' defaultMessage='Contact:' /></h4>
|
||||
|
||||
{isLoading ? <Skeleton width='10ch' /> : <a className='about__mail' href={`mailto:${server.getIn(['contact', 'email'])}`}>{server.getIn(['contact', 'email'])}</a>}
|
||||
{isLoading ? <Skeleton width='10ch' /> : <a className='about__mail' href={`mailto:${server.getIn(["contact", "email"])}`}>{server.getIn(["contact", "email"])}</a>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -148,10 +148,10 @@ class About extends PureComponent {
|
||||
<br />
|
||||
<Skeleton width='70%' />
|
||||
</>
|
||||
) : (server.get('description')?.length > 0 ? (
|
||||
) : (server.get("description")?.length > 0 ? (
|
||||
<div
|
||||
className='prose'
|
||||
dangerouslySetInnerHTML={{ __html: server.get('description') }}
|
||||
dangerouslySetInnerHTML={{ __html: server.get("description") }}
|
||||
/>
|
||||
) : (
|
||||
<p><FormattedMessage id='about.not_available' defaultMessage='This information has not been made available on this server.' /></p>
|
||||
@@ -159,13 +159,13 @@ class About extends PureComponent {
|
||||
</Section>
|
||||
|
||||
<Section title={intl.formatMessage(messages.rules)}>
|
||||
{!isLoading && (server.get('rules', ImmutableList()).isEmpty() ? (
|
||||
{!isLoading && (server.get("rules", ImmutableList()).isEmpty() ? (
|
||||
<p><FormattedMessage id='about.not_available' defaultMessage='This information has not been made available on this server.' /></p>
|
||||
) : (
|
||||
<ol className='rules-list'>
|
||||
{server.get('rules').map(rule => (
|
||||
<li key={rule.get('id')}>
|
||||
<span className='rules-list__text'>{rule.get('text')}</span>
|
||||
{server.get("rules").map(rule => (
|
||||
<li key={rule.get("id")}>
|
||||
<span className='rules-list__text'>{rule.get("text")}</span>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
@@ -173,25 +173,25 @@ class About extends PureComponent {
|
||||
</Section>
|
||||
|
||||
<Section title={intl.formatMessage(messages.blocks)} onOpen={this.handleDomainBlocksOpen}>
|
||||
{domainBlocks.get('isLoading') ? (
|
||||
{domainBlocks.get("isLoading") ? (
|
||||
<>
|
||||
<Skeleton width='100%' />
|
||||
<br />
|
||||
<Skeleton width='70%' />
|
||||
</>
|
||||
) : (domainBlocks.get('isAvailable') ? (
|
||||
) : (domainBlocks.get("isAvailable") ? (
|
||||
<>
|
||||
<p><FormattedMessage id='about.domain_blocks.preamble' defaultMessage='Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.' /></p>
|
||||
|
||||
<div className='about__domain-blocks'>
|
||||
{domainBlocks.get('items').map(block => (
|
||||
<div className='about__domain-blocks__domain' key={block.get('domain')}>
|
||||
{domainBlocks.get("items").map(block => (
|
||||
<div className='about__domain-blocks__domain' key={block.get("domain")}>
|
||||
<div className='about__domain-blocks__domain__header'>
|
||||
<h6><span title={`SHA-256: ${block.get('digest')}`}>{block.get('domain')}</span></h6>
|
||||
<span className='about__domain-blocks__domain__type' title={intl.formatMessage(severityMessages[block.get('severity')].explanation)}>{intl.formatMessage(severityMessages[block.get('severity')].title)}</span>
|
||||
<h6><span title={`SHA-256: ${block.get("digest")}`}>{block.get("domain")}</span></h6>
|
||||
<span className='about__domain-blocks__domain__type' title={intl.formatMessage(severityMessages[block.get("severity")].explanation)}>{intl.formatMessage(severityMessages[block.get("severity")].title)}</span>
|
||||
</div>
|
||||
|
||||
<p>{(block.get('comment') || '').length > 0 ? block.get('comment') : <FormattedMessage id='about.domain_blocks.no_reason_available' defaultMessage='Reason not available' />}</p>
|
||||
<p>{(block.get("comment") || "").length > 0 ? block.get("comment") : <FormattedMessage id='about.domain_blocks.no_reason_available' defaultMessage='Reason not available' />}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -206,7 +206,6 @@ class About extends PureComponent {
|
||||
<div className='about__footer'>
|
||||
<p><FormattedMessage
|
||||
id='about.fork_disclaimer'
|
||||
// eslint-disable-next-line formatjs/no-emoji
|
||||
defaultMessage='Masto-FE (🦥 flavour) is open source software forked from Mastodon via Glitch.'
|
||||
/></p>
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import Textarea from 'react-textarea-autosize';
|
||||
import Textarea from "react-textarea-autosize";
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
|
||||
const messages = defineMessages({
|
||||
placeholder: { id: 'account_note.glitch_placeholder', defaultMessage: 'No comment provided' },
|
||||
placeholder: { id: "account_note.glitch_placeholder", defaultMessage: "No comment provided" },
|
||||
});
|
||||
|
||||
class Header extends ImmutablePureComponent {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { PureComponent } from 'react';
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
||||
import { FormattedMessage, FormattedNumber } from "react-intl";
|
||||
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { NavLink } from "react-router-dom";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
|
||||
class ActionBar extends PureComponent {
|
||||
|
||||
@@ -24,7 +24,7 @@ class ActionBar extends PureComponent {
|
||||
render () {
|
||||
const { account } = this.props;
|
||||
|
||||
if (account.get('suspended')) {
|
||||
if (account.get("suspended")) {
|
||||
return (
|
||||
<div>
|
||||
<div className='account__disclaimer'>
|
||||
@@ -37,17 +37,17 @@ class ActionBar extends PureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
let extraInfo = '';
|
||||
let extraInfo = "";
|
||||
|
||||
if (account.get('acct') !== account.get('username')) {
|
||||
if (account.get("acct") !== account.get("username")) {
|
||||
extraInfo = (
|
||||
<div className='account__disclaimer'>
|
||||
<Icon id='info-circle' fixedWidth /> <FormattedMessage
|
||||
id='account.disclaimer_full'
|
||||
defaultMessage="Information below may reflect the user's profile incompletely."
|
||||
/>
|
||||
{' '}
|
||||
<a target='_blank' rel='noopener' href={account.get('url')}>
|
||||
{" "}
|
||||
<a target='_blank' rel="noopener noreferrer" href={account.get("url")}>
|
||||
<FormattedMessage id='account.view_full_profile' defaultMessage='View full profile' />
|
||||
</a>
|
||||
</div>
|
||||
@@ -60,19 +60,19 @@ class ActionBar extends PureComponent {
|
||||
|
||||
<div className='account__action-bar'>
|
||||
<div className='account__action-bar-links'>
|
||||
<NavLink isActive={this.isStatusesPageActive} activeClassName='active' className='account__action-bar__tab' to={`/@${account.get('acct')}`}>
|
||||
<NavLink isActive={this.isStatusesPageActive} activeClassName='active' className='account__action-bar__tab' to={`/@${account.get("acct")}`}>
|
||||
<FormattedMessage id='account.posts' defaultMessage='Posts' />
|
||||
<strong><FormattedNumber value={account.get('statuses_count')} /></strong>
|
||||
<strong><FormattedNumber value={account.get("statuses_count")} /></strong>
|
||||
</NavLink>
|
||||
|
||||
<NavLink exact activeClassName='active' className='account__action-bar__tab' to={`/@${account.get('acct')}/following`}>
|
||||
<NavLink exact activeClassName='active' className='account__action-bar__tab' to={`/@${account.get("acct")}/following`}>
|
||||
<FormattedMessage id='account.follows' defaultMessage='Follows' />
|
||||
<strong><FormattedNumber value={account.get('following_count')} /></strong>
|
||||
<strong><FormattedNumber value={account.get("following_count")} /></strong>
|
||||
</NavLink>
|
||||
|
||||
<NavLink exact activeClassName='active' className='account__action-bar__tab' to={`/@${account.get('acct')}/followers`}>
|
||||
<NavLink exact activeClassName='active' className='account__action-bar__tab' to={`/@${account.get("acct")}/followers`}>
|
||||
<FormattedMessage id='account.followers' defaultMessage='Followers' />
|
||||
<strong>{ account.get('followers_count') < 0 ? '-' : <FormattedNumber value={account.get('followers_count')} /> }</strong>
|
||||
<strong>{ account.get("followers_count") < 0 ? "-" : <FormattedNumber value={account.get("followers_count")} /> }</strong>
|
||||
</NavLink>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import Hashtag from 'flavours/glitch/components/hashtag';
|
||||
import Hashtag from "flavours/glitch/components/hashtag";
|
||||
|
||||
const messages = defineMessages({
|
||||
lastStatusAt: { id: 'account.featured_tags.last_status_at', defaultMessage: 'Last post on {date}' },
|
||||
empty: { id: 'account.featured_tags.last_status_never', defaultMessage: 'No posts' },
|
||||
lastStatusAt: { id: "account.featured_tags.last_status_at", defaultMessage: "Last post on {date}" },
|
||||
empty: { id: "account.featured_tags.last_status_never", defaultMessage: "No posts" },
|
||||
});
|
||||
|
||||
class FeaturedTags extends ImmutablePureComponent {
|
||||
@@ -28,23 +28,23 @@ class FeaturedTags extends ImmutablePureComponent {
|
||||
render () {
|
||||
const { account, featuredTags, intl } = this.props;
|
||||
|
||||
if (!account || account.get('suspended') || featuredTags.isEmpty()) {
|
||||
if (!account || account.get("suspended") || featuredTags.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='getting-started__trends'>
|
||||
<h4><FormattedMessage id='account.featured_tags.title' defaultMessage="{name}'s featured hashtags" values={{ name: <bdi dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} /> }} /></h4>
|
||||
<h4><FormattedMessage id='account.featured_tags.title' defaultMessage="{name}'s featured hashtags" values={{ name: <bdi dangerouslySetInnerHTML={{ __html: account.get("display_name_html") }} /> }} /></h4>
|
||||
|
||||
{featuredTags.take(3).map(featuredTag => (
|
||||
<Hashtag
|
||||
key={featuredTag.get('name')}
|
||||
name={featuredTag.get('name')}
|
||||
href={featuredTag.get('url')}
|
||||
to={`/@${account.get('acct')}/tagged/${featuredTag.get('name')}`}
|
||||
uses={featuredTag.get('statuses_count')}
|
||||
key={featuredTag.get("name")}
|
||||
name={featuredTag.get("name")}
|
||||
href={featuredTag.get("url")}
|
||||
to={`/@${account.get("acct")}/tagged/${featuredTag.get("name")}`}
|
||||
uses={featuredTag.get("statuses_count")}
|
||||
withGraph={false}
|
||||
description={((featuredTag.get('statuses_count') * 1) > 0) ? intl.formatMessage(messages.lastStatusAt, { date: intl.formatDate(featuredTag.get('last_status_at'), { month: 'short', day: '2-digit' }) }) : intl.formatMessage(messages.empty)}
|
||||
description={((featuredTag.get("statuses_count") * 1) > 0) ? intl.formatMessage(messages.lastStatusAt, { date: intl.formatDate(featuredTag.get("last_status_at"), { month: "short", day: "2-digit" }) }) : intl.formatMessage(messages.empty)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
|
||||
export default class FollowRequestNote extends ImmutablePureComponent {
|
||||
|
||||
@@ -17,7 +17,7 @@ export default class FollowRequestNote extends ImmutablePureComponent {
|
||||
return (
|
||||
<div className='follow-request-banner'>
|
||||
<div className='follow-request-banner__message'>
|
||||
<FormattedMessage id='account.requested_follow' defaultMessage='{name} has requested to follow you' values={{ name: <bdi><strong dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} /></bdi> }} />
|
||||
<FormattedMessage id='account.requested_follow' defaultMessage='{name} has requested to follow you' values={{ name: <bdi><strong dangerouslySetInnerHTML={{ __html: account.get("display_name_html") }} /></bdi> }} />
|
||||
</div>
|
||||
|
||||
<div className='follow-request-banner__action'>
|
||||
|
||||
@@ -1,82 +1,82 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import classNames from "classnames";
|
||||
import { Helmet } from "react-helmet";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||
import Button from 'flavours/glitch/components/button';
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
|
||||
import { autoPlayGif, me, domain } from 'flavours/glitch/initial_state';
|
||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions';
|
||||
import { preferencesLink, profileLink, accountAdminLink } from 'flavours/glitch/utils/backend_links';
|
||||
import { Avatar } from "flavours/glitch/components/avatar";
|
||||
import Button from "flavours/glitch/components/button";
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
import { IconButton } from "flavours/glitch/components/icon_button";
|
||||
import DropdownMenuContainer from "flavours/glitch/containers/dropdown_menu_container";
|
||||
import { autoPlayGif, me, domain } from "flavours/glitch/initial_state";
|
||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from "flavours/glitch/permissions";
|
||||
import { preferencesLink, profileLink, accountAdminLink } from "flavours/glitch/utils/backend_links";
|
||||
|
||||
import AccountNoteContainer from '../containers/account_note_container';
|
||||
import FollowRequestNoteContainer from '../containers/follow_request_note_container';
|
||||
import AccountNoteContainer from "../containers/account_note_container";
|
||||
import FollowRequestNoteContainer from "../containers/follow_request_note_container";
|
||||
|
||||
const messages = defineMessages({
|
||||
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
|
||||
follow: { id: 'account.follow', defaultMessage: 'Follow' },
|
||||
cancel_follow_request: { id: 'account.cancel_follow_request', defaultMessage: 'Withdraw follow request' },
|
||||
requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' },
|
||||
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
|
||||
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
|
||||
linkVerifiedOn: { id: 'account.link_verified_on', defaultMessage: 'Ownership of this link was checked on {date}' },
|
||||
account_locked: { id: 'account.locked_info', defaultMessage: 'This account privacy status is set to locked. The owner manually reviews who can follow them.' },
|
||||
mention: { id: 'account.mention', defaultMessage: 'Mention @{name}' },
|
||||
direct: { id: 'account.direct', defaultMessage: 'Privately mention @{name}' },
|
||||
unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
|
||||
block: { id: 'account.block', defaultMessage: 'Block @{name}' },
|
||||
mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },
|
||||
report: { id: 'account.report', defaultMessage: 'Report @{name}' },
|
||||
share: { id: 'account.share', defaultMessage: 'Share @{name}\'s profile' },
|
||||
media: { id: 'account.media', defaultMessage: 'Media' },
|
||||
blockDomain: { id: 'account.block_domain', defaultMessage: 'Block domain {domain}' },
|
||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
|
||||
hideReblogs: { id: 'account.hide_reblogs', defaultMessage: 'Hide boosts from @{name}' },
|
||||
showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show boosts from @{name}' },
|
||||
enableNotifications: { id: 'account.enable_notifications', defaultMessage: 'Notify me when @{name} posts' },
|
||||
disableNotifications: { id: 'account.disable_notifications', defaultMessage: 'Stop notifying me when @{name} posts' },
|
||||
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' },
|
||||
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
|
||||
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
||||
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favorites' },
|
||||
lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
|
||||
followed_tags: { id: 'navigation_bar.followed_tags', defaultMessage: 'Followed hashtags' },
|
||||
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
|
||||
domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Blocked domains' },
|
||||
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
|
||||
endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' },
|
||||
unendorse: { id: 'account.unendorse', defaultMessage: 'Don\'t feature on profile' },
|
||||
add_or_remove_from_list: { id: 'account.add_or_remove_from_list', defaultMessage: 'Add or Remove from lists' },
|
||||
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
|
||||
admin_domain: { id: 'status.admin_domain', defaultMessage: 'Open moderation interface for {domain}' },
|
||||
add_account_note: { id: 'account.add_account_note', defaultMessage: 'Add note for @{name}' },
|
||||
languages: { id: 'account.languages', defaultMessage: 'Change subscribed languages' },
|
||||
openOriginalPage: { id: 'account.open_original_page', defaultMessage: 'Open original page' },
|
||||
unfollow: { id: "account.unfollow", defaultMessage: "Unfollow" },
|
||||
follow: { id: "account.follow", defaultMessage: "Follow" },
|
||||
cancel_follow_request: { id: "account.cancel_follow_request", defaultMessage: "Withdraw follow request" },
|
||||
requested: { id: "account.requested", defaultMessage: "Awaiting approval. Click to cancel follow request" },
|
||||
unblock: { id: "account.unblock", defaultMessage: "Unblock @{name}" },
|
||||
edit_profile: { id: "account.edit_profile", defaultMessage: "Edit profile" },
|
||||
linkVerifiedOn: { id: "account.link_verified_on", defaultMessage: "Ownership of this link was checked on {date}" },
|
||||
account_locked: { id: "account.locked_info", defaultMessage: "This account privacy status is set to locked. The owner manually reviews who can follow them." },
|
||||
mention: { id: "account.mention", defaultMessage: "Mention @{name}" },
|
||||
direct: { id: "account.direct", defaultMessage: "Privately mention @{name}" },
|
||||
unmute: { id: "account.unmute", defaultMessage: "Unmute @{name}" },
|
||||
block: { id: "account.block", defaultMessage: "Block @{name}" },
|
||||
mute: { id: "account.mute", defaultMessage: "Mute @{name}" },
|
||||
report: { id: "account.report", defaultMessage: "Report @{name}" },
|
||||
share: { id: "account.share", defaultMessage: "Share @{name}'s profile" },
|
||||
media: { id: "account.media", defaultMessage: "Media" },
|
||||
blockDomain: { id: "account.block_domain", defaultMessage: "Block domain {domain}" },
|
||||
unblockDomain: { id: "account.unblock_domain", defaultMessage: "Unblock domain {domain}" },
|
||||
hideReblogs: { id: "account.hide_reblogs", defaultMessage: "Hide boosts from @{name}" },
|
||||
showReblogs: { id: "account.show_reblogs", defaultMessage: "Show boosts from @{name}" },
|
||||
enableNotifications: { id: "account.enable_notifications", defaultMessage: "Notify me when @{name} posts" },
|
||||
disableNotifications: { id: "account.disable_notifications", defaultMessage: "Stop notifying me when @{name} posts" },
|
||||
pins: { id: "navigation_bar.pins", defaultMessage: "Pinned posts" },
|
||||
preferences: { id: "navigation_bar.preferences", defaultMessage: "Preferences" },
|
||||
follow_requests: { id: "navigation_bar.follow_requests", defaultMessage: "Follow requests" },
|
||||
favourites: { id: "navigation_bar.favourites", defaultMessage: "Favorites" },
|
||||
lists: { id: "navigation_bar.lists", defaultMessage: "Lists" },
|
||||
followed_tags: { id: "navigation_bar.followed_tags", defaultMessage: "Followed hashtags" },
|
||||
blocks: { id: "navigation_bar.blocks", defaultMessage: "Blocked users" },
|
||||
domain_blocks: { id: "navigation_bar.domain_blocks", defaultMessage: "Blocked domains" },
|
||||
mutes: { id: "navigation_bar.mutes", defaultMessage: "Muted users" },
|
||||
endorse: { id: "account.endorse", defaultMessage: "Feature on profile" },
|
||||
unendorse: { id: "account.unendorse", defaultMessage: "Don't feature on profile" },
|
||||
add_or_remove_from_list: { id: "account.add_or_remove_from_list", defaultMessage: "Add or Remove from lists" },
|
||||
admin_account: { id: "status.admin_account", defaultMessage: "Open moderation interface for @{name}" },
|
||||
admin_domain: { id: "status.admin_domain", defaultMessage: "Open moderation interface for {domain}" },
|
||||
add_account_note: { id: "account.add_account_note", defaultMessage: "Add note for @{name}" },
|
||||
languages: { id: "account.languages", defaultMessage: "Change subscribed languages" },
|
||||
openOriginalPage: { id: "account.open_original_page", defaultMessage: "Open original page" },
|
||||
});
|
||||
|
||||
const titleFromAccount = account => {
|
||||
const displayName = account.get('display_name');
|
||||
const acct = account.get('acct') === account.get('username') ? `${account.get('username')}@${domain}` : account.get('acct');
|
||||
const prefix = displayName.trim().length === 0 ? account.get('username') : displayName;
|
||||
const displayName = account.get("display_name");
|
||||
const acct = account.get("acct") === account.get("username") ? `${account.get("username")}@${domain}` : account.get("acct");
|
||||
const prefix = displayName.trim().length === 0 ? account.get("username") : displayName;
|
||||
|
||||
return `${prefix} (@${acct})`;
|
||||
};
|
||||
|
||||
const dateFormatOptions = {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
hour12: false,
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
};
|
||||
|
||||
class Header extends ImmutablePureComponent {
|
||||
@@ -110,7 +110,7 @@ class Header extends ImmutablePureComponent {
|
||||
};
|
||||
|
||||
openEditProfile = () => {
|
||||
window.open(profileLink, '_blank');
|
||||
window.open(profileLink, "_blank");
|
||||
};
|
||||
|
||||
handleMouseEnter = ({ currentTarget }) => {
|
||||
@@ -118,11 +118,11 @@ class Header extends ImmutablePureComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
const emojis = currentTarget.querySelectorAll('.custom-emoji');
|
||||
const emojis = currentTarget.querySelectorAll(".custom-emoji");
|
||||
|
||||
for (var i = 0; i < emojis.length; i++) {
|
||||
let emoji = emojis[i];
|
||||
emoji.src = emoji.getAttribute('data-original');
|
||||
emoji.src = emoji.getAttribute("data-original");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -131,11 +131,11 @@ class Header extends ImmutablePureComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
const emojis = currentTarget.querySelectorAll('.custom-emoji');
|
||||
const emojis = currentTarget.querySelectorAll(".custom-emoji");
|
||||
|
||||
for (var i = 0; i < emojis.length; i++) {
|
||||
let emoji = emojis[i];
|
||||
emoji.src = emoji.getAttribute('data-static');
|
||||
emoji.src = emoji.getAttribute("data-static");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -150,9 +150,11 @@ class Header extends ImmutablePureComponent {
|
||||
const { account } = this.props;
|
||||
|
||||
navigator.share({
|
||||
url: account.get('url'),
|
||||
url: account.get("url"),
|
||||
}).catch((e) => {
|
||||
if (e.name !== 'AbortError') console.error(e);
|
||||
if (e.name !== "AbortError") {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -164,183 +166,187 @@ class Header extends ImmutablePureComponent {
|
||||
return null;
|
||||
}
|
||||
|
||||
const accountNote = account.getIn(['relationship', 'note']);
|
||||
const accountNote = account.getIn(["relationship", "note"]);
|
||||
|
||||
const suspended = account.get('suspended');
|
||||
const isRemote = account.get('acct') !== account.get('username');
|
||||
const remoteDomain = isRemote ? account.get('acct').split('@')[1] : null;
|
||||
const suspended = account.get("suspended");
|
||||
const isRemote = account.get("acct") !== account.get("username");
|
||||
const remoteDomain = isRemote ? account.get("acct").split("@")[1] : null;
|
||||
|
||||
let info = [];
|
||||
let actionBtn = '';
|
||||
let bellBtn = '';
|
||||
let lockedIcon = '';
|
||||
let actionBtn = "";
|
||||
let bellBtn = "";
|
||||
let lockedIcon = "";
|
||||
let menu = [];
|
||||
|
||||
if (me !== account.get('id') && account.getIn(['relationship', 'followed_by'])) {
|
||||
if (me !== account.get("id") && account.getIn(["relationship", "followed_by"])) {
|
||||
info.push(<span className='relationship-tag'><FormattedMessage id='account.follows_you' defaultMessage='Follows you' /></span>);
|
||||
} else if (me !== account.get('id') && account.getIn(['relationship', 'blocking'])) {
|
||||
} else if (me !== account.get("id") && account.getIn(["relationship", "blocking"])) {
|
||||
info.push(<span className='relationship-tag'><FormattedMessage id='account.blocked' defaultMessage='Blocked' /></span>);
|
||||
}
|
||||
|
||||
if (me !== account.get('id') && account.getIn(['relationship', 'muting'])) {
|
||||
if (me !== account.get("id") && account.getIn(["relationship", "muting"])) {
|
||||
info.push(<span className='relationship-tag'><FormattedMessage id='account.muted' defaultMessage='Muted' /></span>);
|
||||
} else if (me !== account.get('id') && account.getIn(['relationship', 'domain_blocking'])) {
|
||||
} else if (me !== account.get("id") && account.getIn(["relationship", "domain_blocking"])) {
|
||||
info.push(<span className='relationship-tag'><FormattedMessage id='account.domain_blocked' defaultMessage='Domain blocked' /></span>);
|
||||
}
|
||||
|
||||
if (account.getIn(['relationship', 'requested']) || account.getIn(['relationship', 'following'])) {
|
||||
bellBtn = <IconButton icon={account.getIn(['relationship', 'notifying']) ? 'bell' : 'bell-o'} size={24} active={account.getIn(['relationship', 'notifying'])} title={intl.formatMessage(account.getIn(['relationship', 'notifying']) ? messages.disableNotifications : messages.enableNotifications, { name: account.get('username') })} onClick={this.props.onNotifyToggle} />;
|
||||
if (account.getIn(["relationship", "requested"]) || account.getIn(["relationship", "following"])) {
|
||||
bellBtn = <IconButton icon={account.getIn(["relationship", "notifying"]) ? "bell" : "bell-o"} size={24} active={account.getIn(["relationship", "notifying"])} title={intl.formatMessage(account.getIn(["relationship", "notifying"]) ? messages.disableNotifications : messages.enableNotifications, { name: account.get("username") })} onClick={this.props.onNotifyToggle} />;
|
||||
}
|
||||
|
||||
if (me !== account.get('id')) {
|
||||
if (signedIn && !account.get('relationship')) { // Wait until the relationship is loaded
|
||||
actionBtn = '';
|
||||
} else if (account.getIn(['relationship', 'requested'])) {
|
||||
if (me !== account.get("id")) {
|
||||
if (signedIn && !account.get("relationship")) { // Wait until the relationship is loaded
|
||||
actionBtn = "";
|
||||
} else if (account.getIn(["relationship", "requested"])) {
|
||||
actionBtn = <Button text={intl.formatMessage(messages.cancel_follow_request)} title={intl.formatMessage(messages.requested)} onClick={this.props.onFollow} />;
|
||||
} else if (!account.getIn(['relationship', 'blocking'])) {
|
||||
actionBtn = <Button className={classNames({ 'button--destructive': account.getIn(['relationship', 'following']) })} text={intl.formatMessage(account.getIn(['relationship', 'following']) ? messages.unfollow : messages.follow)} onClick={signedIn ? this.props.onFollow : this.props.onInteractionModal} />;
|
||||
} else if (account.getIn(['relationship', 'blocking'])) {
|
||||
actionBtn = <Button text={intl.formatMessage(messages.unblock, { name: account.get('username') })} onClick={this.props.onBlock} />;
|
||||
} else if (!account.getIn(["relationship", "blocking"])) {
|
||||
actionBtn = <Button className={classNames({ "button--destructive": account.getIn(["relationship", "following"]) })} text={intl.formatMessage(account.getIn(["relationship", "following"]) ? messages.unfollow : messages.follow)} onClick={signedIn ? this.props.onFollow : this.props.onInteractionModal} />;
|
||||
} else if (account.getIn(["relationship", "blocking"])) {
|
||||
actionBtn = <Button text={intl.formatMessage(messages.unblock, { name: account.get("username") })} onClick={this.props.onBlock} />;
|
||||
}
|
||||
} else if (profileLink) {
|
||||
actionBtn = <Button text={intl.formatMessage(messages.edit_profile)} onClick={this.openEditProfile} />;
|
||||
}
|
||||
|
||||
if (account.get('moved') && !account.getIn(['relationship', 'following'])) {
|
||||
actionBtn = '';
|
||||
if (account.get("moved") && !account.getIn(["relationship", "following"])) {
|
||||
actionBtn = "";
|
||||
}
|
||||
|
||||
if (suspended && !account.getIn(['relationship', 'following'])) {
|
||||
actionBtn = '';
|
||||
if (suspended && !account.getIn(["relationship", "following"])) {
|
||||
actionBtn = "";
|
||||
}
|
||||
|
||||
if (account.get('locked')) {
|
||||
if (account.get("locked")) {
|
||||
lockedIcon = <Icon id='lock' title={intl.formatMessage(messages.account_locked)} />;
|
||||
}
|
||||
|
||||
if (signedIn && account.get('id') !== me && !suspended) {
|
||||
menu.push({ text: intl.formatMessage(messages.mention, { name: account.get('username') }), action: this.props.onMention });
|
||||
menu.push({ text: intl.formatMessage(messages.direct, { name: account.get('username') }), action: this.props.onDirect });
|
||||
if (signedIn && account.get("id") !== me && !suspended) {
|
||||
menu.push({ text: intl.formatMessage(messages.mention, { name: account.get("username") }), action: this.props.onMention });
|
||||
menu.push({ text: intl.formatMessage(messages.direct, { name: account.get("username") }), action: this.props.onDirect });
|
||||
menu.push(null);
|
||||
}
|
||||
|
||||
if (isRemote) {
|
||||
menu.push({ text: intl.formatMessage(messages.openOriginalPage), href: account.get('url') });
|
||||
menu.push({ text: intl.formatMessage(messages.openOriginalPage), href: account.get("url") });
|
||||
menu.push(null);
|
||||
}
|
||||
|
||||
if ('share' in navigator && !suspended) {
|
||||
menu.push({ text: intl.formatMessage(messages.share, { name: account.get('username') }), action: this.handleShare });
|
||||
if ("share" in navigator && !suspended) {
|
||||
menu.push({ text: intl.formatMessage(messages.share, { name: account.get("username") }), action: this.handleShare });
|
||||
menu.push(null);
|
||||
}
|
||||
|
||||
if (accountNote === null || accountNote === '') {
|
||||
menu.push({ text: intl.formatMessage(messages.add_account_note, { name: account.get('username') }), action: this.props.onEditAccountNote });
|
||||
if (accountNote === null || accountNote === "") {
|
||||
menu.push({ text: intl.formatMessage(messages.add_account_note, { name: account.get("username") }), action: this.props.onEditAccountNote });
|
||||
}
|
||||
|
||||
if (account.get('id') === me) {
|
||||
if (profileLink) menu.push({ text: intl.formatMessage(messages.edit_profile), href: profileLink });
|
||||
if (preferencesLink) menu.push({ text: intl.formatMessage(messages.preferences), href: preferencesLink });
|
||||
menu.push({ text: intl.formatMessage(messages.pins), to: '/pinned' });
|
||||
if (account.get("id") === me) {
|
||||
if (profileLink) {
|
||||
menu.push({ text: intl.formatMessage(messages.edit_profile), href: profileLink });
|
||||
}
|
||||
if (preferencesLink) {
|
||||
menu.push({ text: intl.formatMessage(messages.preferences), href: preferencesLink });
|
||||
}
|
||||
menu.push({ text: intl.formatMessage(messages.pins), to: "/pinned" });
|
||||
menu.push(null);
|
||||
menu.push({ text: intl.formatMessage(messages.follow_requests), to: '/follow_requests' });
|
||||
menu.push({ text: intl.formatMessage(messages.favourites), to: '/favourites' });
|
||||
menu.push({ text: intl.formatMessage(messages.lists), to: '/lists' });
|
||||
menu.push({ text: intl.formatMessage(messages.followed_tags), to: '/followed_tags' });
|
||||
menu.push({ text: intl.formatMessage(messages.follow_requests), to: "/follow_requests" });
|
||||
menu.push({ text: intl.formatMessage(messages.favourites), to: "/favourites" });
|
||||
menu.push({ text: intl.formatMessage(messages.lists), to: "/lists" });
|
||||
menu.push({ text: intl.formatMessage(messages.followed_tags), to: "/followed_tags" });
|
||||
menu.push(null);
|
||||
menu.push({ text: intl.formatMessage(messages.mutes), to: '/mutes' });
|
||||
menu.push({ text: intl.formatMessage(messages.blocks), to: '/blocks' });
|
||||
menu.push({ text: intl.formatMessage(messages.domain_blocks), to: '/domain_blocks' });
|
||||
menu.push({ text: intl.formatMessage(messages.mutes), to: "/mutes" });
|
||||
menu.push({ text: intl.formatMessage(messages.blocks), to: "/blocks" });
|
||||
menu.push({ text: intl.formatMessage(messages.domain_blocks), to: "/domain_blocks" });
|
||||
} else if (signedIn) {
|
||||
if (account.getIn(['relationship', 'following'])) {
|
||||
if (!account.getIn(['relationship', 'muting'])) {
|
||||
if (account.getIn(['relationship', 'showing_reblogs'])) {
|
||||
menu.push({ text: intl.formatMessage(messages.hideReblogs, { name: account.get('username') }), action: this.props.onReblogToggle });
|
||||
if (account.getIn(["relationship", "following"])) {
|
||||
if (!account.getIn(["relationship", "muting"])) {
|
||||
if (account.getIn(["relationship", "showing_reblogs"])) {
|
||||
menu.push({ text: intl.formatMessage(messages.hideReblogs, { name: account.get("username") }), action: this.props.onReblogToggle });
|
||||
} else {
|
||||
menu.push({ text: intl.formatMessage(messages.showReblogs, { name: account.get('username') }), action: this.props.onReblogToggle });
|
||||
menu.push({ text: intl.formatMessage(messages.showReblogs, { name: account.get("username") }), action: this.props.onReblogToggle });
|
||||
}
|
||||
|
||||
menu.push({ text: intl.formatMessage(messages.languages), action: this.props.onChangeLanguages });
|
||||
menu.push(null);
|
||||
}
|
||||
|
||||
menu.push({ text: intl.formatMessage(account.getIn(['relationship', 'endorsed']) ? messages.unendorse : messages.endorse), action: this.props.onEndorseToggle });
|
||||
menu.push({ text: intl.formatMessage(account.getIn(["relationship", "endorsed"]) ? messages.unendorse : messages.endorse), action: this.props.onEndorseToggle });
|
||||
menu.push({ text: intl.formatMessage(messages.add_or_remove_from_list), action: this.props.onAddToList });
|
||||
menu.push(null);
|
||||
}
|
||||
|
||||
if (account.getIn(['relationship', 'muting'])) {
|
||||
menu.push({ text: intl.formatMessage(messages.unmute, { name: account.get('username') }), action: this.props.onMute });
|
||||
if (account.getIn(["relationship", "muting"])) {
|
||||
menu.push({ text: intl.formatMessage(messages.unmute, { name: account.get("username") }), action: this.props.onMute });
|
||||
} else {
|
||||
menu.push({ text: intl.formatMessage(messages.mute, { name: account.get('username') }), action: this.props.onMute, dangerous: true });
|
||||
menu.push({ text: intl.formatMessage(messages.mute, { name: account.get("username") }), action: this.props.onMute, dangerous: true });
|
||||
}
|
||||
|
||||
if (account.getIn(['relationship', 'blocking'])) {
|
||||
menu.push({ text: intl.formatMessage(messages.unblock, { name: account.get('username') }), action: this.props.onBlock });
|
||||
if (account.getIn(["relationship", "blocking"])) {
|
||||
menu.push({ text: intl.formatMessage(messages.unblock, { name: account.get("username") }), action: this.props.onBlock });
|
||||
} else {
|
||||
menu.push({ text: intl.formatMessage(messages.block, { name: account.get('username') }), action: this.props.onBlock, dangerous: true });
|
||||
menu.push({ text: intl.formatMessage(messages.block, { name: account.get("username") }), action: this.props.onBlock, dangerous: true });
|
||||
}
|
||||
|
||||
menu.push({ text: intl.formatMessage(messages.report, { name: account.get('username') }), action: this.props.onReport, dangerous: true });
|
||||
menu.push({ text: intl.formatMessage(messages.report, { name: account.get("username") }), action: this.props.onReport, dangerous: true });
|
||||
}
|
||||
|
||||
if (signedIn && isRemote) {
|
||||
menu.push(null);
|
||||
|
||||
if (account.getIn(['relationship', 'domain_blocking'])) {
|
||||
if (account.getIn(["relationship", "domain_blocking"])) {
|
||||
menu.push({ text: intl.formatMessage(messages.unblockDomain, { domain: remoteDomain }), action: this.props.onUnblockDomain });
|
||||
} else {
|
||||
menu.push({ text: intl.formatMessage(messages.blockDomain, { domain: remoteDomain }), action: this.props.onBlockDomain, dangerous: true });
|
||||
}
|
||||
}
|
||||
|
||||
if (account.get('id') !== me && ((permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS && accountAdminLink) || (isRemote && (permissions & PERMISSION_MANAGE_FEDERATION) === PERMISSION_MANAGE_FEDERATION)) {
|
||||
if (account.get("id") !== me && ((permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS && accountAdminLink) || (isRemote && (permissions & PERMISSION_MANAGE_FEDERATION) === PERMISSION_MANAGE_FEDERATION)) {
|
||||
menu.push(null);
|
||||
if ((permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS && accountAdminLink) {
|
||||
menu.push({ text: intl.formatMessage(messages.admin_account, { name: account.get('username') }), href: accountAdminLink(account.get('id')) });
|
||||
menu.push({ text: intl.formatMessage(messages.admin_account, { name: account.get("username") }), href: accountAdminLink(account.get("id")) });
|
||||
}
|
||||
if (isRemote && (permissions & PERMISSION_MANAGE_FEDERATION) === PERMISSION_MANAGE_FEDERATION) {
|
||||
menu.push({ text: intl.formatMessage(messages.admin_domain, { domain: remoteDomain }), href: `/admin/instances/${remoteDomain}` });
|
||||
}
|
||||
}
|
||||
|
||||
const content = { __html: account.get('note_emojified') };
|
||||
const displayNameHtml = { __html: account.get('display_name_html') };
|
||||
const fields = account.get('fields');
|
||||
const isLocal = account.get('acct').indexOf('@') === -1;
|
||||
const acct = isLocal && domain ? `${account.get('acct')}@${domain}` : account.get('acct');
|
||||
const isIndexable = !account.get('noindex');
|
||||
const content = { __html: account.get("note_emojified") };
|
||||
const displayNameHtml = { __html: account.get("display_name_html") };
|
||||
const fields = account.get("fields");
|
||||
const isLocal = account.get("acct").indexOf("@") === -1;
|
||||
const acct = isLocal && domain ? `${account.get("acct")}@${domain}` : account.get("acct");
|
||||
const isIndexable = !account.get("noindex");
|
||||
|
||||
let badge;
|
||||
|
||||
if (account.get('bot')) {
|
||||
if (account.get("bot")) {
|
||||
badge = (<div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Automated' /></div>);
|
||||
} else if (account.get('group')) {
|
||||
} else if (account.get("group")) {
|
||||
badge = (<div className='account-role group'><FormattedMessage id='account.badges.group' defaultMessage='Group' /></div>);
|
||||
} else {
|
||||
badge = null;
|
||||
}
|
||||
|
||||
let role = null;
|
||||
if (account.getIn(['roles', 0])) {
|
||||
role = (<div key='role' className={`account-role user-role-${account.getIn(['roles', 0, 'id'])}`}>{account.getIn(['roles', 0, 'name'])}</div>);
|
||||
if (account.getIn(["roles", 0])) {
|
||||
role = (<div key='role' className={`account-role user-role-${account.getIn(["roles", 0, "id"])}`}>{account.getIn(["roles", 0, "name"])}</div>);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames('account__header', { inactive: !!account.get('moved') })} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
||||
{!(suspended || hidden || account.get('moved')) && account.getIn(['relationship', 'requested_by']) && <FollowRequestNoteContainer account={account} />}
|
||||
<div className={classNames("account__header", { inactive: !!account.get("moved") })} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
||||
{!(suspended || hidden || account.get("moved")) && account.getIn(["relationship", "requested_by"]) && <FollowRequestNoteContainer account={account} />}
|
||||
|
||||
<div className='account__header__image'>
|
||||
<div className='account__header__info'>
|
||||
{info}
|
||||
</div>
|
||||
|
||||
{!(suspended || hidden) && <img src={autoPlayGif ? account.get('header') : account.get('header_static')} alt='' className='parallax' />}
|
||||
{!(suspended || hidden) && <img src={autoPlayGif ? account.get("header") : account.get("header_static")} alt='' className='parallax' />}
|
||||
</div>
|
||||
|
||||
<div className='account__header__bar'>
|
||||
<div className='account__header__tabs'>
|
||||
<a className='avatar' href={account.get('avatar')} rel='noopener noreferrer' target='_blank' onClick={this.handleAvatarClick}>
|
||||
<a className='avatar' href={account.get("avatar")} rel='noopener noreferrer' target='_blank' onClick={this.handleAvatarClick}>
|
||||
<Avatar account={suspended || hidden ? undefined : account} size={90} />
|
||||
{role}
|
||||
</a>
|
||||
@@ -377,19 +383,19 @@ class Header extends ImmutablePureComponent {
|
||||
<div className='account__header__fields'>
|
||||
{fields.map((pair, i) => (
|
||||
<dl key={i}>
|
||||
<dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} />
|
||||
<dt dangerouslySetInnerHTML={{ __html: pair.get("name_emojified") }} title={pair.get("name")} />
|
||||
|
||||
<dd className={pair.get('verified_at') && 'verified'} title={pair.get('value_plain')}>
|
||||
{pair.get('verified_at') && <span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(pair.get('verified_at'), dateFormatOptions) })}><Icon id='check' className='verified__mark' /></span>} <span dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} className='translate' />
|
||||
<dd className={pair.get("verified_at") && "verified"} title={pair.get("value_plain")}>
|
||||
{pair.get("verified_at") && <span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(pair.get("verified_at"), dateFormatOptions) })}><Icon id='check' className='verified__mark' /></span>} <span dangerouslySetInnerHTML={{ __html: pair.get("value_emojified") }} className='translate' />
|
||||
</dd>
|
||||
</dl>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{account.get('note').length > 0 && account.get('note') !== '<p></p>' && <div className='account__header__content translate' dangerouslySetInnerHTML={content} />}
|
||||
{account.get("note").length > 0 && account.get("note") !== "<p></p>" && <div className='account__header__content translate' dangerouslySetInnerHTML={content} />}
|
||||
|
||||
<div className='account__header__joined'><FormattedMessage id='account.joined' defaultMessage='Joined {date}' values={{ date: intl.formatDate(account.get('created_at'), { year: 'numeric', month: 'short', day: '2-digit' }) }} /></div>
|
||||
<div className='account__header__joined'><FormattedMessage id='account.joined' defaultMessage='Joined {date}' values={{ date: intl.formatDate(account.get("created_at"), { year: "numeric", month: "short", day: "2-digit" }) }} /></div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -397,8 +403,8 @@ class Header extends ImmutablePureComponent {
|
||||
|
||||
<Helmet>
|
||||
<title>{titleFromAccount(account)}</title>
|
||||
<meta name='robots' content={(isLocal && isIndexable) ? 'all' : 'noindex'} />
|
||||
<link rel='canonical' href={account.get('url')} />
|
||||
<meta name='robots' content={(isLocal && isIndexable) ? "all" : "noindex"} />
|
||||
<link rel='canonical' href={account.get("url")} />
|
||||
</Helmet>
|
||||
</div>
|
||||
);
|
||||
|
||||
+5
-5
@@ -1,12 +1,12 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import { injectIntl, defineMessages } from "react-intl";
|
||||
|
||||
import ColumnHeader from '../../../components/column_header';
|
||||
import ColumnHeader from "../../../components/column_header";
|
||||
|
||||
const messages = defineMessages({
|
||||
profile: { id: 'column_header.profile', defaultMessage: 'Profile' },
|
||||
profile: { id: "column_header.profile", defaultMessage: "Profile" },
|
||||
});
|
||||
|
||||
class ProfileColumnHeader extends PureComponent {
|
||||
|
||||
+6
-6
@@ -1,15 +1,15 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { changeAccountNoteComment, submitAccountNote, initEditAccountNote, cancelAccountNote } from 'flavours/glitch/actions/account_notes';
|
||||
import { changeAccountNoteComment, submitAccountNote, initEditAccountNote, cancelAccountNote } from "flavours/glitch/actions/account_notes";
|
||||
|
||||
import AccountNote from '../components/account_note';
|
||||
import AccountNote from "../components/account_note";
|
||||
|
||||
const mapStateToProps = (state, { account }) => {
|
||||
const isEditing = state.getIn(['account_notes', 'edit', 'account_id']) === account.get('id');
|
||||
const isEditing = state.getIn(["account_notes", "edit", "account_id"]) === account.get("id");
|
||||
|
||||
return {
|
||||
isSubmitting: state.getIn(['account_notes', 'edit', 'isSubmitting']),
|
||||
accountNote: isEditing ? state.getIn(['account_notes', 'edit', 'comment']) : account.getIn(['relationship', 'note']),
|
||||
isSubmitting: state.getIn(["account_notes", "edit", "isSubmitting"]),
|
||||
accountNote: isEditing ? state.getIn(["account_notes", "edit", "comment"]) : account.getIn(["relationship", "note"]),
|
||||
isEditing,
|
||||
};
|
||||
};
|
||||
|
||||
+5
-5
@@ -1,16 +1,16 @@
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import { connect } from 'react-redux';
|
||||
import { List as ImmutableList } from "immutable";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { makeGetAccount } from 'flavours/glitch/selectors';
|
||||
import { makeGetAccount } from "flavours/glitch/selectors";
|
||||
|
||||
import FeaturedTags from '../components/featured_tags';
|
||||
import FeaturedTags from "../components/featured_tags";
|
||||
|
||||
const mapStateToProps = () => {
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
return (state, { accountId }) => ({
|
||||
account: getAccount(state, accountId),
|
||||
featuredTags: state.getIn(['user_lists', 'featured_tags', accountId, 'items'], ImmutableList()),
|
||||
featuredTags: state.getIn(["user_lists", "featured_tags", accountId, "items"], ImmutableList()),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
+5
-5
@@ -1,16 +1,16 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { authorizeFollowRequest, rejectFollowRequest } from 'flavours/glitch/actions/accounts';
|
||||
import { authorizeFollowRequest, rejectFollowRequest } from "flavours/glitch/actions/accounts";
|
||||
|
||||
import FollowRequestNote from '../components/follow_request_note';
|
||||
import FollowRequestNote from "../components/follow_request_note";
|
||||
|
||||
const mapDispatchToProps = (dispatch, { account }) => ({
|
||||
onAuthorize () {
|
||||
dispatch(authorizeFollowRequest(account.get('id')));
|
||||
dispatch(authorizeFollowRequest(account.get("id")));
|
||||
},
|
||||
|
||||
onReject () {
|
||||
dispatch(rejectFollowRequest(account.get('id')));
|
||||
dispatch(rejectFollowRequest(account.get("id")));
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import FeaturedTags from 'flavours/glitch/features/account/containers/featured_tags_container';
|
||||
import { normalizeForLookup } from 'flavours/glitch/reducers/accounts_map';
|
||||
import FeaturedTags from "flavours/glitch/features/account/containers/featured_tags_container";
|
||||
import { normalizeForLookup } from "flavours/glitch/reducers/accounts_map";
|
||||
|
||||
const mapStateToProps = (state, { match: { params: { acct } } }) => {
|
||||
const accountId = state.getIn(['accounts_map', normalizeForLookup(acct)]);
|
||||
const accountId = state.getIn(["accounts_map", normalizeForLookup(acct)]);
|
||||
|
||||
if (!accountId) {
|
||||
return {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import { Blurhash } from 'flavours/glitch/components/blurhash';
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { autoPlayGif, displayMedia } from 'flavours/glitch/initial_state';
|
||||
import { Blurhash } from "flavours/glitch/components/blurhash";
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
import { autoPlayGif, displayMedia } from "flavours/glitch/initial_state";
|
||||
|
||||
export default class MediaItem extends ImmutablePureComponent {
|
||||
|
||||
@@ -19,7 +19,7 @@ export default class MediaItem extends ImmutablePureComponent {
|
||||
};
|
||||
|
||||
state = {
|
||||
visible: displayMedia !== 'hide_all' && !this.props.attachment.getIn(['status', 'sensitive']) || displayMedia === 'show_all',
|
||||
visible: displayMedia !== "hide_all" && !this.props.attachment.getIn(["status", "sensitive"]) || displayMedia === "show_all",
|
||||
loaded: false,
|
||||
};
|
||||
|
||||
@@ -41,7 +41,7 @@ export default class MediaItem extends ImmutablePureComponent {
|
||||
};
|
||||
|
||||
hoverToPlay () {
|
||||
return !autoPlayGif && ['gifv', 'video'].indexOf(this.props.attachment.get('type')) !== -1;
|
||||
return !autoPlayGif && ["gifv", "video"].indexOf(this.props.attachment.get("type")) !== -1;
|
||||
}
|
||||
|
||||
handleClick = e => {
|
||||
@@ -62,8 +62,8 @@ export default class MediaItem extends ImmutablePureComponent {
|
||||
|
||||
const width = `${Math.floor((displayWidth - 4) / 3) - 4}px`;
|
||||
const height = width;
|
||||
const status = attachment.get('status');
|
||||
const title = status.get('spoiler_text') || attachment.get('description');
|
||||
const status = attachment.get("status");
|
||||
const title = status.get("spoiler_text") || attachment.get("description");
|
||||
|
||||
let thumbnail, label, icon, content;
|
||||
|
||||
@@ -74,45 +74,45 @@ export default class MediaItem extends ImmutablePureComponent {
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
if (['audio', 'video'].includes(attachment.get('type'))) {
|
||||
if (["audio", "video"].includes(attachment.get("type"))) {
|
||||
content = (
|
||||
<img
|
||||
src={attachment.get('preview_url') || attachment.getIn(['account', 'avatar_static'])}
|
||||
alt={attachment.get('description')}
|
||||
lang={status.get('language')}
|
||||
src={attachment.get("preview_url") || attachment.getIn(["account", "avatar_static"])}
|
||||
alt={attachment.get("description")}
|
||||
lang={status.get("language")}
|
||||
onLoad={this.handleImageLoad}
|
||||
/>
|
||||
);
|
||||
|
||||
if (attachment.get('type') === 'audio') {
|
||||
if (attachment.get("type") === "audio") {
|
||||
label = <Icon id='music' />;
|
||||
} else {
|
||||
label = <Icon id='play' />;
|
||||
}
|
||||
} else if (attachment.get('type') === 'image') {
|
||||
const focusX = attachment.getIn(['meta', 'focus', 'x']) || 0;
|
||||
const focusY = attachment.getIn(['meta', 'focus', 'y']) || 0;
|
||||
} else if (attachment.get("type") === "image") {
|
||||
const focusX = attachment.getIn(["meta", "focus", "x"]) || 0;
|
||||
const focusY = attachment.getIn(["meta", "focus", "y"]) || 0;
|
||||
const x = ((focusX / 2) + .5) * 100;
|
||||
const y = ((focusY / -2) + .5) * 100;
|
||||
|
||||
content = (
|
||||
<img
|
||||
src={attachment.get('preview_url')}
|
||||
alt={attachment.get('description')}
|
||||
lang={status.get('language')}
|
||||
src={attachment.get("preview_url")}
|
||||
alt={attachment.get("description")}
|
||||
lang={status.get("language")}
|
||||
style={{ objectPosition: `${x}% ${y}%` }}
|
||||
onLoad={this.handleImageLoad}
|
||||
/>
|
||||
);
|
||||
} else if (attachment.get('type') === 'gifv') {
|
||||
} else if (attachment.get("type") === "gifv") {
|
||||
content = (
|
||||
<video
|
||||
className='media-gallery__item-gifv-thumbnail'
|
||||
aria-label={attachment.get('description')}
|
||||
title={attachment.get('description')}
|
||||
lang={status.get('language')}
|
||||
aria-label={attachment.get("description")}
|
||||
title={attachment.get("description")}
|
||||
lang={status.get("language")}
|
||||
role='application'
|
||||
src={attachment.get('url')}
|
||||
src={attachment.get("url")}
|
||||
onMouseEnter={this.handleMouseEnter}
|
||||
onMouseLeave={this.handleMouseLeave}
|
||||
autoPlay={autoPlayGif}
|
||||
@@ -122,7 +122,7 @@ export default class MediaItem extends ImmutablePureComponent {
|
||||
/>
|
||||
);
|
||||
|
||||
label = 'GIF';
|
||||
label = "GIF";
|
||||
}
|
||||
|
||||
thumbnail = (
|
||||
@@ -140,10 +140,10 @@ export default class MediaItem extends ImmutablePureComponent {
|
||||
|
||||
return (
|
||||
<div className='account-gallery__item' style={{ width, height }}>
|
||||
<a className='media-gallery__item-thumbnail' href={status.get('url')} onClick={this.handleClick} title={title} target='_blank' rel='noopener noreferrer'>
|
||||
<a className='media-gallery__item-thumbnail' href={status.get("url")} onClick={this.handleClick} title={title} target='_blank' rel='noopener noreferrer'>
|
||||
<Blurhash
|
||||
hash={attachment.get('blurhash')}
|
||||
className={classNames('media-gallery__preview', { 'media-gallery__preview--hidden': visible && loaded })}
|
||||
hash={attachment.get("blurhash")}
|
||||
className={classNames("media-gallery__preview", { "media-gallery__preview--hidden": visible && loaded })}
|
||||
dummy={!useBlurhash}
|
||||
/>
|
||||
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { lookupAccount, fetchAccount } from 'flavours/glitch/actions/accounts';
|
||||
import { openModal } from 'flavours/glitch/actions/modal';
|
||||
import { expandAccountMediaTimeline } from 'flavours/glitch/actions/timelines';
|
||||
import { LoadMore } from 'flavours/glitch/components/load_more';
|
||||
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||
import ScrollContainer from 'flavours/glitch/containers/scroll_container';
|
||||
import ProfileColumnHeader from 'flavours/glitch/features/account/components/profile_column_header';
|
||||
import HeaderContainer from 'flavours/glitch/features/account_timeline/containers/header_container';
|
||||
import BundleColumnError from 'flavours/glitch/features/ui/components/bundle_column_error';
|
||||
import Column from 'flavours/glitch/features/ui/components/column';
|
||||
import { normalizeForLookup } from 'flavours/glitch/reducers/accounts_map';
|
||||
import { getAccountGallery } from 'flavours/glitch/selectors';
|
||||
import { lookupAccount, fetchAccount } from "flavours/glitch/actions/accounts";
|
||||
import { openModal } from "flavours/glitch/actions/modal";
|
||||
import { expandAccountMediaTimeline } from "flavours/glitch/actions/timelines";
|
||||
import { LoadMore } from "flavours/glitch/components/load_more";
|
||||
import { LoadingIndicator } from "flavours/glitch/components/loading_indicator";
|
||||
import ScrollContainer from "flavours/glitch/containers/scroll_container";
|
||||
import ProfileColumnHeader from "flavours/glitch/features/account/components/profile_column_header";
|
||||
import HeaderContainer from "flavours/glitch/features/account_timeline/containers/header_container";
|
||||
import BundleColumnError from "flavours/glitch/features/ui/components/bundle_column_error";
|
||||
import Column from "flavours/glitch/features/ui/components/column";
|
||||
import { normalizeForLookup } from "flavours/glitch/reducers/accounts_map";
|
||||
import { getAccountGallery } from "flavours/glitch/selectors";
|
||||
|
||||
import MediaItem from './components/media_item';
|
||||
import MediaItem from "./components/media_item";
|
||||
|
||||
const mapStateToProps = (state, { params: { acct, id } }) => {
|
||||
const accountId = id || state.getIn(['accounts_map', normalizeForLookup(acct)]);
|
||||
const accountId = id || state.getIn(["accounts_map", normalizeForLookup(acct)]);
|
||||
|
||||
if (!accountId) {
|
||||
return {
|
||||
@@ -32,12 +32,12 @@ const mapStateToProps = (state, { params: { acct, id } }) => {
|
||||
|
||||
return {
|
||||
accountId,
|
||||
settings: state.get('local_settings'),
|
||||
isAccount: !!state.getIn(['accounts', accountId]),
|
||||
settings: state.get("local_settings"),
|
||||
isAccount: !!state.getIn(["accounts", accountId]),
|
||||
attachments: getAccountGallery(state, accountId),
|
||||
isLoading: state.getIn(['timelines', `account:${accountId}:media`, 'isLoading']),
|
||||
hasMore: state.getIn(['timelines', `account:${accountId}:media`, 'hasMore']),
|
||||
suspended: state.getIn(['accounts', accountId, 'suspended'], false),
|
||||
isLoading: state.getIn(["timelines", `account:${accountId}:media`, "isLoading"]),
|
||||
hasMore: state.getIn(["timelines", `account:${accountId}:media`, "hasMore"]),
|
||||
suspended: state.getIn(["accounts", accountId, "suspended"], false),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -88,7 +88,9 @@ class AccountGallery extends ImmutablePureComponent {
|
||||
_load () {
|
||||
const { accountId, isAccount, dispatch } = this.props;
|
||||
|
||||
if (!isAccount) dispatch(fetchAccount(accountId));
|
||||
if (!isAccount) {
|
||||
dispatch(fetchAccount(accountId));
|
||||
}
|
||||
dispatch(expandAccountMediaTimeline(accountId));
|
||||
}
|
||||
|
||||
@@ -118,7 +120,7 @@ class AccountGallery extends ImmutablePureComponent {
|
||||
|
||||
handleScrollToBottom = () => {
|
||||
if (this.props.hasMore) {
|
||||
this.handleLoadMore(this.props.attachments.size > 0 ? this.props.attachments.last().getIn(['status', 'id']) : undefined);
|
||||
this.handleLoadMore(this.props.attachments.size > 0 ? this.props.attachments.last().getIn(["status", "id"]) : undefined);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -146,25 +148,25 @@ class AccountGallery extends ImmutablePureComponent {
|
||||
|
||||
handleOpenMedia = attachment => {
|
||||
const { dispatch } = this.props;
|
||||
const statusId = attachment.getIn(['status', 'id']);
|
||||
const lang = attachment.getIn(['status', 'language']);
|
||||
const statusId = attachment.getIn(["status", "id"]);
|
||||
const lang = attachment.getIn(["status", "language"]);
|
||||
|
||||
if (attachment.get('type') === 'video') {
|
||||
if (attachment.get("type") === "video") {
|
||||
dispatch(openModal({
|
||||
modalType: 'VIDEO',
|
||||
modalType: "VIDEO",
|
||||
modalProps: { media: attachment, statusId, lang, options: { autoPlay: true } },
|
||||
}));
|
||||
} else if (attachment.get('type') === 'audio') {
|
||||
} else if (attachment.get("type") === "audio") {
|
||||
dispatch(openModal({
|
||||
modalType: 'AUDIO',
|
||||
modalType: "AUDIO",
|
||||
modalProps: { media: attachment, statusId, lang, options: { autoPlay: true } },
|
||||
}));
|
||||
} else {
|
||||
const media = attachment.getIn(['status', 'media_attachments']);
|
||||
const index = media.findIndex(x => x.get('id') === attachment.get('id'));
|
||||
const media = attachment.getIn(["status", "media_attachments"]);
|
||||
const index = media.findIndex(x => x.get("id") === attachment.get("id"));
|
||||
|
||||
dispatch(openModal({
|
||||
modalType: 'MEDIA',
|
||||
modalType: "MEDIA",
|
||||
modalProps: { media, index, statusId, lang },
|
||||
}));
|
||||
}
|
||||
@@ -215,14 +217,14 @@ class AccountGallery extends ImmutablePureComponent {
|
||||
) : (
|
||||
<div role='feed' className='account-gallery__container' ref={this.handleRef}>
|
||||
{attachments.map((attachment, index) => attachment === null ? (
|
||||
<LoadMoreMedia key={'more:' + attachments.getIn(index + 1, 'id')} maxId={index > 0 ? attachments.getIn(index - 1, 'id') : null} onLoadMore={this.handleLoadMore} />
|
||||
<LoadMoreMedia key={"more:" + attachments.getIn(index + 1, "id")} maxId={index > 0 ? attachments.getIn(index - 1, "id") : null} onLoadMore={this.handleLoadMore} />
|
||||
) : (
|
||||
<MediaItem
|
||||
key={attachment.get('id')}
|
||||
key={attachment.get("id")}
|
||||
attachment={attachment}
|
||||
displayWidth={width}
|
||||
onOpenMedia={this.handleOpenMedia}
|
||||
useBlurhash={settings.getIn(['media', 'use_blurhash'])}
|
||||
useBlurhash={settings.getIn(["media", "use_blurhash"])}
|
||||
/>
|
||||
))}
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { NavLink } from "react-router-dom";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import ActionBar from 'flavours/glitch/features/account/components/action_bar';
|
||||
import InnerHeader from 'flavours/glitch/features/account/components/header';
|
||||
import ActionBar from "flavours/glitch/features/account/components/action_bar";
|
||||
import InnerHeader from "flavours/glitch/features/account/components/header";
|
||||
|
||||
import MemorialNote from './memorial_note';
|
||||
import MovedNote from './moved_note';
|
||||
import MemorialNote from "./memorial_note";
|
||||
import MovedNote from "./moved_note";
|
||||
|
||||
export default class Header extends ImmutablePureComponent {
|
||||
|
||||
@@ -73,17 +73,21 @@ export default class Header extends ImmutablePureComponent {
|
||||
};
|
||||
|
||||
handleBlockDomain = () => {
|
||||
const domain = this.props.account.get('acct').split('@')[1];
|
||||
const domain = this.props.account.get("acct").split("@")[1];
|
||||
|
||||
if (!domain) return;
|
||||
if (!domain) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.onBlockDomain(domain);
|
||||
};
|
||||
|
||||
handleUnblockDomain = () => {
|
||||
const domain = this.props.account.get('acct').split('@')[1];
|
||||
const domain = this.props.account.get("acct").split("@")[1];
|
||||
|
||||
if (!domain) return;
|
||||
if (!domain) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.onUnblockDomain(domain);
|
||||
};
|
||||
@@ -121,8 +125,8 @@ export default class Header extends ImmutablePureComponent {
|
||||
|
||||
return (
|
||||
<div className='account-timeline__header'>
|
||||
{(!hidden && account.get('memorial')) && <MemorialNote />}
|
||||
{(!hidden && account.get('moved')) && <MovedNote from={account} to={account.get('moved')} />}
|
||||
{(!hidden && account.get("memorial")) && <MemorialNote />}
|
||||
{(!hidden && account.get("moved")) && <MovedNote from={account} to={account.get("moved")} />}
|
||||
|
||||
<InnerHeader
|
||||
account={account}
|
||||
@@ -152,9 +156,9 @@ export default class Header extends ImmutablePureComponent {
|
||||
|
||||
{!(hideTabs || hidden) && (
|
||||
<div className='account__section-headline'>
|
||||
<NavLink exact to={`/@${account.get('acct')}`}><FormattedMessage id='account.posts' defaultMessage='Posts' /></NavLink>
|
||||
<NavLink exact to={`/@${account.get('acct')}/with_replies`}><FormattedMessage id='account.posts_with_replies' defaultMessage='Posts and replies' /></NavLink>
|
||||
<NavLink exact to={`/@${account.get('acct')}/media`}><FormattedMessage id='account.media' defaultMessage='Media' /></NavLink>
|
||||
<NavLink exact to={`/@${account.get("acct")}`}><FormattedMessage id='account.posts' defaultMessage='Posts' /></NavLink>
|
||||
<NavLink exact to={`/@${account.get("acct")}/with_replies`}><FormattedMessage id='account.posts_with_replies' defaultMessage='Posts and replies' /></NavLink>
|
||||
<NavLink exact to={`/@${account.get("acct")}/media`}><FormattedMessage id='account.media' defaultMessage='Media' /></NavLink>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
+7
-7
@@ -1,13 +1,13 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { revealAccount } from 'flavours/glitch/actions/accounts';
|
||||
import Button from 'flavours/glitch/components/button';
|
||||
import { domain } from 'flavours/glitch/initial_state';
|
||||
import { revealAccount } from "flavours/glitch/actions/accounts";
|
||||
import Button from "flavours/glitch/components/button";
|
||||
import { domain } from "flavours/glitch/initial_state";
|
||||
|
||||
const mapDispatchToProps = (dispatch, { accountId }) => ({
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
const MemorialNote = () => (
|
||||
<div className='account-memorial-banner'>
|
||||
|
||||
+10
-10
@@ -1,14 +1,14 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
|
||||
import AvatarOverlay from '../../../components/avatar_overlay';
|
||||
import { DisplayName } from '../../../components/display_name';
|
||||
import AvatarOverlay from "../../../components/avatar_overlay";
|
||||
import { DisplayName } from "../../../components/display_name";
|
||||
|
||||
export default class MovedNote extends ImmutablePureComponent {
|
||||
|
||||
@@ -24,7 +24,7 @@ export default class MovedNote extends ImmutablePureComponent {
|
||||
handleAccountClick = e => {
|
||||
if (e.button === 0) {
|
||||
e.preventDefault();
|
||||
this.context.router.history.push(`/@${this.props.to.get('acct')}`);
|
||||
this.context.router.history.push(`/@${this.props.to.get("acct")}`);
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
@@ -32,7 +32,7 @@ export default class MovedNote extends ImmutablePureComponent {
|
||||
|
||||
render () {
|
||||
const { from, to } = this.props;
|
||||
const displayNameHtml = { __html: from.get('display_name_html') };
|
||||
const displayNameHtml = { __html: from.get("display_name_html") };
|
||||
|
||||
return (
|
||||
<div className='account__moved-note'>
|
||||
@@ -41,7 +41,7 @@ export default class MovedNote extends ImmutablePureComponent {
|
||||
<FormattedMessage id='account.moved_to' defaultMessage='{name} has indicated that their new account is now:' values={{ name: <bdi><strong dangerouslySetInnerHTML={displayNameHtml} /></bdi> }} />
|
||||
</div>
|
||||
|
||||
<a href={to.get('url')} onClick={this.handleAccountClick} className='detailed-status__display-name'>
|
||||
<a href={to.get("url")} onClick={this.handleAccountClick} className='detailed-status__display-name'>
|
||||
<div className='detailed-status__display-avatar'><AvatarOverlay account={to} friend={from} /></div>
|
||||
<DisplayName account={to} />
|
||||
</a>
|
||||
|
||||
+53
-53
@@ -1,8 +1,8 @@
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { initEditAccountNote } from 'flavours/glitch/actions/account_notes';
|
||||
import { initEditAccountNote } from "flavours/glitch/actions/account_notes";
|
||||
import {
|
||||
followAccount,
|
||||
unfollowAccount,
|
||||
@@ -10,25 +10,25 @@ import {
|
||||
unmuteAccount,
|
||||
pinAccount,
|
||||
unpinAccount,
|
||||
} from 'flavours/glitch/actions/accounts';
|
||||
import { initBlockModal } from 'flavours/glitch/actions/blocks';
|
||||
} from "flavours/glitch/actions/accounts";
|
||||
import { initBlockModal } from "flavours/glitch/actions/blocks";
|
||||
import {
|
||||
mentionCompose,
|
||||
directCompose,
|
||||
} from 'flavours/glitch/actions/compose';
|
||||
import { blockDomain, unblockDomain } from 'flavours/glitch/actions/domain_blocks';
|
||||
import { openModal } from 'flavours/glitch/actions/modal';
|
||||
import { initMuteModal } from 'flavours/glitch/actions/mutes';
|
||||
import { initReport } from 'flavours/glitch/actions/reports';
|
||||
import { unfollowModal } from 'flavours/glitch/initial_state';
|
||||
import { makeGetAccount, getAccountHidden } from 'flavours/glitch/selectors';
|
||||
} from "flavours/glitch/actions/compose";
|
||||
import { blockDomain, unblockDomain } from "flavours/glitch/actions/domain_blocks";
|
||||
import { openModal } from "flavours/glitch/actions/modal";
|
||||
import { initMuteModal } from "flavours/glitch/actions/mutes";
|
||||
import { initReport } from "flavours/glitch/actions/reports";
|
||||
import { unfollowModal } from "flavours/glitch/initial_state";
|
||||
import { makeGetAccount, getAccountHidden } from "flavours/glitch/selectors";
|
||||
|
||||
import Header from '../components/header';
|
||||
import Header from "../components/header";
|
||||
|
||||
const messages = defineMessages({
|
||||
cancelFollowRequestConfirm: { id: 'confirmations.cancel_follow_request.confirm', defaultMessage: 'Withdraw request' },
|
||||
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
|
||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Block entire domain' },
|
||||
cancelFollowRequestConfirm: { id: "confirmations.cancel_follow_request.confirm", defaultMessage: "Withdraw request" },
|
||||
unfollowConfirm: { id: "confirmations.unfollow.confirm", defaultMessage: "Unfollow" },
|
||||
blockDomainConfirm: { id: "confirmations.domain_block.confirm", defaultMessage: "Block entire domain" },
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
@@ -36,7 +36,7 @@ const makeMapStateToProps = () => {
|
||||
|
||||
const mapStateToProps = (state, { accountId }) => ({
|
||||
account: getAccount(state, accountId),
|
||||
domain: state.getIn(['meta', 'domain']),
|
||||
domain: state.getIn(["meta", "domain"]),
|
||||
hidden: getAccountHidden(state, accountId),
|
||||
});
|
||||
|
||||
@@ -46,51 +46,51 @@ const makeMapStateToProps = () => {
|
||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
|
||||
onFollow (account) {
|
||||
if (account.getIn(['relationship', 'following'])) {
|
||||
if (account.getIn(["relationship", "following"])) {
|
||||
if (unfollowModal) {
|
||||
dispatch(openModal({
|
||||
modalType: 'CONFIRM',
|
||||
modalType: "CONFIRM",
|
||||
modalProps: {
|
||||
message: <FormattedMessage id='confirmations.unfollow.message' defaultMessage='Are you sure you want to unfollow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
message: <FormattedMessage id='confirmations.unfollow.message' defaultMessage='Are you sure you want to unfollow {name}?' values={{ name: <strong>@{account.get("acct")}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.unfollowConfirm),
|
||||
onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
|
||||
onConfirm: () => dispatch(unfollowAccount(account.get("id"))),
|
||||
},
|
||||
}));
|
||||
} else {
|
||||
dispatch(unfollowAccount(account.get('id')));
|
||||
dispatch(unfollowAccount(account.get("id")));
|
||||
}
|
||||
} else if (account.getIn(['relationship', 'requested'])) {
|
||||
} else if (account.getIn(["relationship", "requested"])) {
|
||||
if (unfollowModal) {
|
||||
dispatch(openModal({
|
||||
modalType: 'CONFIRM',
|
||||
modalType: "CONFIRM",
|
||||
modalProps: {
|
||||
message: <FormattedMessage id='confirmations.cancel_follow_request.message' defaultMessage='Are you sure you want to withdraw your request to follow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
message: <FormattedMessage id='confirmations.cancel_follow_request.message' defaultMessage='Are you sure you want to withdraw your request to follow {name}?' values={{ name: <strong>@{account.get("acct")}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.cancelFollowRequestConfirm),
|
||||
onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
|
||||
onConfirm: () => dispatch(unfollowAccount(account.get("id"))),
|
||||
},
|
||||
}));
|
||||
} else {
|
||||
dispatch(unfollowAccount(account.get('id')));
|
||||
dispatch(unfollowAccount(account.get("id")));
|
||||
}
|
||||
} else {
|
||||
dispatch(followAccount(account.get('id')));
|
||||
dispatch(followAccount(account.get("id")));
|
||||
}
|
||||
},
|
||||
|
||||
onInteractionModal (account) {
|
||||
dispatch(openModal({
|
||||
modalType: 'INTERACTION',
|
||||
modalType: "INTERACTION",
|
||||
modalProps: {
|
||||
type: 'follow',
|
||||
accountId: account.get('id'),
|
||||
url: account.get('uri'),
|
||||
type: "follow",
|
||||
accountId: account.get("id"),
|
||||
url: account.get("uri"),
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
||||
onBlock (account) {
|
||||
if (account.getIn(['relationship', 'blocking'])) {
|
||||
dispatch(unblockAccount(account.get('id')));
|
||||
if (account.getIn(["relationship", "blocking"])) {
|
||||
dispatch(unblockAccount(account.get("id")));
|
||||
} else {
|
||||
dispatch(initBlockModal(account));
|
||||
}
|
||||
@@ -105,26 +105,26 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
},
|
||||
|
||||
onReblogToggle (account) {
|
||||
if (account.getIn(['relationship', 'showing_reblogs'])) {
|
||||
dispatch(followAccount(account.get('id'), { reblogs: false }));
|
||||
if (account.getIn(["relationship", "showing_reblogs"])) {
|
||||
dispatch(followAccount(account.get("id"), { reblogs: false }));
|
||||
} else {
|
||||
dispatch(followAccount(account.get('id'), { reblogs: true }));
|
||||
dispatch(followAccount(account.get("id"), { reblogs: true }));
|
||||
}
|
||||
},
|
||||
|
||||
onEndorseToggle (account) {
|
||||
if (account.getIn(['relationship', 'endorsed'])) {
|
||||
dispatch(unpinAccount(account.get('id')));
|
||||
if (account.getIn(["relationship", "endorsed"])) {
|
||||
dispatch(unpinAccount(account.get("id")));
|
||||
} else {
|
||||
dispatch(pinAccount(account.get('id')));
|
||||
dispatch(pinAccount(account.get("id")));
|
||||
}
|
||||
},
|
||||
|
||||
onNotifyToggle (account) {
|
||||
if (account.getIn(['relationship', 'notifying'])) {
|
||||
dispatch(followAccount(account.get('id'), { notify: false }));
|
||||
if (account.getIn(["relationship", "notifying"])) {
|
||||
dispatch(followAccount(account.get("id"), { notify: false }));
|
||||
} else {
|
||||
dispatch(followAccount(account.get('id'), { notify: true }));
|
||||
dispatch(followAccount(account.get("id"), { notify: true }));
|
||||
}
|
||||
},
|
||||
|
||||
@@ -133,8 +133,8 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
},
|
||||
|
||||
onMute (account) {
|
||||
if (account.getIn(['relationship', 'muting'])) {
|
||||
dispatch(unmuteAccount(account.get('id')));
|
||||
if (account.getIn(["relationship", "muting"])) {
|
||||
dispatch(unmuteAccount(account.get("id")));
|
||||
} else {
|
||||
dispatch(initMuteModal(account));
|
||||
}
|
||||
@@ -146,7 +146,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
|
||||
onBlockDomain (domain) {
|
||||
dispatch(openModal({
|
||||
modalType: 'CONFIRM',
|
||||
modalType: "CONFIRM",
|
||||
modalProps: {
|
||||
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.' values={{ domain: <strong>{domain}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.blockDomainConfirm),
|
||||
@@ -161,28 +161,28 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
|
||||
onAddToList (account) {
|
||||
dispatch(openModal({
|
||||
modalType: 'LIST_ADDER',
|
||||
modalType: "LIST_ADDER",
|
||||
modalProps: {
|
||||
accountId: account.get('id'),
|
||||
accountId: account.get("id"),
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
||||
onChangeLanguages (account) {
|
||||
dispatch(openModal({
|
||||
modalType: 'SUBSCRIBED_LANGUAGES',
|
||||
modalType: "SUBSCRIBED_LANGUAGES",
|
||||
modalProps: {
|
||||
accountId: account.get('id'),
|
||||
accountId: account.get("id"),
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
||||
onOpenAvatar (account) {
|
||||
dispatch(openModal({
|
||||
modalType: 'IMAGE',
|
||||
modalType: "IMAGE",
|
||||
modalProps: {
|
||||
src: account.get('avatar'),
|
||||
alt: account.get('acct'),
|
||||
src: account.get("avatar"),
|
||||
alt: account.get("acct"),
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import { List as ImmutableList } from "immutable";
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { lookupAccount, fetchAccount } from 'flavours/glitch/actions/accounts';
|
||||
import { TimelineHint } from 'flavours/glitch/components/timeline_hint';
|
||||
import ProfileColumnHeader from 'flavours/glitch/features/account/components/profile_column_header';
|
||||
import BundleColumnError from 'flavours/glitch/features/ui/components/bundle_column_error';
|
||||
import { normalizeForLookup } from 'flavours/glitch/reducers/accounts_map';
|
||||
import { getAccountHidden } from 'flavours/glitch/selectors';
|
||||
import { lookupAccount, fetchAccount } from "flavours/glitch/actions/accounts";
|
||||
import { TimelineHint } from "flavours/glitch/components/timeline_hint";
|
||||
import ProfileColumnHeader from "flavours/glitch/features/account/components/profile_column_header";
|
||||
import BundleColumnError from "flavours/glitch/features/ui/components/bundle_column_error";
|
||||
import { normalizeForLookup } from "flavours/glitch/reducers/accounts_map";
|
||||
import { getAccountHidden } from "flavours/glitch/selectors";
|
||||
|
||||
import { fetchFeaturedTags } from '../../actions/featured_tags';
|
||||
import { expandAccountFeaturedTimeline, expandAccountTimeline } from '../../actions/timelines';
|
||||
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||
import StatusList from '../../components/status_list';
|
||||
import Column from '../ui/components/column';
|
||||
import { fetchFeaturedTags } from "../../actions/featured_tags";
|
||||
import { expandAccountFeaturedTimeline, expandAccountTimeline } from "../../actions/timelines";
|
||||
import { LoadingIndicator } from "../../components/loading_indicator";
|
||||
import StatusList from "../../components/status_list";
|
||||
import Column from "../ui/components/column";
|
||||
|
||||
import LimitedAccountHint from './components/limited_account_hint';
|
||||
import HeaderContainer from './containers/header_container';
|
||||
import LimitedAccountHint from "./components/limited_account_hint";
|
||||
import HeaderContainer from "./containers/header_container";
|
||||
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ import HeaderContainer from './containers/header_container';
|
||||
const emptyList = ImmutableList();
|
||||
|
||||
const mapStateToProps = (state, { params: { acct, id, tagged }, withReplies = false }) => {
|
||||
const accountId = id || state.getIn(['accounts_map', normalizeForLookup(acct)]);
|
||||
const accountId = id || state.getIn(["accounts_map", normalizeForLookup(acct)]);
|
||||
|
||||
if (accountId === null) {
|
||||
return {
|
||||
@@ -48,18 +48,18 @@ const mapStateToProps = (state, { params: { acct, id, tagged }, withReplies = fa
|
||||
};
|
||||
}
|
||||
|
||||
const path = withReplies ? `${accountId}:with_replies` : `${accountId}${tagged ? `:${tagged}` : ''}`;
|
||||
const path = withReplies ? `${accountId}:with_replies` : `${accountId}${tagged ? `:${tagged}` : ""}`;
|
||||
|
||||
return {
|
||||
accountId,
|
||||
remote: !!(state.getIn(['accounts', accountId, 'acct']) !== state.getIn(['accounts', accountId, 'username'])),
|
||||
remoteUrl: state.getIn(['accounts', accountId, 'url']),
|
||||
isAccount: !!state.getIn(['accounts', accountId]),
|
||||
statusIds: state.getIn(['timelines', `account:${path}`, 'items'], ImmutableList()),
|
||||
featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned${tagged ? `:${tagged}` : ''}`, 'items'], ImmutableList()),
|
||||
isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']),
|
||||
hasMore: state.getIn(['timelines', `account:${path}`, 'hasMore']),
|
||||
suspended: state.getIn(['accounts', accountId, 'suspended'], false),
|
||||
remote: !!(state.getIn(["accounts", accountId, "acct"]) !== state.getIn(["accounts", accountId, "username"])),
|
||||
remoteUrl: state.getIn(["accounts", accountId, "url"]),
|
||||
isAccount: !!state.getIn(["accounts", accountId]),
|
||||
statusIds: state.getIn(["timelines", `account:${path}`, "items"], ImmutableList()),
|
||||
featuredStatusIds: withReplies ? ImmutableList() : state.getIn(["timelines", `account:${accountId}:pinned${tagged ? `:${tagged}` : ""}`, "items"], ImmutableList()),
|
||||
isLoading: state.getIn(["timelines", `account:${path}`, "isLoading"]),
|
||||
hasMore: state.getIn(["timelines", `account:${path}`, "hasMore"]),
|
||||
suspended: state.getIn(["accounts", accountId, "suspended"], false),
|
||||
hidden: getAccountHidden(state, accountId),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
|
||||
import { defineMessages, FormattedMessage, injectIntl } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import { is } from 'immutable';
|
||||
import { is } from "immutable";
|
||||
|
||||
import { throttle, debounce } from 'lodash';
|
||||
import { throttle, debounce } from "lodash";
|
||||
|
||||
import { Blurhash } from 'flavours/glitch/components/blurhash';
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { formatTime, getPointerPosition, fileNameFromURL } from 'flavours/glitch/features/video';
|
||||
import { displayMedia } from 'flavours/glitch/initial_state';
|
||||
import { Blurhash } from "flavours/glitch/components/blurhash";
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
import { formatTime, getPointerPosition, fileNameFromURL } from "flavours/glitch/features/video";
|
||||
import { displayMedia } from "flavours/glitch/initial_state";
|
||||
|
||||
import Visualizer from './visualizer';
|
||||
import Visualizer from "./visualizer";
|
||||
|
||||
|
||||
|
||||
const messages = defineMessages({
|
||||
play: { id: 'video.play', defaultMessage: 'Play' },
|
||||
pause: { id: 'video.pause', defaultMessage: 'Pause' },
|
||||
mute: { id: 'video.mute', defaultMessage: 'Mute sound' },
|
||||
unmute: { id: 'video.unmute', defaultMessage: 'Unmute sound' },
|
||||
download: { id: 'video.download', defaultMessage: 'Download file' },
|
||||
hide: { id: 'audio.hide', defaultMessage: 'Hide audio' },
|
||||
play: { id: "video.play", defaultMessage: "Play" },
|
||||
pause: { id: "video.pause", defaultMessage: "Pause" },
|
||||
mute: { id: "video.mute", defaultMessage: "Mute sound" },
|
||||
unmute: { id: "video.unmute", defaultMessage: "Unmute sound" },
|
||||
download: { id: "video.download", defaultMessage: "Download file" },
|
||||
hide: { id: "audio.hide", defaultMessage: "Hide audio" },
|
||||
});
|
||||
|
||||
const TICK_SIZE = 10;
|
||||
@@ -68,7 +68,7 @@ class Audio extends PureComponent {
|
||||
muted: false,
|
||||
volume: 1,
|
||||
dragging: false,
|
||||
revealed: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),
|
||||
revealed: this.props.visible !== undefined ? this.props.visible : (displayMedia !== "hide_all" && !this.props.sensitive || displayMedia === "show_all"),
|
||||
};
|
||||
|
||||
constructor (props) {
|
||||
@@ -136,8 +136,8 @@ class Audio extends PureComponent {
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
window.addEventListener('scroll', this.handleScroll);
|
||||
window.addEventListener('resize', this.handleResize, { passive: true });
|
||||
window.addEventListener("scroll", this.handleScroll);
|
||||
window.addEventListener("resize", this.handleResize, { passive: true });
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps, prevState) {
|
||||
@@ -158,11 +158,11 @@ class Audio extends PureComponent {
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
window.removeEventListener('scroll', this.handleScroll);
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
window.removeEventListener("scroll", this.handleScroll);
|
||||
window.removeEventListener("resize", this.handleResize);
|
||||
|
||||
if (!this.state.paused && this.audio && this.props.deployPictureInPicture) {
|
||||
this.props.deployPictureInPicture('audio', this._pack());
|
||||
this.props.deployPictureInPicture("audio", this._pack());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ class Audio extends PureComponent {
|
||||
handlePlay = () => {
|
||||
this.setState({ paused: false });
|
||||
|
||||
if (this.audioContext && this.audioContext.state === 'suspended') {
|
||||
if (this.audioContext && this.audioContext.state === "suspended") {
|
||||
this.audioContext.resume();
|
||||
}
|
||||
|
||||
@@ -231,10 +231,10 @@ class Audio extends PureComponent {
|
||||
};
|
||||
|
||||
handleVolumeMouseDown = e => {
|
||||
document.addEventListener('mousemove', this.handleMouseVolSlide, true);
|
||||
document.addEventListener('mouseup', this.handleVolumeMouseUp, true);
|
||||
document.addEventListener('touchmove', this.handleMouseVolSlide, true);
|
||||
document.addEventListener('touchend', this.handleVolumeMouseUp, true);
|
||||
document.addEventListener("mousemove", this.handleMouseVolSlide, true);
|
||||
document.addEventListener("mouseup", this.handleVolumeMouseUp, true);
|
||||
document.addEventListener("touchmove", this.handleMouseVolSlide, true);
|
||||
document.addEventListener("touchend", this.handleVolumeMouseUp, true);
|
||||
|
||||
this.handleMouseVolSlide(e);
|
||||
|
||||
@@ -243,17 +243,17 @@ class Audio extends PureComponent {
|
||||
};
|
||||
|
||||
handleVolumeMouseUp = () => {
|
||||
document.removeEventListener('mousemove', this.handleMouseVolSlide, true);
|
||||
document.removeEventListener('mouseup', this.handleVolumeMouseUp, true);
|
||||
document.removeEventListener('touchmove', this.handleMouseVolSlide, true);
|
||||
document.removeEventListener('touchend', this.handleVolumeMouseUp, true);
|
||||
document.removeEventListener("mousemove", this.handleMouseVolSlide, true);
|
||||
document.removeEventListener("mouseup", this.handleVolumeMouseUp, true);
|
||||
document.removeEventListener("touchmove", this.handleMouseVolSlide, true);
|
||||
document.removeEventListener("touchend", this.handleVolumeMouseUp, true);
|
||||
};
|
||||
|
||||
handleMouseDown = e => {
|
||||
document.addEventListener('mousemove', this.handleMouseMove, true);
|
||||
document.addEventListener('mouseup', this.handleMouseUp, true);
|
||||
document.addEventListener('touchmove', this.handleMouseMove, true);
|
||||
document.addEventListener('touchend', this.handleMouseUp, true);
|
||||
document.addEventListener("mousemove", this.handleMouseMove, true);
|
||||
document.addEventListener("mouseup", this.handleMouseUp, true);
|
||||
document.addEventListener("touchmove", this.handleMouseMove, true);
|
||||
document.addEventListener("touchend", this.handleMouseUp, true);
|
||||
|
||||
this.setState({ dragging: true });
|
||||
this.audio.pause();
|
||||
@@ -264,10 +264,10 @@ class Audio extends PureComponent {
|
||||
};
|
||||
|
||||
handleMouseUp = () => {
|
||||
document.removeEventListener('mousemove', this.handleMouseMove, true);
|
||||
document.removeEventListener('mouseup', this.handleMouseUp, true);
|
||||
document.removeEventListener('touchmove', this.handleMouseMove, true);
|
||||
document.removeEventListener('touchend', this.handleMouseUp, true);
|
||||
document.removeEventListener("mousemove", this.handleMouseMove, true);
|
||||
document.removeEventListener("mouseup", this.handleMouseUp, true);
|
||||
document.removeEventListener("touchmove", this.handleMouseMove, true);
|
||||
document.removeEventListener("touchend", this.handleMouseUp, true);
|
||||
|
||||
this.setState({ dragging: false });
|
||||
this.audio.play();
|
||||
@@ -315,7 +315,7 @@ class Audio extends PureComponent {
|
||||
this.audio.pause();
|
||||
|
||||
if (this.props.deployPictureInPicture) {
|
||||
this.props.deployPictureInPicture('audio', this._pack());
|
||||
this.props.deployPictureInPicture("audio", this._pack());
|
||||
}
|
||||
|
||||
this.setState({ paused: true });
|
||||
@@ -360,11 +360,11 @@ class Audio extends PureComponent {
|
||||
|
||||
handleDownload = () => {
|
||||
fetch(this.props.src).then(res => res.blob()).then(blob => {
|
||||
const element = document.createElement('a');
|
||||
const element = document.createElement("a");
|
||||
const objectURL = URL.createObjectURL(blob);
|
||||
|
||||
element.setAttribute('href', objectURL);
|
||||
element.setAttribute('download', fileNameFromURL(this.props.src));
|
||||
element.setAttribute("href", objectURL);
|
||||
element.setAttribute("download", fileNameFromURL(this.props.src));
|
||||
|
||||
document.body.appendChild(element);
|
||||
element.click();
|
||||
@@ -378,7 +378,9 @@ class Audio extends PureComponent {
|
||||
|
||||
_renderCanvas () {
|
||||
requestAnimationFrame(() => {
|
||||
if (!this.audio) return;
|
||||
if (!this.audio) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.handleTimeUpdate();
|
||||
this._clear();
|
||||
@@ -415,15 +417,15 @@ class Audio extends PureComponent {
|
||||
}
|
||||
|
||||
_getAccentColor () {
|
||||
return this.props.accentColor || '#ffffff';
|
||||
return this.props.accentColor || "#ffffff";
|
||||
}
|
||||
|
||||
_getBackgroundColor () {
|
||||
return this.props.backgroundColor || '#000000';
|
||||
return this.props.backgroundColor || "#000000";
|
||||
}
|
||||
|
||||
_getForegroundColor () {
|
||||
return this.props.foregroundColor || '#ffffff';
|
||||
return this.props.foregroundColor || "#ffffff";
|
||||
}
|
||||
|
||||
seekBy (time) {
|
||||
@@ -440,7 +442,7 @@ class Audio extends PureComponent {
|
||||
// On the audio element or the seek bar, we can safely use the space bar
|
||||
// for playback control because there are no buttons to press
|
||||
|
||||
if (e.key === ' ') {
|
||||
if (e.key === " ") {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.togglePlay();
|
||||
@@ -449,26 +451,26 @@ class Audio extends PureComponent {
|
||||
|
||||
handleKeyDown = e => {
|
||||
switch(e.key) {
|
||||
case 'k':
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.togglePlay();
|
||||
break;
|
||||
case 'm':
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.toggleMute();
|
||||
break;
|
||||
case 'j':
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.seekBy(-10);
|
||||
break;
|
||||
case 'l':
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.seekBy(10);
|
||||
break;
|
||||
case "k":
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.togglePlay();
|
||||
break;
|
||||
case "m":
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.toggleMute();
|
||||
break;
|
||||
case "j":
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.seekBy(-10);
|
||||
break;
|
||||
case "l":
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.seekBy(10);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -487,12 +489,12 @@ class Audio extends PureComponent {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames('audio-player', { editable, inactive: !revealed })} ref={this.setPlayerRef} style={{ backgroundColor: this._getBackgroundColor(), color: this._getForegroundColor(), aspectRatio: '16 / 9' }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} tabIndex={0} onKeyDown={this.handleKeyDown}>
|
||||
<div className={classNames("audio-player", { editable, inactive: !revealed })} ref={this.setPlayerRef} style={{ backgroundColor: this._getBackgroundColor(), color: this._getForegroundColor(), aspectRatio: "16 / 9" }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} tabIndex={0} onKeyDown={this.handleKeyDown}>
|
||||
|
||||
<Blurhash
|
||||
hash={blurhash}
|
||||
className={classNames('media-gallery__preview', {
|
||||
'media-gallery__preview--hidden': revealed,
|
||||
className={classNames("media-gallery__preview", {
|
||||
"media-gallery__preview--hidden": revealed,
|
||||
})}
|
||||
dummy={!useBlurhash}
|
||||
/>
|
||||
@@ -500,7 +502,7 @@ class Audio extends PureComponent {
|
||||
{(revealed || editable) && <audio
|
||||
src={src}
|
||||
ref={this.setAudioRef}
|
||||
preload={autoPlay ? 'auto' : 'none'}
|
||||
preload={autoPlay ? "auto" : "none"}
|
||||
onPlay={this.handlePlay}
|
||||
onPause={this.handlePause}
|
||||
onProgress={this.handleProgress}
|
||||
@@ -514,7 +516,7 @@ class Audio extends PureComponent {
|
||||
className='audio-player__canvas'
|
||||
width={this.state.width}
|
||||
height={this.state.height}
|
||||
style={{ width: '100%', position: 'absolute', top: 0, left: 0 }}
|
||||
style={{ width: "100%", position: "absolute", top: 0, left: 0 }}
|
||||
ref={this.setCanvasRef}
|
||||
onClick={this.togglePlay}
|
||||
onKeyDown={this.handleAudioKeyDown}
|
||||
@@ -523,7 +525,7 @@ class Audio extends PureComponent {
|
||||
lang={lang}
|
||||
/>
|
||||
|
||||
<div className={classNames('spoiler-button', { 'spoiler-button--hidden': revealed || editable })}>
|
||||
<div className={classNames("spoiler-button", { "spoiler-button--hidden": revealed || editable })}>
|
||||
<button type='button' className='spoiler-button__overlay' onClick={this.toggleReveal}>
|
||||
<span className='spoiler-button__overlay__label'>
|
||||
{warning}
|
||||
@@ -536,14 +538,14 @@ class Audio extends PureComponent {
|
||||
src={this.props.poster}
|
||||
alt=''
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: '50%',
|
||||
top: '50%',
|
||||
position: "absolute",
|
||||
left: "50%",
|
||||
top: "50%",
|
||||
height: `calc(${(100 - 2 * 100 * PADDING / 982)}% - ${TICK_SIZE * 2}px)`,
|
||||
aspectRatio: '1',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
borderRadius: '50%',
|
||||
pointerEvents: 'none',
|
||||
aspectRatio: "1",
|
||||
transform: "translate(-50%, -50%)",
|
||||
borderRadius: "50%",
|
||||
pointerEvents: "none",
|
||||
}}
|
||||
/>}
|
||||
|
||||
@@ -552,7 +554,7 @@ class Audio extends PureComponent {
|
||||
<div className='video-player__seek__progress' style={{ width: `${progress}%`, backgroundColor: this._getAccentColor() }} />
|
||||
|
||||
<span
|
||||
className={classNames('video-player__seek__handle', { active: dragging })}
|
||||
className={classNames("video-player__seek__handle", { active: dragging })}
|
||||
tabIndex={0}
|
||||
style={{ left: `${progress}%`, backgroundColor: this._getAccentColor() }}
|
||||
onKeyDown={this.handleAudioKeyDown}
|
||||
@@ -562,10 +564,10 @@ class Audio extends PureComponent {
|
||||
<div className='video-player__controls active'>
|
||||
<div className='video-player__buttons-bar'>
|
||||
<div className='video-player__buttons left'>
|
||||
<button type='button' title={intl.formatMessage(paused ? messages.play : messages.pause)} aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} className='player-button' onClick={this.togglePlay}><Icon id={paused ? 'play' : 'pause'} fixedWidth /></button>
|
||||
<button type='button' title={intl.formatMessage(muted ? messages.unmute : messages.mute)} aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} className='player-button' onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button>
|
||||
<button type='button' title={intl.formatMessage(paused ? messages.play : messages.pause)} aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} className='player-button' onClick={this.togglePlay}><Icon id={paused ? "play" : "pause"} fixedWidth /></button>
|
||||
<button type='button' title={intl.formatMessage(muted ? messages.unmute : messages.mute)} aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} className='player-button' onClick={this.toggleMute}><Icon id={muted ? "volume-off" : "volume-up"} fixedWidth /></button>
|
||||
|
||||
<div className={classNames('video-player__volume', { active: this.state.hovered })} ref={this.setVolumeRef} onMouseDown={this.handleVolumeMouseDown}>
|
||||
<div className={classNames("video-player__volume", { active: this.state.hovered })} ref={this.setVolumeRef} onMouseDown={this.handleVolumeMouseDown}>
|
||||
<div className='video-player__volume__current' style={{ width: `${muted ? 0 : volume * 100}%`, backgroundColor: this._getAccentColor() }} />
|
||||
|
||||
<span
|
||||
@@ -585,7 +587,7 @@ class Audio extends PureComponent {
|
||||
<div className='video-player__buttons right'>
|
||||
{!editable && <button type='button' title={intl.formatMessage(messages.hide)} aria-label={intl.formatMessage(messages.hide)} className='player-button' onClick={this.toggleReveal}><Icon id='eye-slash' fixedWidth /></button>}
|
||||
<a title={intl.formatMessage(messages.download)} aria-label={intl.formatMessage(messages.download)} className='video-player__download__icon player-button' href={this.props.src} download>
|
||||
<Icon id={'download'} fixedWidth />
|
||||
<Icon id={"download"} fixedWidth />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -22,7 +22,7 @@ export default class Visualizer {
|
||||
setCanvas(canvas) {
|
||||
this.canvas = canvas;
|
||||
if (canvas) {
|
||||
this.context = canvas.getContext('2d');
|
||||
this.context = canvas.getContext("2d");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { debounce } from 'lodash';
|
||||
import { debounce } from "lodash";
|
||||
|
||||
import { fetchBlocks, expandBlocks } from 'flavours/glitch/actions/blocks';
|
||||
import ColumnBackButtonSlim from 'flavours/glitch/components/column_back_button_slim';
|
||||
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||
import AccountContainer from 'flavours/glitch/containers/account_container';
|
||||
import Column from 'flavours/glitch/features/ui/components/column';
|
||||
import { fetchBlocks, expandBlocks } from "flavours/glitch/actions/blocks";
|
||||
import ColumnBackButtonSlim from "flavours/glitch/components/column_back_button_slim";
|
||||
import { LoadingIndicator } from "flavours/glitch/components/loading_indicator";
|
||||
import AccountContainer from "flavours/glitch/containers/account_container";
|
||||
import Column from "flavours/glitch/features/ui/components/column";
|
||||
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import ScrollableList from "../../components/scrollable_list";
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.blocks', defaultMessage: 'Blocked users' },
|
||||
heading: { id: "column.blocks", defaultMessage: "Blocked users" },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
accountIds: state.getIn(['user_lists', 'blocks', 'items']),
|
||||
hasMore: !!state.getIn(['user_lists', 'blocks', 'next']),
|
||||
isLoading: state.getIn(['user_lists', 'blocks', 'isLoading'], true),
|
||||
accountIds: state.getIn(["user_lists", "blocks", "items"]),
|
||||
hasMore: !!state.getIn(["user_lists", "blocks", "next"]),
|
||||
isLoading: state.getIn(["user_lists", "blocks", "isLoading"], true),
|
||||
});
|
||||
|
||||
class Blocks extends ImmutablePureComponent {
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Helmet } from "react-helmet";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { debounce } from 'lodash';
|
||||
import { debounce } from "lodash";
|
||||
|
||||
import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from 'flavours/glitch/actions/bookmarks';
|
||||
import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
|
||||
import ColumnHeader from 'flavours/glitch/components/column_header';
|
||||
import StatusList from 'flavours/glitch/components/status_list';
|
||||
import Column from 'flavours/glitch/features/ui/components/column';
|
||||
import { getStatusList } from 'flavours/glitch/selectors';
|
||||
import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from "flavours/glitch/actions/bookmarks";
|
||||
import { addColumn, removeColumn, moveColumn } from "flavours/glitch/actions/columns";
|
||||
import ColumnHeader from "flavours/glitch/components/column_header";
|
||||
import StatusList from "flavours/glitch/components/status_list";
|
||||
import Column from "flavours/glitch/features/ui/components/column";
|
||||
import { getStatusList } from "flavours/glitch/selectors";
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' },
|
||||
heading: { id: "column.bookmarks", defaultMessage: "Bookmarks" },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
statusIds: getStatusList(state, 'bookmarks'),
|
||||
isLoading: state.getIn(['status_lists', 'bookmarks', 'isLoading'], true),
|
||||
hasMore: !!state.getIn(['status_lists', 'bookmarks', 'next']),
|
||||
statusIds: getStatusList(state, "bookmarks"),
|
||||
isLoading: state.getIn(["status_lists", "bookmarks", "isLoading"], true),
|
||||
hasMore: !!state.getIn(["status_lists", "bookmarks", "next"]),
|
||||
});
|
||||
|
||||
class Bookmarks extends ImmutablePureComponent {
|
||||
@@ -49,7 +49,7 @@ class Bookmarks extends ImmutablePureComponent {
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('BOOKMARKS', {}));
|
||||
dispatch(addColumn("BOOKMARKS", {}));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { fetchServer } from 'flavours/glitch/actions/server';
|
||||
import { domain } from 'flavours/glitch/initial_state';
|
||||
import { fetchServer } from "flavours/glitch/actions/server";
|
||||
import { domain } from "flavours/glitch/initial_state";
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
message: state.getIn(['server', 'server', 'registrations', 'message']),
|
||||
message: state.getIn(["server", "server", "registrations", "message"]),
|
||||
});
|
||||
|
||||
class ClosedRegistrationsModal extends ImmutablePureComponent {
|
||||
|
||||
+10
-10
@@ -1,16 +1,16 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
|
||||
import SettingText from 'flavours/glitch/components/setting_text';
|
||||
import SettingToggle from 'flavours/glitch/features/notifications/components/setting_toggle';
|
||||
import SettingText from "flavours/glitch/components/setting_text";
|
||||
import SettingToggle from "flavours/glitch/features/notifications/components/setting_toggle";
|
||||
|
||||
const messages = defineMessages({
|
||||
filter_regex: { id: 'home.column_settings.filter_regex', defaultMessage: 'Filter out by regular expressions' },
|
||||
settings: { id: 'home.settings', defaultMessage: 'Column settings' },
|
||||
filter_regex: { id: "home.column_settings.filter_regex", defaultMessage: "Filter out by regular expressions" },
|
||||
settings: { id: "home.settings", defaultMessage: "Column settings" },
|
||||
});
|
||||
|
||||
class ColumnSettings extends PureComponent {
|
||||
@@ -28,13 +28,13 @@ class ColumnSettings extends PureComponent {
|
||||
return (
|
||||
<div>
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle settings={settings} settingPath={['other', 'onlyMedia']} onChange={onChange} label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media only' />} />
|
||||
<SettingToggle settings={settings} settingPath={["other", "onlyMedia"]} onChange={onChange} label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media only' />} />
|
||||
</div>
|
||||
|
||||
<span className='column-settings__section'><FormattedMessage id='home.column_settings.advanced' defaultMessage='Advanced' /></span>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingText settings={settings} settingPath={['regex', 'body']} onChange={onChange} label={intl.formatMessage(messages.filter_regex)} />
|
||||
<SettingText settings={settings} settingPath={["regex", "body"]} onChange={onChange} label={intl.formatMessage(messages.filter_regex)} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
+8
-8
@@ -1,17 +1,17 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { changeColumnParams } from 'flavours/glitch/actions/columns';
|
||||
import { changeSetting } from 'flavours/glitch/actions/settings';
|
||||
import { changeColumnParams } from "flavours/glitch/actions/columns";
|
||||
import { changeSetting } from "flavours/glitch/actions/settings";
|
||||
|
||||
import ColumnSettings from '../components/column_settings';
|
||||
import ColumnSettings from "../components/column_settings";
|
||||
|
||||
const mapStateToProps = (state, { columnId }) => {
|
||||
const uuid = columnId;
|
||||
const columns = state.getIn(['settings', 'columns']);
|
||||
const index = columns.findIndex(c => c.get('uuid') === uuid);
|
||||
const columns = state.getIn(["settings", "columns"]);
|
||||
const index = columns.findIndex(c => c.get("uuid") === uuid);
|
||||
|
||||
return {
|
||||
settings: (uuid && index >= 0) ? columns.get(index).get('params') : state.getIn(['settings', 'community']),
|
||||
settings: (uuid && index >= 0) ? columns.get(index).get("params") : state.getIn(["settings", "community"]),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ const mapDispatchToProps = (dispatch, { columnId }) => {
|
||||
if (columnId) {
|
||||
dispatch(changeColumnParams(columnId, key, checked));
|
||||
} else {
|
||||
dispatch(changeSetting(['community', ...key], checked));
|
||||
dispatch(changeSetting(["community", ...key], checked));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Helmet } from "react-helmet";
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
|
||||
import { connectCommunityStream } from 'flavours/glitch/actions/streaming';
|
||||
import { expandCommunityTimeline } from 'flavours/glitch/actions/timelines';
|
||||
import Column from 'flavours/glitch/components/column';
|
||||
import ColumnHeader from 'flavours/glitch/components/column_header';
|
||||
import { DismissableBanner } from 'flavours/glitch/components/dismissable_banner';
|
||||
import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
|
||||
import { domain } from 'flavours/glitch/initial_state';
|
||||
import { addColumn, removeColumn, moveColumn } from "flavours/glitch/actions/columns";
|
||||
import { connectCommunityStream } from "flavours/glitch/actions/streaming";
|
||||
import { expandCommunityTimeline } from "flavours/glitch/actions/timelines";
|
||||
import Column from "flavours/glitch/components/column";
|
||||
import ColumnHeader from "flavours/glitch/components/column_header";
|
||||
import { DismissableBanner } from "flavours/glitch/components/dismissable_banner";
|
||||
import StatusListContainer from "flavours/glitch/features/ui/containers/status_list_container";
|
||||
import { domain } from "flavours/glitch/initial_state";
|
||||
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
import ColumnSettingsContainer from "./containers/column_settings_container";
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.community', defaultMessage: 'Local timeline' },
|
||||
title: { id: "column.community", defaultMessage: "Local timeline" },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, { columnId }) => {
|
||||
const uuid = columnId;
|
||||
const columns = state.getIn(['settings', 'columns']);
|
||||
const index = columns.findIndex(c => c.get('uuid') === uuid);
|
||||
const onlyMedia = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'onlyMedia']) : state.getIn(['settings', 'community', 'other', 'onlyMedia']);
|
||||
const regex = (columnId && index >= 0) ? columns.get(index).getIn(['params', 'regex', 'body']) : state.getIn(['settings', 'community', 'regex', 'body']);
|
||||
const timelineState = state.getIn(['timelines', `community${onlyMedia ? ':media' : ''}`]);
|
||||
const columns = state.getIn(["settings", "columns"]);
|
||||
const index = columns.findIndex(c => c.get("uuid") === uuid);
|
||||
const onlyMedia = (columnId && index >= 0) ? columns.get(index).getIn(["params", "other", "onlyMedia"]) : state.getIn(["settings", "community", "other", "onlyMedia"]);
|
||||
const regex = (columnId && index >= 0) ? columns.get(index).getIn(["params", "regex", "body"]) : state.getIn(["settings", "community", "regex", "body"]);
|
||||
const timelineState = state.getIn(["timelines", `community${onlyMedia ? ":media" : ""}`]);
|
||||
|
||||
return {
|
||||
hasUnread: !!timelineState && timelineState.get('unread') > 0,
|
||||
hasUnread: !!timelineState && timelineState.get("unread") > 0,
|
||||
onlyMedia,
|
||||
regex,
|
||||
};
|
||||
@@ -64,7 +64,7 @@ class CommunityTimeline extends PureComponent {
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('COMMUNITY', { other: { onlyMedia } }));
|
||||
dispatch(addColumn("COMMUNITY", { other: { onlyMedia } }));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -146,7 +146,7 @@ class CommunityTimeline extends PureComponent {
|
||||
prepend={<DismissableBanner id='community_timeline'><FormattedMessage id='dismissable_banner.community_timeline' defaultMessage='These are the most recent public posts from people whose accounts are hosted by {domain}.' values={{ domain }} /></DismissableBanner>}
|
||||
trackScroll={!pinned}
|
||||
scrollKey={`community_timeline-${columnId}`}
|
||||
timelineId={`community${onlyMedia ? ':media' : ''}`}
|
||||
timelineId={`community${onlyMedia ? ":media" : ""}`}
|
||||
onLoadMore={this.handleLoadMore}
|
||||
emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
|
||||
bindToDocument={!multiColumn}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
|
||||
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
|
||||
import DropdownMenuContainer from "../../../containers/dropdown_menu_container";
|
||||
|
||||
const messages = defineMessages({
|
||||
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
|
||||
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' },
|
||||
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
|
||||
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
|
||||
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favorites' },
|
||||
lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
|
||||
followed_tags: { id: 'navigation_bar.followed_tags', defaultMessage: 'Followed hashtags' },
|
||||
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
|
||||
domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Blocked domains' },
|
||||
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
|
||||
filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' },
|
||||
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
|
||||
bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' },
|
||||
edit_profile: { id: "account.edit_profile", defaultMessage: "Edit profile" },
|
||||
pins: { id: "navigation_bar.pins", defaultMessage: "Pinned posts" },
|
||||
preferences: { id: "navigation_bar.preferences", defaultMessage: "Preferences" },
|
||||
follow_requests: { id: "navigation_bar.follow_requests", defaultMessage: "Follow requests" },
|
||||
favourites: { id: "navigation_bar.favourites", defaultMessage: "Favorites" },
|
||||
lists: { id: "navigation_bar.lists", defaultMessage: "Lists" },
|
||||
followed_tags: { id: "navigation_bar.followed_tags", defaultMessage: "Followed hashtags" },
|
||||
blocks: { id: "navigation_bar.blocks", defaultMessage: "Blocked users" },
|
||||
domain_blocks: { id: "navigation_bar.domain_blocks", defaultMessage: "Blocked domains" },
|
||||
mutes: { id: "navigation_bar.mutes", defaultMessage: "Muted users" },
|
||||
filters: { id: "navigation_bar.filters", defaultMessage: "Muted words" },
|
||||
logout: { id: "navigation_bar.logout", defaultMessage: "Logout" },
|
||||
bookmarks: { id: "navigation_bar.bookmarks", defaultMessage: "Bookmarks" },
|
||||
});
|
||||
|
||||
class ActionBar extends PureComponent {
|
||||
@@ -40,18 +40,18 @@ class ActionBar extends PureComponent {
|
||||
|
||||
let menu = [];
|
||||
|
||||
menu.push({ text: intl.formatMessage(messages.pins), to: '/pinned' });
|
||||
menu.push({ text: intl.formatMessage(messages.pins), to: "/pinned" });
|
||||
menu.push(null);
|
||||
menu.push({ text: intl.formatMessage(messages.follow_requests), to: '/follow_requests' });
|
||||
menu.push({ text: intl.formatMessage(messages.favourites), to: '/favourites' });
|
||||
menu.push({ text: intl.formatMessage(messages.bookmarks), to: '/bookmarks' });
|
||||
menu.push({ text: intl.formatMessage(messages.lists), to: '/lists' });
|
||||
menu.push({ text: intl.formatMessage(messages.followed_tags), to: '/followed_tags' });
|
||||
menu.push({ text: intl.formatMessage(messages.follow_requests), to: "/follow_requests" });
|
||||
menu.push({ text: intl.formatMessage(messages.favourites), to: "/favourites" });
|
||||
menu.push({ text: intl.formatMessage(messages.bookmarks), to: "/bookmarks" });
|
||||
menu.push({ text: intl.formatMessage(messages.lists), to: "/lists" });
|
||||
menu.push({ text: intl.formatMessage(messages.followed_tags), to: "/followed_tags" });
|
||||
menu.push(null);
|
||||
menu.push({ text: intl.formatMessage(messages.mutes), to: '/mutes' });
|
||||
menu.push({ text: intl.formatMessage(messages.blocks), to: '/blocks' });
|
||||
menu.push({ text: intl.formatMessage(messages.domain_blocks), to: '/domain_blocks' });
|
||||
menu.push({ text: intl.formatMessage(messages.filters), href: '/filters' });
|
||||
menu.push({ text: intl.formatMessage(messages.mutes), to: "/mutes" });
|
||||
menu.push({ text: intl.formatMessage(messages.blocks), to: "/blocks" });
|
||||
menu.push({ text: intl.formatMessage(messages.domain_blocks), to: "/domain_blocks" });
|
||||
menu.push({ text: intl.formatMessage(messages.filters), href: "/filters" });
|
||||
menu.push(null);
|
||||
menu.push({ text: intl.formatMessage(messages.logout), action: this.handleLogout });
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||
import { DisplayName } from 'flavours/glitch/components/display_name';
|
||||
import { Avatar } from "flavours/glitch/components/avatar";
|
||||
import { DisplayName } from "flavours/glitch/components/display_name";
|
||||
|
||||
export default class AutosuggestAccount extends ImmutablePureComponent {
|
||||
|
||||
@@ -14,7 +14,7 @@ export default class AutosuggestAccount extends ImmutablePureComponent {
|
||||
const { account } = this.props;
|
||||
|
||||
return (
|
||||
<div className='account small' title={account.get('acct')}>
|
||||
<div className='account small' title={account.get("acct")}>
|
||||
<div className='account__avatar-wrapper'><Avatar account={account} size={24} /></div>
|
||||
<DisplayName account={account} inline />
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { length } from 'stringz';
|
||||
import { length } from "stringz";
|
||||
|
||||
export default class CharacterCounter extends PureComponent {
|
||||
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import { length } from 'stringz';
|
||||
import { length } from "stringz";
|
||||
|
||||
import { maxChars } from 'flavours/glitch/initial_state';
|
||||
import { isMobile } from 'flavours/glitch/is_mobile';
|
||||
import { maxChars } from "flavours/glitch/initial_state";
|
||||
import { isMobile } from "flavours/glitch/is_mobile";
|
||||
|
||||
import AutosuggestInput from '../../../components/autosuggest_input';
|
||||
import AutosuggestTextarea from '../../../components/autosuggest_textarea';
|
||||
import EmojiPickerDropdown from '../containers/emoji_picker_dropdown_container';
|
||||
import OptionsContainer from '../containers/options_container';
|
||||
import PollFormContainer from '../containers/poll_form_container';
|
||||
import ReplyIndicatorContainer from '../containers/reply_indicator_container';
|
||||
import UploadFormContainer from '../containers/upload_form_container';
|
||||
import WarningContainer from '../containers/warning_container';
|
||||
import { countableText } from '../util/counter';
|
||||
import AutosuggestInput from "../../../components/autosuggest_input";
|
||||
import AutosuggestTextarea from "../../../components/autosuggest_textarea";
|
||||
import EmojiPickerDropdown from "../containers/emoji_picker_dropdown_container";
|
||||
import OptionsContainer from "../containers/options_container";
|
||||
import PollFormContainer from "../containers/poll_form_container";
|
||||
import ReplyIndicatorContainer from "../containers/reply_indicator_container";
|
||||
import UploadFormContainer from "../containers/upload_form_container";
|
||||
import WarningContainer from "../containers/warning_container";
|
||||
import { countableText } from "../util/counter";
|
||||
|
||||
import CharacterCounter from './character_counter';
|
||||
import Publisher from './publisher';
|
||||
import TextareaIcons from './textarea_icons';
|
||||
import CharacterCounter from "./character_counter";
|
||||
import Publisher from "./publisher";
|
||||
import TextareaIcons from "./textarea_icons";
|
||||
|
||||
const messages = defineMessages({
|
||||
placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' },
|
||||
placeholder: { id: "compose_form.placeholder", defaultMessage: "What is on your mind?" },
|
||||
missingDescriptionMessage: {
|
||||
id: 'confirmations.missing_media_description.message',
|
||||
defaultMessage: 'At least one media attachment is lacking a description. Consider describing all media attachments for the visually impaired before sending your toot.',
|
||||
id: "confirmations.missing_media_description.message",
|
||||
defaultMessage: "At least one media attachment is lacking a description. Consider describing all media attachments for the visually impaired before sending your toot.",
|
||||
},
|
||||
missingDescriptionConfirm: {
|
||||
id: 'confirmations.missing_media_description.confirm',
|
||||
defaultMessage: 'Send anyway',
|
||||
id: "confirmations.missing_media_description.confirm",
|
||||
defaultMessage: "Send anyway",
|
||||
},
|
||||
spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: '(Optional) post title / content warning' },
|
||||
spoiler_placeholder: { id: "compose_form.spoiler_placeholder", defaultMessage: "(Optional) post title / content warning" },
|
||||
});
|
||||
|
||||
class ComposeForm extends ImmutablePureComponent {
|
||||
@@ -94,9 +94,9 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
|
||||
getFulltextForCharacterCounting = () => {
|
||||
return [
|
||||
this.props.spoiler? this.props.spoilerText: '',
|
||||
this.props.spoiler? this.props.spoilerText: "",
|
||||
countableText(this.props.text),
|
||||
].join('');
|
||||
].join("");
|
||||
};
|
||||
|
||||
canSubmit = () => {
|
||||
@@ -126,9 +126,9 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
// Submit unless there are media with missing descriptions
|
||||
if (mediaDescriptionConfirmation && onMediaDescriptionConfirm && media && media.some(item => !item.get('description'))) {
|
||||
const firstWithoutDescription = media.find(item => !item.get('description'));
|
||||
onMediaDescriptionConfirm(this.context.router ? this.context.router.history : null, firstWithoutDescription.get('id'), overriddenVisibility);
|
||||
if (mediaDescriptionConfirmation && onMediaDescriptionConfirm && media && media.some(item => !item.get("description"))) {
|
||||
const firstWithoutDescription = media.find(item => !item.get("description"));
|
||||
onMediaDescriptionConfirm(this.context.router ? this.context.router.history : null, firstWithoutDescription.get("id"), overriddenVisibility);
|
||||
} else if (onSubmit) {
|
||||
if (onChangeVisibility && overriddenVisibility) {
|
||||
onChangeVisibility(overriddenVisibility);
|
||||
@@ -163,16 +163,16 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
const {
|
||||
sideArm,
|
||||
} = this.props;
|
||||
this.handleSubmit(sideArm === 'none' ? null : sideArm);
|
||||
this.handleSubmit(sideArm === "none" ? null : sideArm);
|
||||
};
|
||||
|
||||
// Selects a suggestion from the autofill.
|
||||
handleSuggestionSelected = (tokenStart, token, value) => {
|
||||
this.props.onSuggestionSelected(tokenStart, token, value, ['text']);
|
||||
this.props.onSuggestionSelected(tokenStart, token, value, ["text"]);
|
||||
};
|
||||
|
||||
handleSpoilerSuggestionSelected = (tokenStart, token, value) => {
|
||||
this.props.onSuggestionSelected(tokenStart, token, value, ['spoiler_text']);
|
||||
this.props.onSuggestionSelected(tokenStart, token, value, ["spoiler_text"]);
|
||||
};
|
||||
|
||||
handleKeyDown = (e) => {
|
||||
@@ -242,15 +242,15 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
// Caret/selection handling.
|
||||
if (focusDate !== prevProps.focusDate) {
|
||||
switch (true) {
|
||||
case preselectDate !== prevProps.preselectDate && this.props.isInReply && preselectOnReply:
|
||||
selectionStart = text.search(/\s/) + 1;
|
||||
selectionEnd = text.length;
|
||||
break;
|
||||
case !isNaN(caretPosition) && caretPosition !== null:
|
||||
selectionStart = selectionEnd = caretPosition;
|
||||
break;
|
||||
default:
|
||||
selectionStart = selectionEnd = text.length;
|
||||
case preselectDate !== prevProps.preselectDate && this.props.isInReply && preselectOnReply:
|
||||
selectionStart = text.search(/\s/) + 1;
|
||||
selectionEnd = text.length;
|
||||
break;
|
||||
case !isNaN(caretPosition) && caretPosition !== null:
|
||||
selectionStart = selectionEnd = caretPosition;
|
||||
break;
|
||||
default:
|
||||
selectionStart = selectionEnd = text.length;
|
||||
}
|
||||
if (textarea) {
|
||||
// Because of the wicg-inert polyfill, the activeElement may not be
|
||||
@@ -259,7 +259,9 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
Promise.resolve().then(() => {
|
||||
textarea.setSelectionRange(selectionStart, selectionEnd);
|
||||
textarea.focus();
|
||||
if (!singleColumn) textarea.scrollIntoView();
|
||||
if (!singleColumn) {
|
||||
textarea.scrollIntoView();
|
||||
}
|
||||
}).catch(console.error);
|
||||
}
|
||||
|
||||
@@ -314,7 +316,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
|
||||
<ReplyIndicatorContainer />
|
||||
|
||||
<div className={`spoiler-input ${spoiler ? 'spoiler-input--visible' : ''}`} ref={this.setRef} aria-hidden={!this.props.spoiler}>
|
||||
<div className={`spoiler-input ${spoiler ? "spoiler-input--visible" : ""}`} ref={this.setRef} aria-hidden={!this.props.spoiler}>
|
||||
<AutosuggestInput
|
||||
placeholder={intl.formatMessage(messages.spoiler_placeholder)}
|
||||
value={spoilerText}
|
||||
@@ -326,7 +328,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
onSuggestionsFetchRequested={onFetchSuggestions}
|
||||
onSuggestionsClearRequested={onClearSuggestions}
|
||||
onSuggestionSelected={this.handleSpoilerSuggestionSelected}
|
||||
searchTokens={[':']}
|
||||
searchTokens={[":"]}
|
||||
id='glitch.composer.spoiler.input'
|
||||
className='spoiler-input__input'
|
||||
lang={this.props.lang}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
// Package imports.
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import Overlay from 'react-overlays/Overlay';
|
||||
import Overlay from "react-overlays/Overlay";
|
||||
|
||||
// Components.
|
||||
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||
import { IconButton } from "flavours/glitch/components/icon_button";
|
||||
|
||||
import DropdownMenu from './dropdown_menu';
|
||||
import DropdownMenu from "./dropdown_menu";
|
||||
|
||||
// The component.
|
||||
export default class ComposerOptionsDropdown extends PureComponent {
|
||||
@@ -41,7 +41,7 @@ export default class ComposerOptionsDropdown extends PureComponent {
|
||||
state = {
|
||||
open: false,
|
||||
openedViaKeyboard: undefined,
|
||||
placement: 'bottom',
|
||||
placement: "bottom",
|
||||
};
|
||||
|
||||
// Toggles opening and closing the dropdown.
|
||||
@@ -62,15 +62,15 @@ export default class ComposerOptionsDropdown extends PureComponent {
|
||||
if (open && this.activeElement) {
|
||||
this.activeElement.focus({ preventScroll: true });
|
||||
}
|
||||
this.setState({ open: !open, openedViaKeyboard: type !== 'click' });
|
||||
this.setState({ open: !open, openedViaKeyboard: type !== "click" });
|
||||
}
|
||||
};
|
||||
|
||||
handleKeyDown = (e) => {
|
||||
switch (e.key) {
|
||||
case 'Escape':
|
||||
this.handleClose();
|
||||
break;
|
||||
case "Escape":
|
||||
this.handleClose();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -82,21 +82,21 @@ export default class ComposerOptionsDropdown extends PureComponent {
|
||||
|
||||
handleButtonKeyDown = (e) => {
|
||||
switch(e.key) {
|
||||
case ' ':
|
||||
case 'Enter':
|
||||
this.handleMouseDown();
|
||||
break;
|
||||
case " ":
|
||||
case "Enter":
|
||||
this.handleMouseDown();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
handleKeyPress = (e) => {
|
||||
switch(e.key) {
|
||||
case ' ':
|
||||
case 'Enter':
|
||||
this.handleToggle(e);
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
break;
|
||||
case " ":
|
||||
case "Enter":
|
||||
this.handleToggle(e);
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -115,12 +115,14 @@ export default class ComposerOptionsDropdown extends PureComponent {
|
||||
closeOnChange,
|
||||
} = this.props;
|
||||
|
||||
const i = Number(e.currentTarget.getAttribute('data-index'));
|
||||
const i = Number(e.currentTarget.getAttribute("data-index"));
|
||||
|
||||
const { name } = items[i];
|
||||
|
||||
e.preventDefault(); // Prevents focus from changing
|
||||
if (closeOnChange) onModalClose();
|
||||
if (closeOnChange) {
|
||||
onModalClose();
|
||||
}
|
||||
onChange(name);
|
||||
};
|
||||
|
||||
@@ -183,15 +185,15 @@ export default class ComposerOptionsDropdown extends PureComponent {
|
||||
} = this.props;
|
||||
const { open, placement } = this.state;
|
||||
|
||||
const active = value && items.findIndex(({ name }) => name === value) === (placement === 'bottom' ? 0 : (items.length - 1));
|
||||
const active = value && items.findIndex(({ name }) => name === value) === (placement === "bottom" ? 0 : (items.length - 1));
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames('privacy-dropdown', placement, { active: open })}
|
||||
className={classNames("privacy-dropdown", placement, { active: open })}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
ref={this.setTargetRef}
|
||||
>
|
||||
<div className={classNames('privacy-dropdown__value', { active })}>
|
||||
<div className={classNames("privacy-dropdown__value", { active })}>
|
||||
<IconButton
|
||||
active={open}
|
||||
className='privacy-dropdown__value-icon'
|
||||
@@ -205,7 +207,7 @@ export default class ComposerOptionsDropdown extends PureComponent {
|
||||
size={18}
|
||||
style={{
|
||||
height: null,
|
||||
lineHeight: '27px',
|
||||
lineHeight: "27px",
|
||||
}}
|
||||
title={title}
|
||||
/>
|
||||
@@ -218,7 +220,7 @@ export default class ComposerOptionsDropdown extends PureComponent {
|
||||
flip
|
||||
target={this.findTarget}
|
||||
container={container}
|
||||
popperConfig={{ strategy: 'fixed', onFirstUpdate: this.handleOverlayEnter }}
|
||||
popperConfig={{ strategy: "fixed", onFirstUpdate: this.handleOverlayEnter }}
|
||||
>
|
||||
{({ props, placement }) => (
|
||||
<div {...props}>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// Package imports.
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||
import { supportsPassiveEvents } from "detect-passive-events";
|
||||
|
||||
// Components.
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
|
||||
const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
|
||||
|
||||
@@ -54,8 +54,8 @@ export default class ComposerOptionsDropdownContent extends PureComponent {
|
||||
|
||||
// On mounting, we add our listeners.
|
||||
componentDidMount () {
|
||||
document.addEventListener('click', this.handleDocumentClick, { capture: true });
|
||||
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
document.addEventListener("click", this.handleDocumentClick, { capture: true });
|
||||
document.addEventListener("touchend", this.handleDocumentClick, listenerOptions);
|
||||
if (this.focusedItem) {
|
||||
this.focusedItem.focus({ preventScroll: true });
|
||||
} else {
|
||||
@@ -65,12 +65,12 @@ export default class ComposerOptionsDropdownContent extends PureComponent {
|
||||
|
||||
// On unmounting, we remove our listeners.
|
||||
componentWillUnmount () {
|
||||
document.removeEventListener('click', this.handleDocumentClick, { capture: true });
|
||||
document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
document.removeEventListener("click", this.handleDocumentClick, { capture: true });
|
||||
document.removeEventListener("touchend", this.handleDocumentClick, listenerOptions);
|
||||
}
|
||||
|
||||
handleClick = (e) => {
|
||||
const i = Number(e.currentTarget.getAttribute('data-index'));
|
||||
const i = Number(e.currentTarget.getAttribute("data-index"));
|
||||
|
||||
const {
|
||||
onChange,
|
||||
@@ -98,42 +98,42 @@ export default class ComposerOptionsDropdownContent extends PureComponent {
|
||||
};
|
||||
|
||||
handleKeyDown = (e) => {
|
||||
const index = Number(e.currentTarget.getAttribute('data-index'));
|
||||
const index = Number(e.currentTarget.getAttribute("data-index"));
|
||||
const { items } = this.props;
|
||||
let element = null;
|
||||
|
||||
switch(e.key) {
|
||||
case 'Escape':
|
||||
this.props.onClose();
|
||||
break;
|
||||
case 'Enter':
|
||||
case ' ':
|
||||
this.handleClick(e);
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
element = this.node.childNodes[index + 1] || this.node.firstChild;
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
element = this.node.childNodes[index - 1] || this.node.lastChild;
|
||||
break;
|
||||
case 'Tab':
|
||||
if (e.shiftKey) {
|
||||
element = this.node.childNodes[index - 1] || this.node.lastChild;
|
||||
} else {
|
||||
case "Escape":
|
||||
this.props.onClose();
|
||||
break;
|
||||
case "Enter":
|
||||
case " ":
|
||||
this.handleClick(e);
|
||||
break;
|
||||
case "ArrowDown":
|
||||
element = this.node.childNodes[index + 1] || this.node.firstChild;
|
||||
}
|
||||
break;
|
||||
case 'Home':
|
||||
element = this.node.firstChild;
|
||||
break;
|
||||
case 'End':
|
||||
element = this.node.lastChild;
|
||||
break;
|
||||
break;
|
||||
case "ArrowUp":
|
||||
element = this.node.childNodes[index - 1] || this.node.lastChild;
|
||||
break;
|
||||
case "Tab":
|
||||
if (e.shiftKey) {
|
||||
element = this.node.childNodes[index - 1] || this.node.lastChild;
|
||||
} else {
|
||||
element = this.node.childNodes[index + 1] || this.node.firstChild;
|
||||
}
|
||||
break;
|
||||
case "Home":
|
||||
element = this.node.firstChild;
|
||||
break;
|
||||
case "End":
|
||||
element = this.node.lastChild;
|
||||
break;
|
||||
}
|
||||
|
||||
if (element) {
|
||||
element.focus();
|
||||
this.handleChange(items[Number(element.getAttribute('data-index'))].name);
|
||||
this.handleChange(items[Number(element.getAttribute("data-index"))].name);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
@@ -148,7 +148,7 @@ export default class ComposerOptionsDropdownContent extends PureComponent {
|
||||
|
||||
const active = (name === (this.props.value || this.state.value));
|
||||
|
||||
const computedClass = classNames('privacy-dropdown__option', { active });
|
||||
const computedClass = classNames("privacy-dropdown__option", { active });
|
||||
|
||||
let contents = this.props.renderItemContents && this.props.renderItemContents(item, i);
|
||||
|
||||
|
||||
+52
-50
@@ -1,35 +1,35 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
|
||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||
import Overlay from 'react-overlays/Overlay';
|
||||
import { supportsPassiveEvents } from "detect-passive-events";
|
||||
import Overlay from "react-overlays/Overlay";
|
||||
|
||||
import { useSystemEmojiFont } from 'flavours/glitch/initial_state';
|
||||
import { assetHost } from 'flavours/glitch/utils/config';
|
||||
import { useSystemEmojiFont } from "flavours/glitch/initial_state";
|
||||
import { assetHost } from "flavours/glitch/utils/config";
|
||||
|
||||
import { buildCustomEmojis, categoriesFromEmojis } from '../../emoji/emoji';
|
||||
import { EmojiPicker as EmojiPickerAsync } from '../../ui/util/async-components';
|
||||
import { buildCustomEmojis, categoriesFromEmojis } from "../../emoji/emoji";
|
||||
import { EmojiPicker as EmojiPickerAsync } from "../../ui/util/async-components";
|
||||
|
||||
const messages = defineMessages({
|
||||
emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' },
|
||||
emoji_search: { id: 'emoji_button.search', defaultMessage: 'Search...' },
|
||||
custom: { id: 'emoji_button.custom', defaultMessage: 'Custom' },
|
||||
recent: { id: 'emoji_button.recent', defaultMessage: 'Frequently used' },
|
||||
search_results: { id: 'emoji_button.search_results', defaultMessage: 'Search results' },
|
||||
people: { id: 'emoji_button.people', defaultMessage: 'People' },
|
||||
nature: { id: 'emoji_button.nature', defaultMessage: 'Nature' },
|
||||
food: { id: 'emoji_button.food', defaultMessage: 'Food & Drink' },
|
||||
activity: { id: 'emoji_button.activity', defaultMessage: 'Activity' },
|
||||
travel: { id: 'emoji_button.travel', defaultMessage: 'Travel & Places' },
|
||||
objects: { id: 'emoji_button.objects', defaultMessage: 'Objects' },
|
||||
symbols: { id: 'emoji_button.symbols', defaultMessage: 'Symbols' },
|
||||
flags: { id: 'emoji_button.flags', defaultMessage: 'Flags' },
|
||||
emoji: { id: "emoji_button.label", defaultMessage: "Insert emoji" },
|
||||
emoji_search: { id: "emoji_button.search", defaultMessage: "Search..." },
|
||||
custom: { id: "emoji_button.custom", defaultMessage: "Custom" },
|
||||
recent: { id: "emoji_button.recent", defaultMessage: "Frequently used" },
|
||||
search_results: { id: "emoji_button.search_results", defaultMessage: "Search results" },
|
||||
people: { id: "emoji_button.people", defaultMessage: "People" },
|
||||
nature: { id: "emoji_button.nature", defaultMessage: "Nature" },
|
||||
food: { id: "emoji_button.food", defaultMessage: "Food & Drink" },
|
||||
activity: { id: "emoji_button.activity", defaultMessage: "Activity" },
|
||||
travel: { id: "emoji_button.travel", defaultMessage: "Travel & Places" },
|
||||
objects: { id: "emoji_button.objects", defaultMessage: "Objects" },
|
||||
symbols: { id: "emoji_button.symbols", defaultMessage: "Symbols" },
|
||||
flags: { id: "emoji_button.flags", defaultMessage: "Flags" },
|
||||
});
|
||||
|
||||
let EmojiPicker, Emoji; // load asynchronously
|
||||
@@ -63,7 +63,7 @@ class ModifierPickerMenu extends PureComponent {
|
||||
};
|
||||
|
||||
handleClick = e => {
|
||||
this.props.onSelect(e.currentTarget.getAttribute('data-index') * 1);
|
||||
this.props.onSelect(e.currentTarget.getAttribute("data-index") * 1);
|
||||
};
|
||||
|
||||
UNSAFE_componentWillReceiveProps (nextProps) {
|
||||
@@ -85,13 +85,13 @@ class ModifierPickerMenu extends PureComponent {
|
||||
};
|
||||
|
||||
attachListeners () {
|
||||
document.addEventListener('click', this.handleDocumentClick, { capture: true });
|
||||
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
document.addEventListener("click", this.handleDocumentClick, { capture: true });
|
||||
document.addEventListener("touchend", this.handleDocumentClick, listenerOptions);
|
||||
}
|
||||
|
||||
removeListeners () {
|
||||
document.removeEventListener('click', this.handleDocumentClick, { capture: true });
|
||||
document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
document.removeEventListener("click", this.handleDocumentClick, { capture: true });
|
||||
document.removeEventListener("touchend", this.handleDocumentClick, listenerOptions);
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
@@ -102,7 +102,7 @@ class ModifierPickerMenu extends PureComponent {
|
||||
const { active } = this.props;
|
||||
|
||||
return (
|
||||
<div className='emoji-picker-dropdown__modifiers__menu' style={{ display: active ? 'block' : 'none' }} ref={this.setRef}>
|
||||
<div className='emoji-picker-dropdown__modifiers__menu' style={{ display: active ? "block" : "none" }} ref={this.setRef}>
|
||||
<button onClick={this.handleClick} data-index={1}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={1} backgroundImageFn={backgroundImageFn} native={useSystemEmojiFont} /></button>
|
||||
<button onClick={this.handleClick} data-index={2}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={2} backgroundImageFn={backgroundImageFn} native={useSystemEmojiFont} /></button>
|
||||
<button onClick={this.handleClick} data-index={3}><Emoji emoji='fist' set='twitter' size={22} sheetSize={32} skin={3} backgroundImageFn={backgroundImageFn} native={useSystemEmojiFont} /></button>
|
||||
@@ -183,23 +183,25 @@ class EmojiPickerMenuImpl extends PureComponent {
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
document.addEventListener('click', this.handleDocumentClick, { capture: true });
|
||||
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
document.addEventListener("click", this.handleDocumentClick, { capture: true });
|
||||
document.addEventListener("touchend", this.handleDocumentClick, listenerOptions);
|
||||
|
||||
// Because of https://github.com/react-bootstrap/react-bootstrap/issues/2614 we need
|
||||
// to wait for a frame before focusing
|
||||
requestAnimationFrame(() => {
|
||||
this.setState({ readyToFocus: true });
|
||||
if (this.node) {
|
||||
const element = this.node.querySelector('input[type="search"]');
|
||||
if (element) element.focus();
|
||||
const element = this.node.querySelector("input[type=\"search\"]");
|
||||
if (element) {
|
||||
element.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
document.removeEventListener('click', this.handleDocumentClick, { capture: true });
|
||||
document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
document.removeEventListener("click", this.handleDocumentClick, { capture: true });
|
||||
document.removeEventListener("touchend", this.handleDocumentClick, listenerOptions);
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
@@ -261,21 +263,21 @@ class EmojiPickerMenuImpl extends PureComponent {
|
||||
const { modifierOpen } = this.state;
|
||||
|
||||
const categoriesSort = [
|
||||
'recent',
|
||||
'people',
|
||||
'nature',
|
||||
'foods',
|
||||
'activity',
|
||||
'places',
|
||||
'objects',
|
||||
'symbols',
|
||||
'flags',
|
||||
"recent",
|
||||
"people",
|
||||
"nature",
|
||||
"foods",
|
||||
"activity",
|
||||
"places",
|
||||
"objects",
|
||||
"symbols",
|
||||
"flags",
|
||||
];
|
||||
|
||||
categoriesSort.splice(1, 0, ...Array.from(categoriesFromEmojis(custom_emojis)).sort());
|
||||
|
||||
return (
|
||||
<div className={classNames('emoji-picker-dropdown__menu', { selecting: modifierOpen })} style={style} ref={this.setRef}>
|
||||
<div className={classNames("emoji-picker-dropdown__menu", { selecting: modifierOpen })} style={style} ref={this.setRef}>
|
||||
<EmojiPicker
|
||||
perLine={8}
|
||||
emojiSize={22}
|
||||
@@ -357,7 +359,7 @@ class EmojiPickerDropdown extends PureComponent {
|
||||
};
|
||||
|
||||
onToggle = (e) => {
|
||||
if (!this.state.loading && (!e.key || e.key === 'Enter')) {
|
||||
if (!this.state.loading && (!e.key || e.key === "Enter")) {
|
||||
if (this.state.active) {
|
||||
this.onHideDropdown();
|
||||
} else {
|
||||
@@ -367,7 +369,7 @@ class EmojiPickerDropdown extends PureComponent {
|
||||
};
|
||||
|
||||
handleKeyDown = e => {
|
||||
if (e.key === 'Escape') {
|
||||
if (e.key === "Escape") {
|
||||
this.onHideDropdown();
|
||||
}
|
||||
};
|
||||
@@ -389,13 +391,13 @@ class EmojiPickerDropdown extends PureComponent {
|
||||
<div className='emoji-picker-dropdown' onKeyDown={this.handleKeyDown}>
|
||||
<div ref={this.setTargetRef} className='emoji-button' title={title} aria-label={title} aria-expanded={active} role='button' onClick={this.onToggle} onKeyDown={this.onToggle} tabIndex={0}>
|
||||
{button || <img
|
||||
className={classNames('emojione', { 'pulse-loading': active && loading })}
|
||||
className={classNames("emojione", { "pulse-loading": active && loading })}
|
||||
alt='🙂'
|
||||
src={`${assetHost}/emoji/1f642.svg`}
|
||||
/>}
|
||||
</div>
|
||||
|
||||
<Overlay show={active} placement={'bottom'} target={this.findTarget} popperConfig={{ strategy: 'fixed' }}>
|
||||
<Overlay show={active} placement={"bottom"} target={this.findTarget} popperConfig={{ strategy: "fixed" }}>
|
||||
{({ props, placement })=> (
|
||||
<div {...props} style={{ ...props.style, width: 299 }}>
|
||||
<div className={`dropdown-animation ${placement}`}>
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import { injectIntl, defineMessages } from "react-intl";
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { signOutLink } from 'flavours/glitch/utils/backend_links';
|
||||
import { conditionalRender } from 'flavours/glitch/utils/react_helpers';
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
import { signOutLink } from "flavours/glitch/utils/backend_links";
|
||||
import { conditionalRender } from "flavours/glitch/utils/react_helpers";
|
||||
|
||||
const messages = defineMessages({
|
||||
community: {
|
||||
defaultMessage: 'Local timeline',
|
||||
id: 'navigation_bar.community_timeline',
|
||||
defaultMessage: "Local timeline",
|
||||
id: "navigation_bar.community_timeline",
|
||||
},
|
||||
home_timeline: {
|
||||
defaultMessage: 'Home',
|
||||
id: 'tabs_bar.home',
|
||||
defaultMessage: "Home",
|
||||
id: "tabs_bar.home",
|
||||
},
|
||||
logout: {
|
||||
defaultMessage: 'Logout',
|
||||
id: 'navigation_bar.logout',
|
||||
defaultMessage: "Logout",
|
||||
id: "navigation_bar.logout",
|
||||
},
|
||||
notifications: {
|
||||
defaultMessage: 'Notifications',
|
||||
id: 'tabs_bar.notifications',
|
||||
defaultMessage: "Notifications",
|
||||
id: "tabs_bar.notifications",
|
||||
},
|
||||
public: {
|
||||
defaultMessage: 'Federated timeline',
|
||||
id: 'navigation_bar.public_timeline',
|
||||
defaultMessage: "Federated timeline",
|
||||
id: "navigation_bar.public_timeline",
|
||||
},
|
||||
settings: {
|
||||
defaultMessage: 'App settings',
|
||||
id: 'navigation_bar.app_settings',
|
||||
defaultMessage: "App settings",
|
||||
id: "navigation_bar.app_settings",
|
||||
},
|
||||
start: {
|
||||
defaultMessage: 'Getting started',
|
||||
id: 'getting_started.heading',
|
||||
defaultMessage: "Getting started",
|
||||
id: "getting_started.heading",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -68,7 +68,7 @@ class Header extends ImmutablePureComponent {
|
||||
// Only renders the component if the column isn't being shown.
|
||||
const renderForColumn = conditionalRender.bind(null,
|
||||
columnId => !columns || !columns.some(
|
||||
column => column.get('id') === columnId,
|
||||
column => column.get("id") === columnId,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -80,14 +80,14 @@ class Header extends ImmutablePureComponent {
|
||||
title={intl.formatMessage(messages.start)}
|
||||
to='/getting-started'
|
||||
><Icon id='asterisk' /></Link>
|
||||
{renderForColumn('HOME', (
|
||||
{renderForColumn("HOME", (
|
||||
<Link
|
||||
aria-label={intl.formatMessage(messages.home_timeline)}
|
||||
title={intl.formatMessage(messages.home_timeline)}
|
||||
to='/home'
|
||||
><Icon id='home' /></Link>
|
||||
))}
|
||||
{renderForColumn('NOTIFICATIONS', (
|
||||
{renderForColumn("NOTIFICATIONS", (
|
||||
<Link
|
||||
aria-label={intl.formatMessage(messages.notifications)}
|
||||
title={intl.formatMessage(messages.notifications)}
|
||||
@@ -99,14 +99,14 @@ class Header extends ImmutablePureComponent {
|
||||
</span>
|
||||
</Link>
|
||||
))}
|
||||
{renderForColumn('COMMUNITY', (
|
||||
{renderForColumn("COMMUNITY", (
|
||||
<Link
|
||||
aria-label={intl.formatMessage(messages.community)}
|
||||
title={intl.formatMessage(messages.community)}
|
||||
to='/public/local'
|
||||
><Icon id='users' /></Link>
|
||||
))}
|
||||
{renderForColumn('PUBLIC', (
|
||||
{renderForColumn("PUBLIC", (
|
||||
<Link
|
||||
aria-label={intl.formatMessage(messages.public)}
|
||||
title={intl.formatMessage(messages.public)}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import { injectIntl, defineMessages } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||
import fuzzysort from 'fuzzysort';
|
||||
import Overlay from 'react-overlays/Overlay';
|
||||
import { supportsPassiveEvents } from "detect-passive-events";
|
||||
import fuzzysort from "fuzzysort";
|
||||
import Overlay from "react-overlays/Overlay";
|
||||
|
||||
import { languages as preloadedLanguages } from 'flavours/glitch/initial_state';
|
||||
import { loupeIcon, deleteIcon } from 'flavours/glitch/utils/icons';
|
||||
import { languages as preloadedLanguages } from "flavours/glitch/initial_state";
|
||||
import { loupeIcon, deleteIcon } from "flavours/glitch/utils/icons";
|
||||
|
||||
import TextIconButton from './text_icon_button';
|
||||
import TextIconButton from "./text_icon_button";
|
||||
|
||||
const messages = defineMessages({
|
||||
changeLanguage: { id: 'compose.language.change', defaultMessage: 'Change language' },
|
||||
search: { id: 'compose.language.search', defaultMessage: 'Search languages...' },
|
||||
clear: { id: 'emoji_button.clear', defaultMessage: 'Clear' },
|
||||
changeLanguage: { id: "compose.language.change", defaultMessage: "Change language" },
|
||||
search: { id: "compose.language.search", defaultMessage: "Search languages..." },
|
||||
clear: { id: "emoji_button.clear", defaultMessage: "Clear" },
|
||||
});
|
||||
|
||||
const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
|
||||
@@ -38,7 +38,7 @@ class LanguageDropdownMenu extends PureComponent {
|
||||
};
|
||||
|
||||
state = {
|
||||
searchValue: '',
|
||||
searchValue: "",
|
||||
};
|
||||
|
||||
handleDocumentClick = e => {
|
||||
@@ -49,22 +49,24 @@ class LanguageDropdownMenu extends PureComponent {
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
document.addEventListener('click', this.handleDocumentClick, { capture: true });
|
||||
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
document.addEventListener("click", this.handleDocumentClick, { capture: true });
|
||||
document.addEventListener("touchend", this.handleDocumentClick, listenerOptions);
|
||||
|
||||
// Because of https://github.com/react-bootstrap/react-bootstrap/issues/2614 we need
|
||||
// to wait for a frame before focusing
|
||||
requestAnimationFrame(() => {
|
||||
if (this.node) {
|
||||
const element = this.node.querySelector('input[type="search"]');
|
||||
if (element) element.focus();
|
||||
const element = this.node.querySelector("input[type=\"search\"]");
|
||||
if (element) {
|
||||
element.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
document.removeEventListener('click', this.handleDocumentClick, { capture: true });
|
||||
document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
document.removeEventListener("click", this.handleDocumentClick, { capture: true });
|
||||
document.removeEventListener("touchend", this.handleDocumentClick, listenerOptions);
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
@@ -83,7 +85,7 @@ class LanguageDropdownMenu extends PureComponent {
|
||||
const { languages, value, frequentlyUsedLanguages } = this.props;
|
||||
const { searchValue } = this.state;
|
||||
|
||||
if (searchValue === '') {
|
||||
if (searchValue === "") {
|
||||
return [...languages].sort((a, b) => {
|
||||
// Push current selection to the top of the list
|
||||
|
||||
@@ -103,7 +105,7 @@ class LanguageDropdownMenu extends PureComponent {
|
||||
}
|
||||
|
||||
return fuzzysort.go(searchValue, languages, {
|
||||
keys: ['0', '1', '2'],
|
||||
keys: ["0", "1", "2"],
|
||||
limit: 5,
|
||||
threshold: -10000,
|
||||
}).map(result => result.obj);
|
||||
@@ -122,7 +124,7 @@ class LanguageDropdownMenu extends PureComponent {
|
||||
}
|
||||
|
||||
handleClick = e => {
|
||||
const value = e.currentTarget.getAttribute('data-index');
|
||||
const value = e.currentTarget.getAttribute("data-index");
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
@@ -137,31 +139,31 @@ class LanguageDropdownMenu extends PureComponent {
|
||||
let element = null;
|
||||
|
||||
switch(e.key) {
|
||||
case 'Escape':
|
||||
onClose();
|
||||
break;
|
||||
case 'Enter':
|
||||
this.handleClick(e);
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
element = this.listNode.childNodes[index + 1] || this.listNode.firstChild;
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
element = this.listNode.childNodes[index - 1] || this.listNode.lastChild;
|
||||
break;
|
||||
case 'Tab':
|
||||
if (e.shiftKey) {
|
||||
element = this.listNode.childNodes[index - 1] || this.listNode.lastChild;
|
||||
} else {
|
||||
case "Escape":
|
||||
onClose();
|
||||
break;
|
||||
case "Enter":
|
||||
this.handleClick(e);
|
||||
break;
|
||||
case "ArrowDown":
|
||||
element = this.listNode.childNodes[index + 1] || this.listNode.firstChild;
|
||||
}
|
||||
break;
|
||||
case 'Home':
|
||||
element = this.listNode.firstChild;
|
||||
break;
|
||||
case 'End':
|
||||
element = this.listNode.lastChild;
|
||||
break;
|
||||
break;
|
||||
case "ArrowUp":
|
||||
element = this.listNode.childNodes[index - 1] || this.listNode.lastChild;
|
||||
break;
|
||||
case "Tab":
|
||||
if (e.shiftKey) {
|
||||
element = this.listNode.childNodes[index - 1] || this.listNode.lastChild;
|
||||
} else {
|
||||
element = this.listNode.childNodes[index + 1] || this.listNode.firstChild;
|
||||
}
|
||||
break;
|
||||
case "Home":
|
||||
element = this.listNode.firstChild;
|
||||
break;
|
||||
case "End":
|
||||
element = this.listNode.lastChild;
|
||||
break;
|
||||
}
|
||||
|
||||
if (element) {
|
||||
@@ -178,44 +180,44 @@ class LanguageDropdownMenu extends PureComponent {
|
||||
let element = null;
|
||||
|
||||
switch(e.key) {
|
||||
case 'Tab':
|
||||
case 'ArrowDown':
|
||||
element = this.listNode.firstChild;
|
||||
case "Tab":
|
||||
case "ArrowDown":
|
||||
element = this.listNode.firstChild;
|
||||
|
||||
if (element) {
|
||||
element.focus();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
if (element) {
|
||||
element.focus();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
break;
|
||||
case 'Enter':
|
||||
element = this.listNode.firstChild;
|
||||
break;
|
||||
case "Enter":
|
||||
element = this.listNode.firstChild;
|
||||
|
||||
if (element) {
|
||||
onChange(element.getAttribute('data-index'));
|
||||
onClose();
|
||||
}
|
||||
break;
|
||||
case 'Escape':
|
||||
if (searchValue !== '') {
|
||||
e.preventDefault();
|
||||
this.handleClear();
|
||||
}
|
||||
if (element) {
|
||||
onChange(element.getAttribute("data-index"));
|
||||
onClose();
|
||||
}
|
||||
break;
|
||||
case "Escape":
|
||||
if (searchValue !== "") {
|
||||
e.preventDefault();
|
||||
this.handleClear();
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
handleClear = () => {
|
||||
this.setState({ searchValue: '' });
|
||||
this.setState({ searchValue: "" });
|
||||
};
|
||||
|
||||
renderItem = lang => {
|
||||
const { value } = this.props;
|
||||
|
||||
return (
|
||||
<div key={lang[0]} role='option' tabIndex={0} data-index={lang[0]} className={classNames('language-dropdown__dropdown__results__item', { active: lang[0] === value })} aria-selected={lang[0] === value} onClick={this.handleClick} onKeyDown={this.handleKeyDown}>
|
||||
<div key={lang[0]} role='option' tabIndex={0} data-index={lang[0]} className={classNames("language-dropdown__dropdown__results__item", { active: lang[0] === value })} aria-selected={lang[0] === value} onClick={this.handleClick} onKeyDown={this.handleKeyDown}>
|
||||
<span className='language-dropdown__dropdown__results__item__native-name' lang={lang[0]}>{lang[2]}</span> <span className='language-dropdown__dropdown__results__item__common-name'>({lang[1]})</span>
|
||||
</div>
|
||||
);
|
||||
@@ -224,7 +226,7 @@ class LanguageDropdownMenu extends PureComponent {
|
||||
render () {
|
||||
const { intl } = this.props;
|
||||
const { searchValue } = this.state;
|
||||
const isSearching = searchValue !== '';
|
||||
const isSearching = searchValue !== "";
|
||||
const results = this.search();
|
||||
|
||||
return (
|
||||
@@ -255,7 +257,7 @@ class LanguageDropdown extends PureComponent {
|
||||
|
||||
state = {
|
||||
open: false,
|
||||
placement: 'bottom',
|
||||
placement: "bottom",
|
||||
};
|
||||
|
||||
handleToggle = () => {
|
||||
@@ -299,7 +301,7 @@ class LanguageDropdown extends PureComponent {
|
||||
const { open, placement } = this.state;
|
||||
|
||||
return (
|
||||
<div className={classNames('privacy-dropdown', placement, { active: open })}>
|
||||
<div className={classNames("privacy-dropdown", placement, { active: open })}>
|
||||
<div className='privacy-dropdown__value' ref={this.setTargetRef} >
|
||||
<TextIconButton
|
||||
className='privacy-dropdown__value-icon'
|
||||
@@ -310,7 +312,7 @@ class LanguageDropdown extends PureComponent {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Overlay show={open} placement={'bottom'} flip target={this.findTarget} popperConfig={{ strategy: 'fixed', onFirstUpdate: this.handleOverlayEnter }}>
|
||||
<Overlay show={open} placement={"bottom"} flip target={this.findTarget} popperConfig={{ strategy: "fixed", onFirstUpdate: this.handleOverlayEnter }}>
|
||||
{({ props, placement }) => (
|
||||
<div {...props}>
|
||||
<div className={`dropdown-animation language-dropdown__dropdown ${placement}`} >
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||
import Permalink from 'flavours/glitch/components/permalink';
|
||||
// eslint-disable-next-line import/no-restricted-paths
|
||||
import initialState from 'mastodon/initial_state';
|
||||
import { Avatar } from "flavours/glitch/components/avatar";
|
||||
import Permalink from "flavours/glitch/components/permalink";
|
||||
|
||||
import initialState from "mastodon/initial_state";
|
||||
|
||||
import ActionBar from './action_bar';
|
||||
import ActionBar from "./action_bar";
|
||||
|
||||
export default class NavigationBar extends ImmutablePureComponent {
|
||||
|
||||
@@ -20,15 +20,15 @@ export default class NavigationBar extends ImmutablePureComponent {
|
||||
render () {
|
||||
return (
|
||||
<div className='navigation-bar'>
|
||||
<Permalink className='avatar' href={this.props.account.get('url')} to={`/@${this.props.account.get('acct')}`}>
|
||||
<span style={{ display: 'none' }}>{this.props.account.get('acct')}</span>
|
||||
<Permalink className='avatar' href={this.props.account.get("url")} to={`/@${this.props.account.get("acct")}`}>
|
||||
<span style={{ display: "none" }}>{this.props.account.get("acct")}</span>
|
||||
<Avatar account={this.props.account} size={48} />
|
||||
</Permalink>
|
||||
|
||||
<div className='navigation-bar__profile'>
|
||||
<div>{this.props.account.get('display_name')}</div>
|
||||
<Permalink className='acct' href={this.props.account.get('url')} to={`/@${this.props.account.get('acct')}`}>
|
||||
<strong>@{this.props.account.get('acct')}</strong>
|
||||
<div>{this.props.account.get("display_name")}</div>
|
||||
<Permalink className='acct' href={this.props.account.get("url")} to={`/@${this.props.account.get("acct")}`}>
|
||||
<strong>@{this.props.account.get("acct")}</strong>
|
||||
<span>@{initialState.meta.domain}</span>
|
||||
</Permalink>
|
||||
</div>
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
// Package imports.
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import Toggle from 'react-toggle';
|
||||
import Toggle from "react-toggle";
|
||||
|
||||
|
||||
// Components.
|
||||
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||
import { pollLimits } from 'flavours/glitch/initial_state';
|
||||
import { IconButton } from "flavours/glitch/components/icon_button";
|
||||
import { pollLimits } from "flavours/glitch/initial_state";
|
||||
|
||||
import DropdownContainer from '../containers/dropdown_container';
|
||||
import LanguageDropdown from '../containers/language_dropdown_container';
|
||||
import PrivacyDropdownContainer from '../containers/privacy_dropdown_container';
|
||||
import DropdownContainer from "../containers/dropdown_container";
|
||||
import LanguageDropdown from "../containers/language_dropdown_container";
|
||||
import PrivacyDropdownContainer from "../containers/privacy_dropdown_container";
|
||||
|
||||
import TextIconButton from './text_icon_button';
|
||||
import TextIconButton from "./text_icon_button";
|
||||
|
||||
|
||||
|
||||
@@ -27,69 +27,69 @@ import TextIconButton from './text_icon_button';
|
||||
// Messages.
|
||||
const messages = defineMessages({
|
||||
advanced_options_icon_title: {
|
||||
defaultMessage: 'Advanced options',
|
||||
id: 'advanced_options.icon_title',
|
||||
defaultMessage: "Advanced options",
|
||||
id: "advanced_options.icon_title",
|
||||
},
|
||||
attach: {
|
||||
defaultMessage: 'Attach...',
|
||||
id: 'compose.attach',
|
||||
defaultMessage: "Attach...",
|
||||
id: "compose.attach",
|
||||
},
|
||||
content_type: {
|
||||
defaultMessage: 'Content type',
|
||||
id: 'content-type.change',
|
||||
defaultMessage: "Content type",
|
||||
id: "content-type.change",
|
||||
},
|
||||
doodle: {
|
||||
defaultMessage: 'Draw something',
|
||||
id: 'compose.attach.doodle',
|
||||
defaultMessage: "Draw something",
|
||||
id: "compose.attach.doodle",
|
||||
},
|
||||
html: {
|
||||
defaultMessage: 'HTML',
|
||||
id: 'compose.content-type.html',
|
||||
defaultMessage: "HTML",
|
||||
id: "compose.content-type.html",
|
||||
},
|
||||
local_only_long: {
|
||||
defaultMessage: 'Do not post to other instances',
|
||||
id: 'advanced_options.local-only.long',
|
||||
defaultMessage: "Do not post to other instances",
|
||||
id: "advanced_options.local-only.long",
|
||||
},
|
||||
local_only_short: {
|
||||
defaultMessage: 'Local-only',
|
||||
id: 'advanced_options.local-only.short',
|
||||
defaultMessage: "Local-only",
|
||||
id: "advanced_options.local-only.short",
|
||||
},
|
||||
markdown: {
|
||||
defaultMessage: 'Markdown',
|
||||
id: 'compose.content-type.markdown',
|
||||
defaultMessage: "Markdown",
|
||||
id: "compose.content-type.markdown",
|
||||
},
|
||||
plain: {
|
||||
defaultMessage: 'Plain text',
|
||||
id: 'compose.content-type.plain',
|
||||
defaultMessage: "Plain text",
|
||||
id: "compose.content-type.plain",
|
||||
},
|
||||
spoiler: {
|
||||
defaultMessage: 'Hide text behind warning',
|
||||
id: 'compose_form.spoiler',
|
||||
defaultMessage: "Hide text behind warning",
|
||||
id: "compose_form.spoiler",
|
||||
},
|
||||
threaded_mode_long: {
|
||||
defaultMessage: 'Automatically opens a reply on posting',
|
||||
id: 'advanced_options.threaded_mode.long',
|
||||
defaultMessage: "Automatically opens a reply on posting",
|
||||
id: "advanced_options.threaded_mode.long",
|
||||
},
|
||||
threaded_mode_short: {
|
||||
defaultMessage: 'Threaded mode',
|
||||
id: 'advanced_options.threaded_mode.short',
|
||||
defaultMessage: "Threaded mode",
|
||||
id: "advanced_options.threaded_mode.short",
|
||||
},
|
||||
upload: {
|
||||
defaultMessage: 'Upload a file',
|
||||
id: 'compose.attach.upload',
|
||||
defaultMessage: "Upload a file",
|
||||
id: "compose.attach.upload",
|
||||
},
|
||||
add_poll: {
|
||||
defaultMessage: 'Add a poll',
|
||||
id: 'poll_button.add_poll',
|
||||
defaultMessage: "Add a poll",
|
||||
id: "poll_button.add_poll",
|
||||
},
|
||||
remove_poll: {
|
||||
defaultMessage: 'Remove poll',
|
||||
id: 'poll_button.remove_poll',
|
||||
defaultMessage: "Remove poll",
|
||||
id: "poll_button.remove_poll",
|
||||
},
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, { name }) => ({
|
||||
checked: state.getIn(['compose', 'advanced_options', name]),
|
||||
checked: state.getIn(["compose", "advanced_options", name]),
|
||||
});
|
||||
|
||||
class ToggleOptionImpl extends ImmutablePureComponent {
|
||||
@@ -161,16 +161,16 @@ class ComposerOptions extends ImmutablePureComponent {
|
||||
|
||||
// We switch over the name of the option.
|
||||
switch (name) {
|
||||
case 'upload':
|
||||
if (fileElement) {
|
||||
fileElement.click();
|
||||
}
|
||||
return;
|
||||
case 'doodle':
|
||||
if (onDoodleOpen) {
|
||||
onDoodleOpen();
|
||||
}
|
||||
return;
|
||||
case "upload":
|
||||
if (fileElement) {
|
||||
fileElement.click();
|
||||
}
|
||||
return;
|
||||
case "doodle":
|
||||
if (onDoodleOpen) {
|
||||
onDoodleOpen();
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -209,13 +209,13 @@ class ComposerOptions extends ImmutablePureComponent {
|
||||
|
||||
const contentTypeItems = {
|
||||
plain: {
|
||||
icon: 'file-text',
|
||||
name: 'text/plain',
|
||||
icon: "file-text",
|
||||
name: "text/plain",
|
||||
text: formatMessage(messages.plain),
|
||||
},
|
||||
markdown: {
|
||||
icon: 'arrow-circle-down',
|
||||
name: 'text/markdown',
|
||||
icon: "arrow-circle-down",
|
||||
name: "text/markdown",
|
||||
text: formatMessage(messages.markdown),
|
||||
},
|
||||
};
|
||||
@@ -231,20 +231,20 @@ class ComposerOptions extends ImmutablePureComponent {
|
||||
ref={this.handleRefFileElement}
|
||||
type='file'
|
||||
multiple
|
||||
style={{ display: 'none' }}
|
||||
style={{ display: "none" }}
|
||||
/>
|
||||
<DropdownContainer
|
||||
disabled={disabled || !allowMedia}
|
||||
icon='paperclip'
|
||||
items={[
|
||||
{
|
||||
icon: 'cloud-upload',
|
||||
name: 'upload',
|
||||
icon: "cloud-upload",
|
||||
name: "upload",
|
||||
text: formatMessage(messages.upload),
|
||||
},
|
||||
{
|
||||
icon: 'paint-brush',
|
||||
name: 'doodle',
|
||||
icon: "paint-brush",
|
||||
name: "doodle",
|
||||
text: formatMessage(messages.doodle),
|
||||
},
|
||||
]}
|
||||
@@ -271,7 +271,7 @@ class ComposerOptions extends ImmutablePureComponent {
|
||||
{showContentTypeChoice && (
|
||||
<DropdownContainer
|
||||
disabled={disabled}
|
||||
icon={(contentTypeItems[contentType.split('/')[1]] || {}).icon}
|
||||
icon={(contentTypeItems[contentType.split("/")[1]] || {}).icon}
|
||||
items={[
|
||||
contentTypeItems.plain,
|
||||
contentTypeItems.markdown,
|
||||
@@ -297,12 +297,12 @@ class ComposerOptions extends ImmutablePureComponent {
|
||||
items={advancedOptions ? [
|
||||
{
|
||||
meta: formatMessage(messages.local_only_long),
|
||||
name: 'do_not_federate',
|
||||
name: "do_not_federate",
|
||||
text: formatMessage(messages.local_only_short),
|
||||
},
|
||||
{
|
||||
meta: formatMessage(messages.threaded_mode_long),
|
||||
name: 'threaded_mode',
|
||||
name: "threaded_mode",
|
||||
text: formatMessage(messages.threaded_mode_short),
|
||||
},
|
||||
] : null}
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import AutosuggestInput from 'flavours/glitch/components/autosuggest_input';
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||
import { pollLimits } from 'flavours/glitch/initial_state';
|
||||
import AutosuggestInput from "flavours/glitch/components/autosuggest_input";
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
import { IconButton } from "flavours/glitch/components/icon_button";
|
||||
import { pollLimits } from "flavours/glitch/initial_state";
|
||||
|
||||
const messages = defineMessages({
|
||||
option_placeholder: { id: 'compose_form.poll.option_placeholder', defaultMessage: 'Choice {number}' },
|
||||
add_option: { id: 'compose_form.poll.add_option', defaultMessage: 'Add a choice' },
|
||||
remove_option: { id: 'compose_form.poll.remove_option', defaultMessage: 'Remove this choice' },
|
||||
poll_duration: { id: 'compose_form.poll.duration', defaultMessage: 'Poll duration' },
|
||||
single_choice: { id: 'compose_form.poll.single_choice', defaultMessage: 'Allow one choice' },
|
||||
multiple_choices: { id: 'compose_form.poll.multiple_choices', defaultMessage: 'Allow multiple choices' },
|
||||
minutes: { id: 'intervals.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}}' },
|
||||
hours: { id: 'intervals.full.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}}' },
|
||||
days: { id: 'intervals.full.days', defaultMessage: '{number, plural, one {# day} other {# days}}' },
|
||||
option_placeholder: { id: "compose_form.poll.option_placeholder", defaultMessage: "Choice {number}" },
|
||||
add_option: { id: "compose_form.poll.add_option", defaultMessage: "Add a choice" },
|
||||
remove_option: { id: "compose_form.poll.remove_option", defaultMessage: "Remove this choice" },
|
||||
poll_duration: { id: "compose_form.poll.duration", defaultMessage: "Poll duration" },
|
||||
single_choice: { id: "compose_form.poll.single_choice", defaultMessage: "Allow one choice" },
|
||||
multiple_choices: { id: "compose_form.poll.multiple_choices", defaultMessage: "Allow multiple choices" },
|
||||
minutes: { id: "intervals.full.minutes", defaultMessage: "{number, plural, one {# minute} other {# minutes}}" },
|
||||
hours: { id: "intervals.full.hours", defaultMessage: "{number, plural, one {# hour} other {# hours}}" },
|
||||
days: { id: "intervals.full.days", defaultMessage: "{number, plural, one {# day} other {# days}}" },
|
||||
});
|
||||
|
||||
class OptionIntl extends PureComponent {
|
||||
@@ -59,7 +59,7 @@ class OptionIntl extends PureComponent {
|
||||
};
|
||||
|
||||
onSuggestionSelected = (tokenStart, token, value) => {
|
||||
this.props.onSuggestionSelected(tokenStart, token, value, ['poll', 'options', this.props.index]);
|
||||
this.props.onSuggestionSelected(tokenStart, token, value, ["poll", "options", this.props.index]);
|
||||
};
|
||||
|
||||
render () {
|
||||
@@ -68,7 +68,7 @@ class OptionIntl extends PureComponent {
|
||||
return (
|
||||
<li>
|
||||
<label className='poll__option editable'>
|
||||
<span className={classNames('poll__input', { checkbox: isPollMultiple })} />
|
||||
<span className={classNames("poll__input", { checkbox: isPollMultiple })} />
|
||||
|
||||
<AutosuggestInput
|
||||
placeholder={intl.formatMessage(messages.option_placeholder, { number: index + 1 })}
|
||||
@@ -81,7 +81,7 @@ class OptionIntl extends PureComponent {
|
||||
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
||||
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
||||
onSuggestionSelected={this.onSuggestionSelected}
|
||||
searchTokens={[':']}
|
||||
searchTokens={[":"]}
|
||||
autoFocus={autoFocus}
|
||||
/>
|
||||
</label>
|
||||
@@ -116,7 +116,7 @@ class PollForm extends ImmutablePureComponent {
|
||||
};
|
||||
|
||||
handleAddOption = () => {
|
||||
this.props.onAddOption('');
|
||||
this.props.onAddOption("");
|
||||
};
|
||||
|
||||
handleSelectDuration = e => {
|
||||
@@ -124,7 +124,7 @@ class PollForm extends ImmutablePureComponent {
|
||||
};
|
||||
|
||||
handleSelectMultiple = e => {
|
||||
this.props.onChangeSettings(this.props.expiresIn, e.target.value === 'true');
|
||||
this.props.onChangeSettings(this.props.expiresIn, e.target.value === "true");
|
||||
};
|
||||
|
||||
render () {
|
||||
@@ -134,7 +134,7 @@ class PollForm extends ImmutablePureComponent {
|
||||
return null;
|
||||
}
|
||||
|
||||
const autoFocusIndex = options.indexOf('');
|
||||
const autoFocusIndex = options.indexOf("");
|
||||
|
||||
return (
|
||||
<div className='compose-form__poll-wrapper'>
|
||||
@@ -142,7 +142,7 @@ class PollForm extends ImmutablePureComponent {
|
||||
{options.map((title, i) => <Option title={title} lang={lang} key={i} index={i} onChange={onChangeOption} onRemove={onRemoveOption} isPollMultiple={isMultiple} autoFocus={i === autoFocusIndex} {...other} />)}
|
||||
{options.size < pollLimits.max_options && (
|
||||
<label className='poll__text editable'>
|
||||
<span className={classNames('poll__input')} style={{ opacity: 0 }} />
|
||||
<span className={classNames("poll__input")} style={{ opacity: 0 }} />
|
||||
<button className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' /> <FormattedMessage {...messages.add_option} /></button>
|
||||
</label>
|
||||
)}
|
||||
@@ -150,7 +150,7 @@ class PollForm extends ImmutablePureComponent {
|
||||
|
||||
<div className='poll__footer'>
|
||||
{/* eslint-disable-next-line jsx-a11y/no-onchange */}
|
||||
<select value={isMultiple ? 'true' : 'false'} onChange={this.handleSelectMultiple}>
|
||||
<select value={isMultiple ? "true" : "false"} onChange={this.handleSelectMultiple}>
|
||||
<option value='false'>{intl.formatMessage(messages.single_choice)}</option>
|
||||
<option value='true'>{intl.formatMessage(messages.multiple_choices)}</option>
|
||||
</select>
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl } from "react-intl";
|
||||
|
||||
import Dropdown from './dropdown';
|
||||
import Dropdown from "./dropdown";
|
||||
|
||||
const messages = defineMessages({
|
||||
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
|
||||
public_long: { id: 'privacy.public.long', defaultMessage: 'Visible for all' },
|
||||
unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
|
||||
unlisted_long: { id: 'privacy.unlisted.long', defaultMessage: 'Visible for all, but opted-out of discovery features' },
|
||||
private_short: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
|
||||
private_long: { id: 'privacy.private.long', defaultMessage: 'Visible for followers only' },
|
||||
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
|
||||
direct_long: { id: 'privacy.direct.long', defaultMessage: 'Visible for mentioned users only' },
|
||||
change_privacy: { id: 'privacy.change', defaultMessage: 'Adjust status privacy' },
|
||||
public_short: { id: "privacy.public.short", defaultMessage: "Public" },
|
||||
public_long: { id: "privacy.public.long", defaultMessage: "Visible for all" },
|
||||
unlisted_short: { id: "privacy.unlisted.short", defaultMessage: "Unlisted" },
|
||||
unlisted_long: { id: "privacy.unlisted.long", defaultMessage: "Visible for all, but opted-out of discovery features" },
|
||||
private_short: { id: "privacy.private.short", defaultMessage: "Followers only" },
|
||||
private_long: { id: "privacy.private.long", defaultMessage: "Visible for followers only" },
|
||||
direct_short: { id: "privacy.direct.short", defaultMessage: "Mentioned people only" },
|
||||
direct_long: { id: "privacy.direct.long", defaultMessage: "Visible for mentioned users only" },
|
||||
change_privacy: { id: "privacy.change", defaultMessage: "Adjust status privacy" },
|
||||
});
|
||||
|
||||
class PrivacyDropdown extends PureComponent {
|
||||
@@ -38,27 +38,27 @@ class PrivacyDropdown extends PureComponent {
|
||||
// dropdown icon later.
|
||||
const privacyItems = {
|
||||
direct: {
|
||||
icon: 'envelope',
|
||||
icon: "envelope",
|
||||
meta: formatMessage(messages.direct_long),
|
||||
name: 'direct',
|
||||
name: "direct",
|
||||
text: formatMessage(messages.direct_short),
|
||||
},
|
||||
private: {
|
||||
icon: 'lock',
|
||||
icon: "lock",
|
||||
meta: formatMessage(messages.private_long),
|
||||
name: 'private',
|
||||
name: "private",
|
||||
text: formatMessage(messages.private_short),
|
||||
},
|
||||
public: {
|
||||
icon: 'globe',
|
||||
icon: "globe",
|
||||
meta: formatMessage(messages.public_long),
|
||||
name: 'public',
|
||||
name: "public",
|
||||
text: formatMessage(messages.public_short),
|
||||
},
|
||||
unlisted: {
|
||||
icon: 'unlock',
|
||||
icon: "unlock",
|
||||
meta: formatMessage(messages.unlisted_long),
|
||||
name: 'unlisted',
|
||||
name: "unlisted",
|
||||
text: formatMessage(messages.unlisted_short),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import { length } from 'stringz';
|
||||
import { length } from "stringz";
|
||||
|
||||
import Button from 'flavours/glitch/components/button';
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { maxChars } from 'flavours/glitch/initial_state';
|
||||
import Button from "flavours/glitch/components/button";
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
import { maxChars } from "flavours/glitch/initial_state";
|
||||
|
||||
const messages = defineMessages({
|
||||
publish: {
|
||||
defaultMessage: 'Promulgate',
|
||||
id: 'compose_form.publish',
|
||||
defaultMessage: "Promulgate",
|
||||
id: "compose_form.publish",
|
||||
},
|
||||
publishLoud: {
|
||||
defaultMessage: '{publish}!',
|
||||
id: 'compose_form.publish_loud',
|
||||
defaultMessage: "{publish}!",
|
||||
id: "compose_form.publish_loud",
|
||||
},
|
||||
saveChanges: { id: 'compose_form.save_changes', defaultMessage: 'Save changes' },
|
||||
public: { id: 'privacy.public.short', defaultMessage: 'Public' },
|
||||
unlisted: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
|
||||
private: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
|
||||
direct: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
|
||||
saveChanges: { id: "compose_form.save_changes", defaultMessage: "Save changes" },
|
||||
public: { id: "privacy.public.short", defaultMessage: "Public" },
|
||||
unlisted: { id: "privacy.unlisted.short", defaultMessage: "Unlisted" },
|
||||
private: { id: "privacy.private.short", defaultMessage: "Followers only" },
|
||||
direct: { id: "privacy.direct.short", defaultMessage: "Mentioned people only" },
|
||||
});
|
||||
|
||||
class Publisher extends ImmutablePureComponent {
|
||||
@@ -36,8 +36,8 @@ class Publisher extends ImmutablePureComponent {
|
||||
intl: PropTypes.object.isRequired,
|
||||
onSecondarySubmit: PropTypes.func,
|
||||
onSubmit: PropTypes.func,
|
||||
privacy: PropTypes.oneOf(['direct', 'private', 'unlisted', 'public']),
|
||||
sideArm: PropTypes.oneOf(['none', 'direct', 'private', 'unlisted', 'public']),
|
||||
privacy: PropTypes.oneOf(["direct", "private", "unlisted", "public"]),
|
||||
sideArm: PropTypes.oneOf(["none", "direct", "private", "unlisted", "public"]),
|
||||
isEditing: PropTypes.bool,
|
||||
};
|
||||
|
||||
@@ -48,18 +48,18 @@ class Publisher extends ImmutablePureComponent {
|
||||
render () {
|
||||
const { countText, disabled, intl, onSecondarySubmit, privacy, sideArm, isEditing } = this.props;
|
||||
|
||||
const diff = maxChars - length(countText || '');
|
||||
const computedClass = classNames('compose-form__publish', {
|
||||
const diff = maxChars - length(countText || "");
|
||||
const computedClass = classNames("compose-form__publish", {
|
||||
disabled: disabled,
|
||||
over: diff < 0,
|
||||
});
|
||||
|
||||
const privacyIcons = { direct: 'envelope', private: 'lock', public: 'globe', unlisted: 'unlock' };
|
||||
const privacyIcons = { direct: "envelope", private: "lock", public: "globe", unlisted: "unlock" };
|
||||
|
||||
let publishText;
|
||||
if (isEditing) {
|
||||
publishText = intl.formatMessage(messages.saveChanges);
|
||||
} else if (privacy === 'private' || privacy === 'direct') {
|
||||
} else if (privacy === "private" || privacy === "direct") {
|
||||
const iconId = privacyIcons[privacy];
|
||||
publishText = (
|
||||
<span>
|
||||
@@ -67,7 +67,7 @@ class Publisher extends ImmutablePureComponent {
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
publishText = privacy !== 'unlisted' ? intl.formatMessage(messages.publishLoud, { publish: intl.formatMessage(messages.publish) }) : intl.formatMessage(messages.publish);
|
||||
publishText = privacy !== "unlisted" ? intl.formatMessage(messages.publishLoud, { publish: intl.formatMessage(messages.publish) }) : intl.formatMessage(messages.publish);
|
||||
}
|
||||
|
||||
const privacyNames = {
|
||||
@@ -79,7 +79,7 @@ class Publisher extends ImmutablePureComponent {
|
||||
|
||||
return (
|
||||
<div className={computedClass}>
|
||||
{sideArm && !isEditing && sideArm !== 'none' ? (
|
||||
{sideArm && !isEditing && sideArm !== "none" ? (
|
||||
<div className='compose-form__publish-button-wrapper'>
|
||||
<Button
|
||||
className='side_arm'
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
// Package imports.
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
// Components.
|
||||
import AttachmentList from 'flavours/glitch/components/attachment_list';
|
||||
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||
import AccountContainer from 'flavours/glitch/containers/account_container';
|
||||
import AttachmentList from "flavours/glitch/components/attachment_list";
|
||||
import { IconButton } from "flavours/glitch/components/icon_button";
|
||||
import AccountContainer from "flavours/glitch/containers/account_container";
|
||||
// Messages.
|
||||
const messages = defineMessages({
|
||||
cancel: {
|
||||
defaultMessage: 'Cancel',
|
||||
id: 'reply_indicator.cancel',
|
||||
defaultMessage: "Cancel",
|
||||
id: "reply_indicator.cancel",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -42,9 +42,9 @@ class ReplyIndicator extends ImmutablePureComponent {
|
||||
return null;
|
||||
}
|
||||
|
||||
const account = status.get('account');
|
||||
const content = status.get('content');
|
||||
const attachments = status.get('media_attachments');
|
||||
const account = status.get("account");
|
||||
const content = status.get("content");
|
||||
const attachments = status.get("media_attachments");
|
||||
|
||||
// The result.
|
||||
return (
|
||||
@@ -66,7 +66,7 @@ class ReplyIndicator extends ImmutablePureComponent {
|
||||
</header>
|
||||
<div
|
||||
className='reply-indicator__content translate'
|
||||
dangerouslySetInnerHTML={{ __html: content || '' }}
|
||||
dangerouslySetInnerHTML={{ __html: content || "" }}
|
||||
/>
|
||||
{attachments.size > 0 && (
|
||||
<AttachmentList
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage, FormattedList } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage, FormattedList } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { domain, searchEnabled } from 'flavours/glitch/initial_state';
|
||||
import { focusRoot } from 'flavours/glitch/utils/dom_helpers';
|
||||
import { HASHTAG_REGEX } from 'flavours/glitch/utils/hashtags';
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
import { domain, searchEnabled } from "flavours/glitch/initial_state";
|
||||
import { focusRoot } from "flavours/glitch/utils/dom_helpers";
|
||||
import { HASHTAG_REGEX } from "flavours/glitch/utils/hashtags";
|
||||
|
||||
const messages = defineMessages({
|
||||
placeholder: { id: 'search.placeholder', defaultMessage: 'Search' },
|
||||
placeholderSignedIn: { id: 'search.search_or_paste', defaultMessage: 'Search or paste URL' },
|
||||
placeholder: { id: "search.placeholder", defaultMessage: "Search" },
|
||||
placeholderSignedIn: { id: "search.search_or_paste", defaultMessage: "Search or paste URL" },
|
||||
});
|
||||
|
||||
const labelForRecentSearch = search => {
|
||||
switch(search.get('type')) {
|
||||
case 'account':
|
||||
return `@${search.get('q')}`;
|
||||
case 'hashtag':
|
||||
return `#${search.get('q')}`;
|
||||
default:
|
||||
return search.get('q');
|
||||
switch(search.get("type")) {
|
||||
case "account":
|
||||
return `@${search.get("q")}`;
|
||||
case "hashtag":
|
||||
return `#${search.get("q")}`;
|
||||
default:
|
||||
return search.get("q");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -59,14 +59,30 @@ class Search extends PureComponent {
|
||||
};
|
||||
|
||||
defaultOptions = [
|
||||
{ label: <><mark>has:</mark> <FormattedList type='disjunction' value={['media', 'poll', 'embed']} /></>, action: e => { e.preventDefault(); this._insertText('has:'); } },
|
||||
{ label: <><mark>is:</mark> <FormattedList type='disjunction' value={['reply', 'sensitive']} /></>, action: e => { e.preventDefault(); this._insertText('is:'); } },
|
||||
{ label: <><mark>language:</mark> <FormattedMessage id='search_popout.language_code' defaultMessage='ISO language code' /></>, action: e => { e.preventDefault(); this._insertText('language:'); } },
|
||||
{ label: <><mark>from:</mark> <FormattedMessage id='search_popout.user' defaultMessage='user' /></>, action: e => { e.preventDefault(); this._insertText('from:'); } },
|
||||
{ label: <><mark>before:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('before:'); } },
|
||||
{ label: <><mark>during:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('during:'); } },
|
||||
{ label: <><mark>after:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('after:'); } },
|
||||
{ label: <><mark>in:</mark> <FormattedList type='disjunction' value={['all', 'library']} /></>, action: e => { e.preventDefault(); this._insertText('in:'); } }
|
||||
{ label: <><mark>has:</mark> <FormattedList type='disjunction' value={["media", "poll", "embed"]} /></>, action: e => {
|
||||
e.preventDefault(); this._insertText("has:");
|
||||
} },
|
||||
{ label: <><mark>is:</mark> <FormattedList type='disjunction' value={["reply", "sensitive"]} /></>, action: e => {
|
||||
e.preventDefault(); this._insertText("is:");
|
||||
} },
|
||||
{ label: <><mark>language:</mark> <FormattedMessage id='search_popout.language_code' defaultMessage='ISO language code' /></>, action: e => {
|
||||
e.preventDefault(); this._insertText("language:");
|
||||
} },
|
||||
{ label: <><mark>from:</mark> <FormattedMessage id='search_popout.user' defaultMessage='user' /></>, action: e => {
|
||||
e.preventDefault(); this._insertText("from:");
|
||||
} },
|
||||
{ label: <><mark>before:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => {
|
||||
e.preventDefault(); this._insertText("before:");
|
||||
} },
|
||||
{ label: <><mark>during:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => {
|
||||
e.preventDefault(); this._insertText("during:");
|
||||
} },
|
||||
{ label: <><mark>after:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => {
|
||||
e.preventDefault(); this._insertText("after:");
|
||||
} },
|
||||
{ label: <><mark>in:</mark> <FormattedList type='disjunction' value={["all", "library"]} /></>, action: e => {
|
||||
e.preventDefault(); this._insertText("in:");
|
||||
} },
|
||||
];
|
||||
|
||||
setRef = c => {
|
||||
@@ -120,48 +136,48 @@ class Search extends PureComponent {
|
||||
const options = searchEnabled ? this._getOptions().concat(this.defaultOptions) : this._getOptions();
|
||||
|
||||
switch(e.key) {
|
||||
case 'Escape':
|
||||
e.preventDefault();
|
||||
case "Escape":
|
||||
e.preventDefault();
|
||||
|
||||
focusRoot();
|
||||
focusRoot();
|
||||
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
e.preventDefault();
|
||||
break;
|
||||
case "ArrowDown":
|
||||
e.preventDefault();
|
||||
|
||||
if (options.length > 0) {
|
||||
this.setState({ selectedOption: Math.min(selectedOption + 1, options.length - 1) });
|
||||
}
|
||||
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
e.preventDefault();
|
||||
|
||||
if (options.length > 0) {
|
||||
this.setState({ selectedOption: Math.max(selectedOption - 1, -1) });
|
||||
}
|
||||
|
||||
break;
|
||||
case 'Enter':
|
||||
e.preventDefault();
|
||||
|
||||
if (selectedOption === -1) {
|
||||
this._submit();
|
||||
} else if (options.length > 0) {
|
||||
options[selectedOption].action(e);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'Delete':
|
||||
if (selectedOption > -1 && options.length > 0) {
|
||||
const search = options[selectedOption];
|
||||
|
||||
if (typeof search.forget === 'function') {
|
||||
e.preventDefault();
|
||||
search.forget(e);
|
||||
if (options.length > 0) {
|
||||
this.setState({ selectedOption: Math.min(selectedOption + 1, options.length - 1) });
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
break;
|
||||
case "ArrowUp":
|
||||
e.preventDefault();
|
||||
|
||||
if (options.length > 0) {
|
||||
this.setState({ selectedOption: Math.max(selectedOption - 1, -1) });
|
||||
}
|
||||
|
||||
break;
|
||||
case "Enter":
|
||||
e.preventDefault();
|
||||
|
||||
if (selectedOption === -1) {
|
||||
this._submit();
|
||||
} else if (options.length > 0) {
|
||||
options[selectedOption].action(e);
|
||||
}
|
||||
|
||||
break;
|
||||
case "Delete":
|
||||
if (selectedOption > -1 && options.length > 0) {
|
||||
const search = options[selectedOption];
|
||||
|
||||
if (typeof search.forget === "function") {
|
||||
e.preventDefault();
|
||||
search.forget(e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -173,10 +189,10 @@ class Search extends PureComponent {
|
||||
const { router } = this.context;
|
||||
const { value, onClickSearchResult } = this.props;
|
||||
|
||||
const query = value.trim().replace(/^#/, '');
|
||||
const query = value.trim().replace(/^#/, "");
|
||||
|
||||
router.history.push(`/tags/${query}`);
|
||||
onClickSearchResult(query, 'hashtag');
|
||||
onClickSearchResult(query, "hashtag");
|
||||
this._unfocus();
|
||||
};
|
||||
|
||||
@@ -184,10 +200,10 @@ class Search extends PureComponent {
|
||||
const { router } = this.context;
|
||||
const { value, onClickSearchResult } = this.props;
|
||||
|
||||
const query = value.trim().replace(/^@/, '');
|
||||
const query = value.trim().replace(/^@/, "");
|
||||
|
||||
router.history.push(`/@${query}`);
|
||||
onClickSearchResult(query, 'account');
|
||||
onClickSearchResult(query, "account");
|
||||
this._unfocus();
|
||||
};
|
||||
|
||||
@@ -200,24 +216,24 @@ class Search extends PureComponent {
|
||||
};
|
||||
|
||||
handleStatusSearch = () => {
|
||||
this._submit('statuses');
|
||||
this._submit("statuses");
|
||||
};
|
||||
|
||||
handleAccountSearch = () => {
|
||||
this._submit('accounts');
|
||||
this._submit("accounts");
|
||||
};
|
||||
|
||||
handleRecentSearchClick = search => {
|
||||
const { onChange } = this.props;
|
||||
const { router } = this.context;
|
||||
|
||||
if (search.get('type') === 'account') {
|
||||
router.history.push(`/@${search.get('q')}`);
|
||||
} else if (search.get('type') === 'hashtag') {
|
||||
router.history.push(`/tags/${search.get('q')}`);
|
||||
if (search.get("type") === "account") {
|
||||
router.history.push(`/@${search.get("q")}`);
|
||||
} else if (search.get("type") === "hashtag") {
|
||||
router.history.push(`/tags/${search.get("q")}`);
|
||||
} else {
|
||||
onChange(search.get('q'));
|
||||
this._submit(search.get('type'));
|
||||
onChange(search.get("q"));
|
||||
this._submit(search.get("type"));
|
||||
}
|
||||
|
||||
this._unfocus();
|
||||
@@ -226,19 +242,19 @@ class Search extends PureComponent {
|
||||
handleForgetRecentSearchClick = search => {
|
||||
const { onForgetSearchResult } = this.props;
|
||||
|
||||
onForgetSearchResult(search.get('q'));
|
||||
onForgetSearchResult(search.get("q"));
|
||||
};
|
||||
|
||||
_unfocus () {
|
||||
document.querySelector('.ui').parentElement.focus();
|
||||
document.querySelector(".ui").parentElement.focus();
|
||||
}
|
||||
|
||||
_insertText (text) {
|
||||
const { value, onChange } = this.props;
|
||||
|
||||
if (value === '') {
|
||||
if (value === "") {
|
||||
onChange(text);
|
||||
} else if (value[value.length - 1] === ' ') {
|
||||
} else if (value[value.length - 1] === " ") {
|
||||
onChange(`${value}${text}`);
|
||||
} else {
|
||||
onChange(`${value} ${text}`);
|
||||
@@ -256,7 +272,7 @@ class Search extends PureComponent {
|
||||
}
|
||||
|
||||
if (openInRoute) {
|
||||
router.history.push('/search');
|
||||
router.history.push("/search");
|
||||
}
|
||||
|
||||
this._unfocus();
|
||||
@@ -288,34 +304,34 @@ class Search extends PureComponent {
|
||||
const options = [];
|
||||
|
||||
if (trimmedValue.length > 0) {
|
||||
const couldBeURL = trimmedValue.startsWith('https://') && !trimmedValue.includes(' ');
|
||||
const couldBeURL = trimmedValue.startsWith("https://") && !trimmedValue.includes(" ");
|
||||
|
||||
if (couldBeURL) {
|
||||
options.push({ key: 'open-url', label: <FormattedMessage id='search.quick_action.open_url' defaultMessage='Open URL in Mastodon' />, action: this.handleURLClick });
|
||||
options.push({ key: "open-url", label: <FormattedMessage id='search.quick_action.open_url' defaultMessage='Open URL in Mastodon' />, action: this.handleURLClick });
|
||||
}
|
||||
|
||||
const couldBeHashtag = (trimmedValue.startsWith('#') && trimmedValue.length > 1) || trimmedValue.match(HASHTAG_REGEX);
|
||||
const couldBeHashtag = (trimmedValue.startsWith("#") && trimmedValue.length > 1) || trimmedValue.match(HASHTAG_REGEX);
|
||||
|
||||
if (couldBeHashtag) {
|
||||
options.push({ key: 'go-to-hashtag', label: <FormattedMessage id='search.quick_action.go_to_hashtag' defaultMessage='Go to hashtag {x}' values={{ x: <mark>#{trimmedValue.replace(/^#/, '')}</mark> }} />, action: this.handleHashtagClick });
|
||||
options.push({ key: "go-to-hashtag", label: <FormattedMessage id='search.quick_action.go_to_hashtag' defaultMessage='Go to hashtag {x}' values={{ x: <mark>#{trimmedValue.replace(/^#/, "")}</mark> }} />, action: this.handleHashtagClick });
|
||||
}
|
||||
|
||||
const couldBeUsername = trimmedValue.match(/^@?[a-z0-9_-]+(@[^\s]+)?$/i);
|
||||
|
||||
if (couldBeUsername) {
|
||||
options.push({ key: 'go-to-account', label: <FormattedMessage id='search.quick_action.go_to_account' defaultMessage='Go to profile {x}' values={{ x: <mark>@{trimmedValue.replace(/^@/, '')}</mark> }} />, action: this.handleAccountClick });
|
||||
options.push({ key: "go-to-account", label: <FormattedMessage id='search.quick_action.go_to_account' defaultMessage='Go to profile {x}' values={{ x: <mark>@{trimmedValue.replace(/^@/, "")}</mark> }} />, action: this.handleAccountClick });
|
||||
}
|
||||
|
||||
const couldBeStatusSearch = searchEnabled;
|
||||
|
||||
if (couldBeStatusSearch) {
|
||||
options.push({ key: 'status-search', label: <FormattedMessage id='search.quick_action.status_search' defaultMessage='Posts matching {x}' values={{ x: <mark>{trimmedValue}</mark> }} />, action: this.handleStatusSearch });
|
||||
options.push({ key: "status-search", label: <FormattedMessage id='search.quick_action.status_search' defaultMessage='Posts matching {x}' values={{ x: <mark>{trimmedValue}</mark> }} />, action: this.handleStatusSearch });
|
||||
}
|
||||
|
||||
const couldBeUserSearch = true;
|
||||
|
||||
if (couldBeUserSearch) {
|
||||
options.push({ key: 'account-search', label: <FormattedMessage id='search.quick_action.account_search' defaultMessage='Profiles matching {x}' values={{ x: <mark>{trimmedValue}</mark> }} />, action: this.handleAccountSearch });
|
||||
options.push({ key: "account-search", label: <FormattedMessage id='search.quick_action.account_search' defaultMessage='Profiles matching {x}' values={{ x: <mark>{trimmedValue}</mark> }} />, action: this.handleAccountSearch });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,14 +346,14 @@ class Search extends PureComponent {
|
||||
const hasValue = value.length > 0 || submitted;
|
||||
|
||||
return (
|
||||
<div className={classNames('search', { active: expanded })}>
|
||||
<div className={classNames("search", { active: expanded })}>
|
||||
<input
|
||||
ref={this.setRef}
|
||||
className='search__input'
|
||||
type='text'
|
||||
placeholder={intl.formatMessage(signedIn ? messages.placeholderSignedIn : messages.placeholder)}
|
||||
aria-label={intl.formatMessage(signedIn ? messages.placeholderSignedIn : messages.placeholder)}
|
||||
value={value || ''}
|
||||
value={value || ""}
|
||||
onChange={this.handleChange}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onFocus={this.handleFocus}
|
||||
@@ -345,8 +361,8 @@ class Search extends PureComponent {
|
||||
/>
|
||||
|
||||
<div role='button' tabIndex={0} className='search__icon' onClick={this.handleClear}>
|
||||
<Icon id='search' className={hasValue ? '' : 'active'} />
|
||||
<Icon id='times-circle' className={hasValue ? 'active' : ''} />
|
||||
<Icon id='search' className={hasValue ? "" : "active"} />
|
||||
<Icon id='times-circle' className={hasValue ? "active" : ""} />
|
||||
</div>
|
||||
<div className='search__popout'>
|
||||
{options.length === 0 && (
|
||||
@@ -355,7 +371,7 @@ class Search extends PureComponent {
|
||||
|
||||
<div className='search__popout__menu'>
|
||||
{recent.size > 0 ? this._getOptions().map(({ label, action, forget }, i) => (
|
||||
<button key={label} onMouseDown={action} className={classNames('search__popout__menu__item search__popout__menu__item--flex', { selected: selectedOption === i })}>
|
||||
<button key={label} onMouseDown={action} className={classNames("search__popout__menu__item search__popout__menu__item--flex", { selected: selectedOption === i })}>
|
||||
<span>{label}</span>
|
||||
<button className='icon-button' onMouseDown={forget}><Icon id='times' /></button>
|
||||
</button>
|
||||
@@ -373,7 +389,7 @@ class Search extends PureComponent {
|
||||
|
||||
<div className='search__popout__menu'>
|
||||
{options.map(({ key, label, action }, i) => (
|
||||
<button key={key} onMouseDown={action} className={classNames('search__popout__menu__item', { selected: selectedOption === i })}>
|
||||
<button key={key} onMouseDown={action} className={classNames("search__popout__menu__item", { selected: selectedOption === i })}>
|
||||
{label}
|
||||
</button>
|
||||
))}
|
||||
@@ -386,7 +402,7 @@ class Search extends PureComponent {
|
||||
{searchEnabled ? (
|
||||
<div className='search__popout__menu'>
|
||||
{this.defaultOptions.map(({ key, label, action }, i) => (
|
||||
<button key={key} onMouseDown={action} className={classNames('search__popout__menu__item', { selected: selectedOption === ((options.length || recent.size) + i) })}>
|
||||
<button key={key} onMouseDown={action} className={classNames("search__popout__menu__item", { selected: selectedOption === ((options.length || recent.size) + i) })}>
|
||||
{label}
|
||||
</button>
|
||||
))}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import { ImmutableHashtag as Hashtag } from 'flavours/glitch/components/hashtag';
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { LoadMore } from 'flavours/glitch/components/load_more';
|
||||
import AccountContainer from 'flavours/glitch/containers/account_container';
|
||||
import StatusContainer from 'flavours/glitch/containers/status_container';
|
||||
import { SearchSection } from 'flavours/glitch/features/explore/components/search_section';
|
||||
import { ImmutableHashtag as Hashtag } from "flavours/glitch/components/hashtag";
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
import { LoadMore } from "flavours/glitch/components/load_more";
|
||||
import AccountContainer from "flavours/glitch/containers/account_container";
|
||||
import StatusContainer from "flavours/glitch/containers/status_container";
|
||||
import { SearchSection } from "flavours/glitch/features/explore/components/search_section";
|
||||
|
||||
const INITIAL_PAGE_LIMIT = 10;
|
||||
|
||||
@@ -30,40 +30,40 @@ class SearchResults extends ImmutablePureComponent {
|
||||
searchTerm: PropTypes.string,
|
||||
};
|
||||
|
||||
handleLoadMoreAccounts = () => this.props.expandSearch('accounts');
|
||||
handleLoadMoreAccounts = () => this.props.expandSearch("accounts");
|
||||
|
||||
handleLoadMoreStatuses = () => this.props.expandSearch('statuses');
|
||||
handleLoadMoreStatuses = () => this.props.expandSearch("statuses");
|
||||
|
||||
handleLoadMoreHashtags = () => this.props.expandSearch('hashtags');
|
||||
handleLoadMoreHashtags = () => this.props.expandSearch("hashtags");
|
||||
|
||||
render () {
|
||||
const { results } = this.props;
|
||||
|
||||
let accounts, statuses, hashtags;
|
||||
|
||||
if (results.get('accounts') && results.get('accounts').size > 0) {
|
||||
if (results.get("accounts") && results.get("accounts").size > 0) {
|
||||
accounts = (
|
||||
<SearchSection title={<><Icon id='users' fixedWidth /><FormattedMessage id='search_results.accounts' defaultMessage='Profiles' /></>}>
|
||||
{withoutLastResult(results.get('accounts')).map(accountId => <AccountContainer key={accountId} id={accountId} />)}
|
||||
{(results.get('accounts').size > INITIAL_PAGE_LIMIT && results.get('accounts').size % INITIAL_PAGE_LIMIT === 1) && <LoadMore visible onClick={this.handleLoadMoreAccounts} />}
|
||||
{withoutLastResult(results.get("accounts")).map(accountId => <AccountContainer key={accountId} id={accountId} />)}
|
||||
{(results.get("accounts").size > INITIAL_PAGE_LIMIT && results.get("accounts").size % INITIAL_PAGE_LIMIT === 1) && <LoadMore visible onClick={this.handleLoadMoreAccounts} />}
|
||||
</SearchSection>
|
||||
);
|
||||
}
|
||||
|
||||
if (results.get('hashtags') && results.get('hashtags').size > 0) {
|
||||
if (results.get("hashtags") && results.get("hashtags").size > 0) {
|
||||
hashtags = (
|
||||
<SearchSection title={<><Icon id='hashtag' fixedWidth /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></>}>
|
||||
{withoutLastResult(results.get('hashtags')).map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
|
||||
{(results.get('hashtags').size > INITIAL_PAGE_LIMIT && results.get('hashtags').size % INITIAL_PAGE_LIMIT === 1) && <LoadMore visible onClick={this.handleLoadMoreHashtags} />}
|
||||
{withoutLastResult(results.get("hashtags")).map(hashtag => <Hashtag key={hashtag.get("name")} hashtag={hashtag} />)}
|
||||
{(results.get("hashtags").size > INITIAL_PAGE_LIMIT && results.get("hashtags").size % INITIAL_PAGE_LIMIT === 1) && <LoadMore visible onClick={this.handleLoadMoreHashtags} />}
|
||||
</SearchSection>
|
||||
);
|
||||
}
|
||||
|
||||
if (results.get('statuses') && results.get('statuses').size > 0) {
|
||||
if (results.get("statuses") && results.get("statuses").size > 0) {
|
||||
statuses = (
|
||||
<SearchSection title={<><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></>}>
|
||||
{withoutLastResult(results.get('statuses')).map(statusId => <StatusContainer key={statusId} id={statusId} />)}
|
||||
{(results.get('statuses').size > INITIAL_PAGE_LIMIT && results.get('statuses').size % INITIAL_PAGE_LIMIT === 1) && <LoadMore visible onClick={this.handleLoadMoreStatuses} />}
|
||||
{withoutLastResult(results.get("statuses")).map(statusId => <StatusContainer key={statusId} id={statusId} />)}
|
||||
{(results.get("statuses").size > INITIAL_PAGE_LIMIT && results.get("statuses").size % INITIAL_PAGE_LIMIT === 1) && <LoadMore visible onClick={this.handleLoadMoreStatuses} />}
|
||||
</SearchSection>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
const iconStyle = {
|
||||
height: null,
|
||||
lineHeight: '27px',
|
||||
lineHeight: "27px",
|
||||
minWidth: `${18 * 1.28571429}px`,
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@ export default class TextIconButton extends PureComponent {
|
||||
<button
|
||||
title={title}
|
||||
aria-label={title}
|
||||
className={`text-icon-button ${active ? 'active' : ''}`}
|
||||
className={`text-icon-button ${active ? "active" : ""}`}
|
||||
aria-expanded={active}
|
||||
onClick={this.props.onClick}
|
||||
aria-controls={ariaControls}
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
// Package imports.
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
// Components.
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
// Messages.
|
||||
const messages = defineMessages({
|
||||
localOnly: {
|
||||
defaultMessage: 'This post is local-only',
|
||||
id: 'advanced_options.local-only.tooltip',
|
||||
defaultMessage: "This post is local-only",
|
||||
id: "advanced_options.local-only.tooltip",
|
||||
},
|
||||
threadedMode: {
|
||||
defaultMessage: 'Threaded mode enabled',
|
||||
id: 'advanced_options.threaded_mode.tooltip',
|
||||
defaultMessage: "Threaded mode enabled",
|
||||
id: "advanced_options.threaded_mode.tooltip",
|
||||
},
|
||||
});
|
||||
|
||||
// We use an array of tuples here instead of an object because it
|
||||
// preserves order.
|
||||
const iconMap = [
|
||||
['do_not_federate', 'home', messages.localOnly],
|
||||
['threaded_mode', 'comments', messages.threadedMode],
|
||||
["do_not_federate", "home", messages.localOnly],
|
||||
["threaded_mode", "comments", messages.threadedMode],
|
||||
];
|
||||
|
||||
class TextareaIcons extends ImmutablePureComponent {
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import spring from 'react-motion/lib/spring';
|
||||
import spring from "react-motion/lib/spring";
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
|
||||
import Motion from '../../ui/util/optional_motion';
|
||||
import Motion from "../../ui/util/optional_motion";
|
||||
|
||||
export default class Upload extends ImmutablePureComponent {
|
||||
|
||||
@@ -25,12 +25,12 @@ export default class Upload extends ImmutablePureComponent {
|
||||
|
||||
handleUndoClick = e => {
|
||||
e.stopPropagation();
|
||||
this.props.onUndo(this.props.media.get('id'));
|
||||
this.props.onUndo(this.props.media.get("id"));
|
||||
};
|
||||
|
||||
handleFocalPointClick = e => {
|
||||
e.stopPropagation();
|
||||
this.props.onOpenFocalPoint(this.props.media.get('id'));
|
||||
this.props.onOpenFocalPoint(this.props.media.get("id"));
|
||||
};
|
||||
|
||||
render () {
|
||||
@@ -40,8 +40,8 @@ export default class Upload extends ImmutablePureComponent {
|
||||
return null;
|
||||
}
|
||||
|
||||
const focusX = media.getIn(['meta', 'focus', 'x']);
|
||||
const focusY = media.getIn(['meta', 'focus', 'y']);
|
||||
const focusX = media.getIn(["meta", "focus", "x"]);
|
||||
const focusY = media.getIn(["meta", "focus", "y"]);
|
||||
const x = ((focusX / 2) + .5) * 100;
|
||||
const y = ((focusY / -2) + .5) * 100;
|
||||
|
||||
@@ -49,13 +49,13 @@ export default class Upload extends ImmutablePureComponent {
|
||||
<div className='compose-form__upload'>
|
||||
<Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12 }) }}>
|
||||
{({ scale }) => (
|
||||
<div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
|
||||
<div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get("preview_url")})`, backgroundPosition: `${x}% ${y}%` }}>
|
||||
<div className='compose-form__upload__actions'>
|
||||
<button type='button' className='icon-button' onClick={this.handleUndoClick}><Icon id='times' /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button>
|
||||
<button type='button' className='icon-button' onClick={this.handleFocalPointClick}><Icon id='pencil' /> <FormattedMessage id='upload_form.edit' defaultMessage='Edit' /></button>
|
||||
</div>
|
||||
|
||||
{(media.get('description') || '').length === 0 && (
|
||||
{(media.get("description") || "").length === 0 && (
|
||||
<div className='compose-form__upload__warning'>
|
||||
<button type='button' className='icon-button' onClick={this.handleFocalPointClick}><Icon id='info-circle' /> <FormattedMessage id='upload_form.description_missing' defaultMessage='No description added' /></button>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import SensitiveButtonContainer from '../containers/sensitive_button_container';
|
||||
import UploadContainer from '../containers/upload_container';
|
||||
import UploadProgressContainer from '../containers/upload_progress_container';
|
||||
import SensitiveButtonContainer from "../containers/sensitive_button_container";
|
||||
import UploadContainer from "../containers/upload_container";
|
||||
import UploadProgressContainer from "../containers/upload_progress_container";
|
||||
|
||||
export default class UploadForm extends ImmutablePureComponent {
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import spring from 'react-motion/lib/spring';
|
||||
import spring from "react-motion/lib/spring";
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
|
||||
import Motion from '../../ui/util/optional_motion';
|
||||
import Motion from "../../ui/util/optional_motion";
|
||||
|
||||
export default class UploadProgress extends PureComponent {
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import spring from 'react-motion/lib/spring';
|
||||
import spring from "react-motion/lib/spring";
|
||||
|
||||
import Motion from '../../ui/util/optional_motion';
|
||||
import Motion from "../../ui/util/optional_motion";
|
||||
|
||||
export default class Warning extends PureComponent {
|
||||
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { makeGetAccount } from 'flavours/glitch/selectors';
|
||||
import { makeGetAccount } from "flavours/glitch/selectors";
|
||||
|
||||
import AutosuggestAccount from '../components/autosuggest_account';
|
||||
import AutosuggestAccount from "../components/autosuggest_account";
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
+49
-49
@@ -1,6 +1,6 @@
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl } from "react-intl";
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import {
|
||||
changeCompose,
|
||||
@@ -13,72 +13,72 @@ import {
|
||||
selectComposeSuggestion,
|
||||
submitCompose,
|
||||
uploadCompose,
|
||||
} from 'flavours/glitch/actions/compose';
|
||||
import { changeLocalSetting } from 'flavours/glitch/actions/local_settings';
|
||||
} from "flavours/glitch/actions/compose";
|
||||
import { changeLocalSetting } from "flavours/glitch/actions/local_settings";
|
||||
import {
|
||||
openModal,
|
||||
} from 'flavours/glitch/actions/modal';
|
||||
import { privacyPreference } from 'flavours/glitch/utils/privacy_preference';
|
||||
} from "flavours/glitch/actions/modal";
|
||||
import { privacyPreference } from "flavours/glitch/utils/privacy_preference";
|
||||
|
||||
import ComposeForm from '../components/compose_form';
|
||||
import ComposeForm from "../components/compose_form";
|
||||
|
||||
const messages = defineMessages({
|
||||
missingDescriptionMessage: {
|
||||
id: 'confirmations.missing_media_description.message',
|
||||
defaultMessage: 'At least one media attachment is lacking a description. Consider describing all media attachments for the visually impaired before sending your toot.',
|
||||
id: "confirmations.missing_media_description.message",
|
||||
defaultMessage: "At least one media attachment is lacking a description. Consider describing all media attachments for the visually impaired before sending your toot.",
|
||||
},
|
||||
missingDescriptionConfirm: {
|
||||
id: 'confirmations.missing_media_description.confirm',
|
||||
defaultMessage: 'Send anyway',
|
||||
id: "confirmations.missing_media_description.confirm",
|
||||
defaultMessage: "Send anyway",
|
||||
},
|
||||
missingDescriptionEdit: {
|
||||
id: 'confirmations.missing_media_description.edit',
|
||||
defaultMessage: 'Edit media',
|
||||
id: "confirmations.missing_media_description.edit",
|
||||
defaultMessage: "Edit media",
|
||||
},
|
||||
});
|
||||
|
||||
// State mapping.
|
||||
function mapStateToProps (state) {
|
||||
const spoilersAlwaysOn = state.getIn(['local_settings', 'always_show_spoilers_field']);
|
||||
const inReplyTo = state.getIn(['compose', 'in_reply_to']);
|
||||
const replyPrivacy = inReplyTo ? state.getIn(['statuses', inReplyTo, 'visibility']) : null;
|
||||
const sideArmBasePrivacy = state.getIn(['local_settings', 'side_arm']);
|
||||
const spoilersAlwaysOn = state.getIn(["local_settings", "always_show_spoilers_field"]);
|
||||
const inReplyTo = state.getIn(["compose", "in_reply_to"]);
|
||||
const replyPrivacy = inReplyTo ? state.getIn(["statuses", inReplyTo, "visibility"]) : null;
|
||||
const sideArmBasePrivacy = state.getIn(["local_settings", "side_arm"]);
|
||||
const sideArmRestrictedPrivacy = replyPrivacy ? privacyPreference(replyPrivacy, sideArmBasePrivacy) : null;
|
||||
let sideArmPrivacy = null;
|
||||
switch (state.getIn(['local_settings', 'side_arm_reply_mode'])) {
|
||||
case 'copy':
|
||||
sideArmPrivacy = replyPrivacy;
|
||||
break;
|
||||
case 'restrict':
|
||||
sideArmPrivacy = sideArmRestrictedPrivacy;
|
||||
break;
|
||||
switch (state.getIn(["local_settings", "side_arm_reply_mode"])) {
|
||||
case "copy":
|
||||
sideArmPrivacy = replyPrivacy;
|
||||
break;
|
||||
case "restrict":
|
||||
sideArmPrivacy = sideArmRestrictedPrivacy;
|
||||
break;
|
||||
}
|
||||
sideArmPrivacy = sideArmPrivacy || sideArmBasePrivacy;
|
||||
return {
|
||||
advancedOptions: state.getIn(['compose', 'advanced_options']),
|
||||
focusDate: state.getIn(['compose', 'focusDate']),
|
||||
caretPosition: state.getIn(['compose', 'caretPosition']),
|
||||
isSubmitting: state.getIn(['compose', 'is_submitting']),
|
||||
isEditing: state.getIn(['compose', 'id']) !== null,
|
||||
isChangingUpload: state.getIn(['compose', 'is_changing_upload']),
|
||||
isUploading: state.getIn(['compose', 'is_uploading']),
|
||||
layout: state.getIn(['local_settings', 'layout']),
|
||||
media: state.getIn(['compose', 'media_attachments']),
|
||||
preselectDate: state.getIn(['compose', 'preselectDate']),
|
||||
privacy: state.getIn(['compose', 'privacy']),
|
||||
advancedOptions: state.getIn(["compose", "advanced_options"]),
|
||||
focusDate: state.getIn(["compose", "focusDate"]),
|
||||
caretPosition: state.getIn(["compose", "caretPosition"]),
|
||||
isSubmitting: state.getIn(["compose", "is_submitting"]),
|
||||
isEditing: state.getIn(["compose", "id"]) !== null,
|
||||
isChangingUpload: state.getIn(["compose", "is_changing_upload"]),
|
||||
isUploading: state.getIn(["compose", "is_uploading"]),
|
||||
layout: state.getIn(["local_settings", "layout"]),
|
||||
media: state.getIn(["compose", "media_attachments"]),
|
||||
preselectDate: state.getIn(["compose", "preselectDate"]),
|
||||
privacy: state.getIn(["compose", "privacy"]),
|
||||
sideArm: sideArmPrivacy,
|
||||
sensitive: state.getIn(['compose', 'sensitive']),
|
||||
showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']),
|
||||
spoiler: spoilersAlwaysOn || state.getIn(['compose', 'spoiler']),
|
||||
spoilerText: state.getIn(['compose', 'spoiler_text']),
|
||||
suggestions: state.getIn(['compose', 'suggestions']),
|
||||
text: state.getIn(['compose', 'text']),
|
||||
anyMedia: state.getIn(['compose', 'media_attachments']).size > 0,
|
||||
sensitive: state.getIn(["compose", "sensitive"]),
|
||||
showSearch: state.getIn(["search", "submitted"]) && !state.getIn(["search", "hidden"]),
|
||||
spoiler: spoilersAlwaysOn || state.getIn(["compose", "spoiler"]),
|
||||
spoilerText: state.getIn(["compose", "spoiler_text"]),
|
||||
suggestions: state.getIn(["compose", "suggestions"]),
|
||||
text: state.getIn(["compose", "text"]),
|
||||
anyMedia: state.getIn(["compose", "media_attachments"]).size > 0,
|
||||
spoilersAlwaysOn: spoilersAlwaysOn,
|
||||
mediaDescriptionConfirmation: state.getIn(['local_settings', 'confirm_missing_media_description']),
|
||||
preselectOnReply: state.getIn(['local_settings', 'preselect_on_reply']),
|
||||
isInReply: state.getIn(['compose', 'in_reply_to']) !== null,
|
||||
lang: state.getIn(['compose', 'language']),
|
||||
mediaDescriptionConfirmation: state.getIn(["local_settings", "confirm_missing_media_description"]),
|
||||
preselectOnReply: state.getIn(["local_settings", "preselect_on_reply"]),
|
||||
isInReply: state.getIn(["compose", "in_reply_to"]) !== null,
|
||||
lang: state.getIn(["compose", "language"]),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
|
||||
onMediaDescriptionConfirm(routerHistory, mediaId, overriddenVisibility = null) {
|
||||
dispatch(openModal({
|
||||
modalType: 'CONFIRM',
|
||||
modalType: "CONFIRM",
|
||||
modalProps: {
|
||||
message: intl.formatMessage(messages.missingDescriptionMessage),
|
||||
confirm: intl.formatMessage(messages.missingDescriptionConfirm),
|
||||
@@ -139,10 +139,10 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
},
|
||||
secondary: intl.formatMessage(messages.missingDescriptionEdit),
|
||||
onSecondary: () => dispatch(openModal({
|
||||
modalType: 'FOCAL_POINT',
|
||||
modalType: "FOCAL_POINT",
|
||||
modalProps: { id: mediaId },
|
||||
})),
|
||||
onDoNotAsk: () => dispatch(changeLocalSetting(['confirm_missing_media_description'], false)),
|
||||
onDoNotAsk: () => dispatch(changeLocalSetting(["confirm_missing_media_description"], false)),
|
||||
},
|
||||
}));
|
||||
},
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { openModal, closeModal } from 'flavours/glitch/actions/modal';
|
||||
import { isUserTouching } from 'flavours/glitch/is_mobile';
|
||||
import { openModal, closeModal } from "flavours/glitch/actions/modal";
|
||||
import { isUserTouching } from "flavours/glitch/is_mobile";
|
||||
|
||||
import Dropdown from '../components/dropdown';
|
||||
import Dropdown from "../components/dropdown";
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
isUserTouching,
|
||||
onModalOpen: props => dispatch(openModal({ modalType: 'ACTIONS', modalProps: props })),
|
||||
onModalOpen: props => dispatch(openModal({ modalType: "ACTIONS", modalProps: props })),
|
||||
onModalClose: () => dispatch(closeModal({ modalType: undefined, ignoreFocus: false })),
|
||||
});
|
||||
|
||||
|
||||
+30
-30
@@ -1,36 +1,36 @@
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { Map as ImmutableMap } from "immutable";
|
||||
import { connect } from "react-redux";
|
||||
import { createSelector } from "reselect";
|
||||
|
||||
import { useEmoji } from 'flavours/glitch/actions/emojis';
|
||||
import { changeSetting } from 'flavours/glitch/actions/settings';
|
||||
import { useEmoji } from "flavours/glitch/actions/emojis";
|
||||
import { changeSetting } from "flavours/glitch/actions/settings";
|
||||
|
||||
import EmojiPickerDropdown from '../components/emoji_picker_dropdown';
|
||||
import EmojiPickerDropdown from "../components/emoji_picker_dropdown";
|
||||
|
||||
const perLine = 8;
|
||||
const lines = 2;
|
||||
|
||||
const DEFAULTS = [
|
||||
'+1',
|
||||
'grinning',
|
||||
'kissing_heart',
|
||||
'heart_eyes',
|
||||
'laughing',
|
||||
'stuck_out_tongue_winking_eye',
|
||||
'sweat_smile',
|
||||
'joy',
|
||||
'yum',
|
||||
'disappointed',
|
||||
'thinking_face',
|
||||
'weary',
|
||||
'sob',
|
||||
'sunglasses',
|
||||
'heart',
|
||||
'ok_hand',
|
||||
"+1",
|
||||
"grinning",
|
||||
"kissing_heart",
|
||||
"heart_eyes",
|
||||
"laughing",
|
||||
"stuck_out_tongue_winking_eye",
|
||||
"sweat_smile",
|
||||
"joy",
|
||||
"yum",
|
||||
"disappointed",
|
||||
"thinking_face",
|
||||
"weary",
|
||||
"sob",
|
||||
"sunglasses",
|
||||
"heart",
|
||||
"ok_hand",
|
||||
];
|
||||
|
||||
const getFrequentlyUsedEmojis = createSelector([
|
||||
state => state.getIn(['settings', 'frequentlyUsedEmojis'], ImmutableMap()),
|
||||
state => state.getIn(["settings", "frequentlyUsedEmojis"], ImmutableMap()),
|
||||
], emojiCounters => {
|
||||
let emojis = emojiCounters
|
||||
.keySeq()
|
||||
@@ -48,10 +48,10 @@ const getFrequentlyUsedEmojis = createSelector([
|
||||
});
|
||||
|
||||
const getCustomEmojis = createSelector([
|
||||
state => state.get('custom_emojis'),
|
||||
], emojis => emojis.filter(e => e.get('visible_in_picker')).sort((a, b) => {
|
||||
const aShort = a.get('shortcode').toLowerCase();
|
||||
const bShort = b.get('shortcode').toLowerCase();
|
||||
state => state.get("custom_emojis"),
|
||||
], emojis => emojis.filter(e => e.get("visible_in_picker")).sort((a, b) => {
|
||||
const aShort = a.get("shortcode").toLowerCase();
|
||||
const bShort = b.get("shortcode").toLowerCase();
|
||||
|
||||
if (aShort < bShort) {
|
||||
return -1;
|
||||
@@ -64,17 +64,17 @@ const getCustomEmojis = createSelector([
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
custom_emojis: getCustomEmojis(state),
|
||||
skinTone: state.getIn(['settings', 'skinTone']),
|
||||
skinTone: state.getIn(["settings", "skinTone"]),
|
||||
frequentlyUsedEmojis: getFrequentlyUsedEmojis(state),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch, { onPickEmoji }) => ({
|
||||
onSkinTone: skinTone => {
|
||||
dispatch(changeSetting(['skinTone'], skinTone));
|
||||
dispatch(changeSetting(["skinTone"], skinTone));
|
||||
},
|
||||
|
||||
onPickEmoji: emoji => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks -- this is not a react hook
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
dispatch(useEmoji(emoji));
|
||||
|
||||
if (onPickEmoji) {
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl } from "react-intl";
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { openModal } from 'flavours/glitch/actions/modal';
|
||||
import { logOut } from 'flavours/glitch/utils/log_out';
|
||||
import { openModal } from "flavours/glitch/actions/modal";
|
||||
import { logOut } from "flavours/glitch/utils/log_out";
|
||||
|
||||
import Header from '../components/header';
|
||||
import Header from "../components/header";
|
||||
|
||||
const messages = defineMessages({
|
||||
logoutMessage: { id: 'confirmations.logout.message', defaultMessage: 'Are you sure you want to log out?' },
|
||||
logoutConfirm: { id: 'confirmations.logout.confirm', defaultMessage: 'Log out' },
|
||||
logoutMessage: { id: "confirmations.logout.message", defaultMessage: "Are you sure you want to log out?" },
|
||||
logoutConfirm: { id: "confirmations.logout.confirm", defaultMessage: "Log out" },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
columns: state.getIn(['settings', 'columns']),
|
||||
unreadNotifications: state.getIn(['notifications', 'unread']),
|
||||
showNotificationsBadge: state.getIn(['local_settings', 'notifications', 'tab_badge']),
|
||||
columns: state.getIn(["settings", "columns"]),
|
||||
unreadNotifications: state.getIn(["notifications", "unread"]),
|
||||
showNotificationsBadge: state.getIn(["local_settings", "notifications", "tab_badge"]),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -24,11 +24,11 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
onSettingsClick (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
dispatch(openModal({ modalType: 'SETTINGS', modalProps: {} }));
|
||||
dispatch(openModal({ modalType: "SETTINGS", modalProps: {} }));
|
||||
},
|
||||
onLogout () {
|
||||
dispatch(openModal({
|
||||
modalType: 'CONFIRM',
|
||||
modalType: "CONFIRM",
|
||||
modalProps: {
|
||||
message: intl.formatMessage(messages.logoutMessage),
|
||||
confirm: intl.formatMessage(messages.logoutConfirm),
|
||||
|
||||
+9
-9
@@ -1,14 +1,14 @@
|
||||
import { Map as ImmutableMap } from 'immutable';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { Map as ImmutableMap } from "immutable";
|
||||
import { connect } from "react-redux";
|
||||
import { createSelector } from "reselect";
|
||||
|
||||
import { changeComposeLanguage } from 'flavours/glitch/actions/compose';
|
||||
import { useLanguage } from 'flavours/glitch/actions/languages';
|
||||
import { changeComposeLanguage } from "flavours/glitch/actions/compose";
|
||||
import { useLanguage } from "flavours/glitch/actions/languages";
|
||||
|
||||
import LanguageDropdown from '../components/language_dropdown';
|
||||
import LanguageDropdown from "../components/language_dropdown";
|
||||
|
||||
const getFrequentlyUsedLanguages = createSelector([
|
||||
state => state.getIn(['settings', 'frequentlyUsedLanguages'], ImmutableMap()),
|
||||
state => state.getIn(["settings", "frequentlyUsedLanguages"], ImmutableMap()),
|
||||
], languageCounters => (
|
||||
languageCounters.keySeq()
|
||||
.sort((a, b) => languageCounters.get(a) - languageCounters.get(b))
|
||||
@@ -18,7 +18,7 @@ const getFrequentlyUsedLanguages = createSelector([
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
frequentlyUsedLanguages: getFrequentlyUsedLanguages(state),
|
||||
value: state.getIn(['compose', 'language']),
|
||||
value: state.getIn(["compose", "language"]),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
@@ -28,7 +28,7 @@ const mapDispatchToProps = dispatch => ({
|
||||
},
|
||||
|
||||
onClose (value) {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks -- this is not a react hook
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
dispatch(useLanguage(value));
|
||||
},
|
||||
|
||||
|
||||
+10
-10
@@ -1,28 +1,28 @@
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl } from "react-intl";
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { openModal } from 'flavours/glitch/actions/modal';
|
||||
import { me } from 'flavours/glitch/initial_state';
|
||||
import { logOut } from 'flavours/glitch/utils/log_out';
|
||||
import { openModal } from "flavours/glitch/actions/modal";
|
||||
import { me } from "flavours/glitch/initial_state";
|
||||
import { logOut } from "flavours/glitch/utils/log_out";
|
||||
|
||||
import NavigationBar from '../components/navigation_bar';
|
||||
import NavigationBar from "../components/navigation_bar";
|
||||
|
||||
const messages = defineMessages({
|
||||
logoutMessage: { id: 'confirmations.logout.message', defaultMessage: 'Are you sure you want to log out?' },
|
||||
logoutConfirm: { id: 'confirmations.logout.confirm', defaultMessage: 'Log out' },
|
||||
logoutMessage: { id: "confirmations.logout.message", defaultMessage: "Are you sure you want to log out?" },
|
||||
logoutConfirm: { id: "confirmations.logout.confirm", defaultMessage: "Log out" },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
account: state.getIn(['accounts', me]),
|
||||
account: state.getIn(["accounts", me]),
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
onLogout () {
|
||||
dispatch(openModal({
|
||||
modalType: 'CONFIRM',
|
||||
modalType: "CONFIRM",
|
||||
modalProps: {
|
||||
message: intl.formatMessage(messages.logoutMessage),
|
||||
confirm: intl.formatMessage(messages.logoutConfirm),
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import {
|
||||
changeComposeAdvancedOption,
|
||||
changeComposeContentType,
|
||||
addPoll,
|
||||
removePoll,
|
||||
} from 'flavours/glitch/actions/compose';
|
||||
import { openModal } from 'flavours/glitch/actions/modal';
|
||||
} from "flavours/glitch/actions/compose";
|
||||
import { openModal } from "flavours/glitch/actions/modal";
|
||||
|
||||
import Options from '../components/options';
|
||||
import Options from "../components/options";
|
||||
|
||||
function mapStateToProps (state) {
|
||||
const poll = state.getIn(['compose', 'poll']);
|
||||
const media = state.getIn(['compose', 'media_attachments']);
|
||||
const pending_media = state.getIn(['compose', 'pending_media_attachments']);
|
||||
const poll = state.getIn(["compose", "poll"]);
|
||||
const media = state.getIn(["compose", "media_attachments"]);
|
||||
const pending_media = state.getIn(["compose", "pending_media_attachments"]);
|
||||
return {
|
||||
acceptContentTypes: state.getIn(['media_attachments', 'accept_content_types']).toArray().join(','),
|
||||
resetFileKey: state.getIn(['compose', 'resetFileKey']),
|
||||
acceptContentTypes: state.getIn(["media_attachments", "accept_content_types"]).toArray().join(","),
|
||||
resetFileKey: state.getIn(["compose", "resetFileKey"]),
|
||||
hasPoll: !!poll,
|
||||
allowMedia: !poll && (media ? media.size + pending_media < 4 && !media.some(item => ['video', 'audio'].includes(item.get('type'))) : pending_media < 4),
|
||||
allowMedia: !poll && (media ? media.size + pending_media < 4 && !media.some(item => ["video", "audio"].includes(item.get("type"))) : pending_media < 4),
|
||||
allowPoll: !(media && !!media.size),
|
||||
showContentTypeChoice: state.getIn(['local_settings', 'show_content_type_choice']),
|
||||
contentType: state.getIn(['compose', 'content_type']),
|
||||
showContentTypeChoice: state.getIn(["local_settings", "show_content_type_choice"]),
|
||||
contentType: state.getIn(["compose", "content_type"]),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
onTogglePoll() {
|
||||
dispatch((_, getState) => {
|
||||
if (getState().getIn(['compose', 'poll'])) {
|
||||
if (getState().getIn(["compose", "poll"])) {
|
||||
dispatch(removePoll());
|
||||
} else {
|
||||
dispatch(addPoll());
|
||||
@@ -47,7 +47,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
onDoodleOpen() {
|
||||
dispatch(openModal({
|
||||
modalType: 'DOODLE',
|
||||
modalType: "DOODLE",
|
||||
modalProps: { noEsc: true, noClose: true },
|
||||
}));
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import {
|
||||
addPollOption,
|
||||
@@ -8,16 +8,16 @@ import {
|
||||
clearComposeSuggestions,
|
||||
fetchComposeSuggestions,
|
||||
selectComposeSuggestion,
|
||||
} from 'flavours/glitch/actions/compose';
|
||||
} from "flavours/glitch/actions/compose";
|
||||
|
||||
import PollForm from '../components/poll_form';
|
||||
import PollForm from "../components/poll_form";
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
suggestions: state.getIn(['compose', 'suggestions']),
|
||||
options: state.getIn(['compose', 'poll', 'options']),
|
||||
lang: state.getIn(['compose', 'language']),
|
||||
expiresIn: state.getIn(['compose', 'poll', 'expires_in']),
|
||||
isMultiple: state.getIn(['compose', 'poll', 'multiple']),
|
||||
suggestions: state.getIn(["compose", "suggestions"]),
|
||||
options: state.getIn(["compose", "poll", "options"]),
|
||||
lang: state.getIn(["compose", "language"]),
|
||||
expiresIn: state.getIn(["compose", "poll", "expires_in"]),
|
||||
isMultiple: state.getIn(["compose", "poll", "multiple"]),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
||||
+7
-7
@@ -1,13 +1,13 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { changeComposeVisibility } from 'flavours/glitch/actions/compose';
|
||||
import { openModal, closeModal } from 'flavours/glitch/actions/modal';
|
||||
import { isUserTouching } from 'flavours/glitch/is_mobile';
|
||||
import { changeComposeVisibility } from "flavours/glitch/actions/compose";
|
||||
import { openModal, closeModal } from "flavours/glitch/actions/modal";
|
||||
import { isUserTouching } from "flavours/glitch/is_mobile";
|
||||
|
||||
import PrivacyDropdown from '../components/privacy_dropdown';
|
||||
import PrivacyDropdown from "../components/privacy_dropdown";
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
value: state.getIn(['compose', 'privacy']),
|
||||
value: state.getIn(["compose", "privacy"]),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
@@ -18,7 +18,7 @@ const mapDispatchToProps = dispatch => ({
|
||||
|
||||
isUserTouching,
|
||||
onModalOpen: props => dispatch(openModal({
|
||||
modalType: 'ACTIONS',
|
||||
modalType: "ACTIONS",
|
||||
modalProps: props,
|
||||
})),
|
||||
onModalClose: () => dispatch(closeModal({
|
||||
|
||||
+6
-6
@@ -1,21 +1,21 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { cancelReplyCompose } from 'flavours/glitch/actions/compose';
|
||||
import { cancelReplyCompose } from "flavours/glitch/actions/compose";
|
||||
|
||||
import ReplyIndicator from '../components/reply_indicator';
|
||||
import ReplyIndicator from "../components/reply_indicator";
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const mapStateToProps = state => {
|
||||
let statusId = state.getIn(['compose', 'id'], null);
|
||||
let statusId = state.getIn(["compose", "id"], null);
|
||||
let editing = true;
|
||||
|
||||
if (statusId === null) {
|
||||
statusId = state.getIn(['compose', 'in_reply_to']);
|
||||
statusId = state.getIn(["compose", "in_reply_to"]);
|
||||
editing = false;
|
||||
}
|
||||
|
||||
return {
|
||||
status: state.getIn(['statuses', statusId]),
|
||||
status: state.getIn(["statuses", statusId]),
|
||||
editing,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import {
|
||||
changeSearch,
|
||||
@@ -8,14 +8,14 @@ import {
|
||||
openURL,
|
||||
clickSearchResult,
|
||||
forgetSearchResult,
|
||||
} from 'flavours/glitch/actions/search';
|
||||
} from "flavours/glitch/actions/search";
|
||||
|
||||
import Search from '../components/search';
|
||||
import Search from "../components/search";
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
value: state.getIn(['search', 'value']),
|
||||
submitted: state.getIn(['search', 'submitted']),
|
||||
recent: state.getIn(['search', 'recent']).reverse(),
|
||||
value: state.getIn(["search", "value"]),
|
||||
submitted: state.getIn(["search", "submitted"]),
|
||||
recent: state.getIn(["search", "recent"]).reverse(),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
||||
+8
-8
@@ -1,20 +1,20 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { expandSearch } from 'flavours/glitch/actions/search';
|
||||
import { fetchSuggestions, dismissSuggestion } from 'flavours/glitch/actions/suggestions';
|
||||
import { expandSearch } from "flavours/glitch/actions/search";
|
||||
import { fetchSuggestions, dismissSuggestion } from "flavours/glitch/actions/suggestions";
|
||||
|
||||
import SearchResults from '../components/search_results';
|
||||
import SearchResults from "../components/search_results";
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
results: state.getIn(['search', 'results']),
|
||||
suggestions: state.getIn(['suggestions', 'items']),
|
||||
searchTerm: state.getIn(['search', 'searchTerm']),
|
||||
results: state.getIn(["search", "results"]),
|
||||
suggestions: state.getIn(["suggestions", "items"]),
|
||||
searchTerm: state.getIn(["search", "searchTerm"]),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
fetchSuggestions: () => dispatch(fetchSuggestions()),
|
||||
expandSearch: type => dispatch(expandSearch(type)),
|
||||
dismissSuggestion: account => dispatch(dismissSuggestion(account.get('id'))),
|
||||
dismissSuggestion: account => dispatch(dismissSuggestion(account.get("id"))),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SearchResults);
|
||||
|
||||
+17
-17
@@ -1,32 +1,32 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||
import { injectIntl, defineMessages, FormattedMessage } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { changeComposeSensitivity } from 'flavours/glitch/actions/compose';
|
||||
import { changeComposeSensitivity } from "flavours/glitch/actions/compose";
|
||||
|
||||
const messages = defineMessages({
|
||||
marked: {
|
||||
id: 'compose_form.sensitive.marked',
|
||||
defaultMessage: '{count, plural, one {Media is marked as sensitive} other {Media is marked as sensitive}}',
|
||||
id: "compose_form.sensitive.marked",
|
||||
defaultMessage: "{count, plural, one {Media is marked as sensitive} other {Media is marked as sensitive}}",
|
||||
},
|
||||
unmarked: {
|
||||
id: 'compose_form.sensitive.unmarked',
|
||||
defaultMessage: '{count, plural, one {Media is not marked as sensitive} other {Media is not marked as sensitive}}',
|
||||
id: "compose_form.sensitive.unmarked",
|
||||
defaultMessage: "{count, plural, one {Media is not marked as sensitive} other {Media is not marked as sensitive}}",
|
||||
},
|
||||
});
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const spoilersAlwaysOn = state.getIn(['local_settings', 'always_show_spoilers_field']);
|
||||
const spoilerText = state.getIn(['compose', 'spoiler_text']);
|
||||
const spoilersAlwaysOn = state.getIn(["local_settings", "always_show_spoilers_field"]);
|
||||
const spoilerText = state.getIn(["compose", "spoiler_text"]);
|
||||
return {
|
||||
active: state.getIn(['compose', 'sensitive']) || (spoilersAlwaysOn && spoilerText && spoilerText.length > 0),
|
||||
disabled: state.getIn(['compose', 'spoiler']),
|
||||
mediaCount: state.getIn(['compose', 'media_attachments']).size,
|
||||
active: state.getIn(["compose", "sensitive"]) || (spoilersAlwaysOn && spoilerText && spoilerText.length > 0),
|
||||
disabled: state.getIn(["compose", "spoiler"]),
|
||||
mediaCount: state.getIn(["compose", "media_attachments"]).size,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -53,7 +53,7 @@ class SensitiveButton extends PureComponent {
|
||||
|
||||
return (
|
||||
<div className='compose-form__sensitive-button'>
|
||||
<label className={classNames('icon-button', { active })} title={intl.formatMessage(active ? messages.marked : messages.unmarked, { count: mediaCount })}>
|
||||
<label className={classNames("icon-button", { active })} title={intl.formatMessage(active ? messages.marked : messages.unmarked, { count: mediaCount })}>
|
||||
<input
|
||||
name='mark-sensitive'
|
||||
type='checkbox'
|
||||
@@ -62,7 +62,7 @@ class SensitiveButton extends PureComponent {
|
||||
disabled={disabled}
|
||||
/>
|
||||
|
||||
<span className={classNames('checkbox', { active })} />
|
||||
<span className={classNames("checkbox", { active })} />
|
||||
|
||||
<FormattedMessage
|
||||
id='compose_form.sensitive.hide'
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { undoUploadCompose, initMediaEditModal, submitCompose } from 'flavours/glitch/actions/compose';
|
||||
import { undoUploadCompose, initMediaEditModal, submitCompose } from "flavours/glitch/actions/compose";
|
||||
|
||||
import Upload from '../components/upload';
|
||||
import Upload from "../components/upload";
|
||||
|
||||
const mapStateToProps = (state, { id }) => ({
|
||||
media: state.getIn(['compose', 'media_attachments']).find(item => item.get('id') === id),
|
||||
media: state.getIn(["compose", "media_attachments"]).find(item => item.get("id") === id),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import UploadForm from '../components/upload_form';
|
||||
import UploadForm from "../components/upload_form";
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
mediaIds: state.getIn(['compose', 'media_attachments']).map(item => item.get('id')),
|
||||
mediaIds: state.getIn(["compose", "media_attachments"]).map(item => item.get("id")),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(UploadForm);
|
||||
|
||||
+5
-5
@@ -1,11 +1,11 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import UploadProgress from '../components/upload_progress';
|
||||
import UploadProgress from "../components/upload_progress";
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
active: state.getIn(['compose', 'is_uploading']),
|
||||
progress: state.getIn(['compose', 'progress']),
|
||||
isProcessing: state.getIn(['compose', 'is_processing']),
|
||||
active: state.getIn(["compose", "is_uploading"]),
|
||||
progress: state.getIn(["compose", "progress"]),
|
||||
isProcessing: state.getIn(["compose", "is_processing"]),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(UploadProgress);
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { me } from 'flavours/glitch/initial_state';
|
||||
import { privacyPolicyLink } from 'flavours/glitch/utils/backend_links';
|
||||
import { HASHTAG_PATTERN_REGEX } from 'flavours/glitch/utils/hashtags';
|
||||
import { me } from "flavours/glitch/initial_state";
|
||||
import { privacyPolicyLink } from "flavours/glitch/utils/backend_links";
|
||||
import { HASHTAG_PATTERN_REGEX } from "flavours/glitch/utils/hashtags";
|
||||
|
||||
import Warning from '../components/warning';
|
||||
import Warning from "../components/warning";
|
||||
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
needsLockWarning: state.getIn(['compose', 'privacy']) === 'private' && !state.getIn(['accounts', me, 'locked']),
|
||||
hashtagWarning: state.getIn(['compose', 'privacy']) !== 'public' && HASHTAG_PATTERN_REGEX.test(state.getIn(['compose', 'text'])),
|
||||
directMessageWarning: state.getIn(['compose', 'privacy']) === 'direct',
|
||||
needsLockWarning: state.getIn(["compose", "privacy"]) === "private" && !state.getIn(["accounts", me, "locked"]),
|
||||
hashtagWarning: state.getIn(["compose", "privacy"]) !== "public" && HASHTAG_PATTERN_REGEX.test(state.getIn(["compose", "text"])),
|
||||
directMessageWarning: state.getIn(["compose", "privacy"]) === "direct",
|
||||
});
|
||||
|
||||
const WarningWrapper = ({ needsLockWarning, hashtagWarning, directMessageWarning }) => {
|
||||
@@ -29,7 +29,7 @@ const WarningWrapper = ({ needsLockWarning, hashtagWarning, directMessageWarning
|
||||
if (directMessageWarning) {
|
||||
const message = (
|
||||
<span>
|
||||
<FormattedMessage id='compose_form.encryption_warning' defaultMessage='Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.' /> {!!privacyPolicyLink && <a href={privacyPolicyLink} target='_blank'><FormattedMessage id='compose_form.direct_message_warning_learn_more' defaultMessage='Learn more' /></a>}
|
||||
<FormattedMessage id='compose_form.encryption_warning' defaultMessage='Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.' /> {!!privacyPolicyLink && <a href={privacyPolicyLink} target='_blank' rel="noreferrer"><FormattedMessage id='compose_form.direct_message_warning_learn_more' defaultMessage='Learn more' /></a>}
|
||||
</span>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { injectIntl, defineMessages } from 'react-intl';
|
||||
import { injectIntl, defineMessages } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import classNames from "classnames";
|
||||
import { Helmet } from "react-helmet";
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import spring from 'react-motion/lib/spring';
|
||||
import spring from "react-motion/lib/spring";
|
||||
|
||||
import { mountCompose, unmountCompose, cycleElefriendCompose } from 'flavours/glitch/actions/compose';
|
||||
import Column from 'flavours/glitch/components/column';
|
||||
import { mascot } from 'flavours/glitch/initial_state';
|
||||
import { mountCompose, unmountCompose, cycleElefriendCompose } from "flavours/glitch/actions/compose";
|
||||
import Column from "flavours/glitch/components/column";
|
||||
import { mascot } from "flavours/glitch/initial_state";
|
||||
|
||||
import Motion from '../ui/util/optional_motion';
|
||||
import Motion from "../ui/util/optional_motion";
|
||||
|
||||
import ComposeFormContainer from './containers/compose_form_container';
|
||||
import HeaderContainer from './containers/header_container';
|
||||
import NavigationContainer from './containers/navigation_container';
|
||||
import SearchContainer from './containers/search_container';
|
||||
import SearchResultsContainer from './containers/search_results_container';
|
||||
import ComposeFormContainer from "./containers/compose_form_container";
|
||||
import HeaderContainer from "./containers/header_container";
|
||||
import NavigationContainer from "./containers/navigation_container";
|
||||
import SearchContainer from "./containers/search_container";
|
||||
import SearchResultsContainer from "./containers/search_results_container";
|
||||
|
||||
const messages = defineMessages({
|
||||
compose: { id: 'navigation_bar.compose', defaultMessage: 'Compose new post' },
|
||||
compose: { id: "navigation_bar.compose", defaultMessage: "Compose new post" },
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
elefriend: state.getIn(['compose', 'elefriend']),
|
||||
showSearch: ownProps.multiColumn ? state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']) : false,
|
||||
elefriend: state.getIn(["compose", "elefriend"]),
|
||||
showSearch: ownProps.multiColumn ? state.getIn(["search", "submitted"]) && !state.getIn(["search", "hidden"]) : false,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
@@ -73,7 +73,7 @@ class Compose extends PureComponent {
|
||||
onClickElefriend,
|
||||
showSearch,
|
||||
} = this.props;
|
||||
const computedClass = classNames('drawer', `mbstobon-${elefriend}`);
|
||||
const computedClass = classNames("drawer", `mbstobon-${elefriend}`);
|
||||
|
||||
if (multiColumn) {
|
||||
return (
|
||||
@@ -95,7 +95,7 @@ class Compose extends PureComponent {
|
||||
|
||||
<Motion defaultStyle={{ x: -100 }} style={{ x: spring(showSearch ? 0 : -100, { stiffness: 210, damping: 20 }) }}>
|
||||
{({ x }) => (
|
||||
<div className='drawer__inner darker' style={{ transform: `translateX(${x}%)`, visibility: x === -100 ? 'hidden' : 'visible' }}>
|
||||
<div className='drawer__inner darker' style={{ transform: `translateX(${x}%)`, visibility: x === -100 ? "hidden" : "visible" }}>
|
||||
<SearchResultsContainer />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { urlRegex } from './url_regex';
|
||||
import { urlRegex } from "./url_regex";
|
||||
|
||||
const urlPlaceholder = '$2xxxxxxxxxxxxxxxxxxxxxxx';
|
||||
const urlPlaceholder = "$2xxxxxxxxxxxxxxxxxxxxxxx";
|
||||
|
||||
export function countableText(inputText) {
|
||||
return inputText
|
||||
.replace(urlRegex, urlPlaceholder)
|
||||
.replace(/(^|[^/\w])@(([a-z0-9_]+)@[a-z0-9.-]+[a-z0-9]+)/ig, '$1@$3');
|
||||
.replace(/(^|[^/\w])@(([a-z0-9_]+)@[a-z0-9.-]+[a-z0-9]+)/ig, "$1@$3");
|
||||
}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import regexSupplant from 'twitter-text/dist/lib/regexSupplant';
|
||||
import validDomain from 'twitter-text/dist/regexp/validDomain';
|
||||
import validPortNumber from 'twitter-text/dist/regexp/validPortNumber';
|
||||
import validUrlPath from 'twitter-text/dist/regexp/validUrlPath';
|
||||
import validUrlPrecedingChars from 'twitter-text/dist/regexp/validUrlPrecedingChars';
|
||||
import validUrlQueryChars from 'twitter-text/dist/regexp/validUrlQueryChars';
|
||||
import validUrlQueryEndingChars from 'twitter-text/dist/regexp/validUrlQueryEndingChars';
|
||||
import regexSupplant from "twitter-text/dist/lib/regexSupplant";
|
||||
import validDomain from "twitter-text/dist/regexp/validDomain";
|
||||
import validPortNumber from "twitter-text/dist/regexp/validPortNumber";
|
||||
import validUrlPath from "twitter-text/dist/regexp/validUrlPath";
|
||||
import validUrlPrecedingChars from "twitter-text/dist/regexp/validUrlPrecedingChars";
|
||||
import validUrlQueryChars from "twitter-text/dist/regexp/validUrlQueryChars";
|
||||
import validUrlQueryEndingChars from "twitter-text/dist/regexp/validUrlQueryEndingChars";
|
||||
|
||||
// The difference with twitter-text's extractURL is that the protocol isn't
|
||||
// optional.
|
||||
|
||||
export const urlRegex = regexSupplant(
|
||||
'(' + // $1 URL
|
||||
'(#{validUrlPrecedingChars})' + // $2
|
||||
'(https?:\\/\\/)' + // $3 Protocol
|
||||
'(#{validDomain})' + // $4 Domain(s)
|
||||
'(?::(#{validPortNumber}))?' + // $5 Port number (optional)
|
||||
'(\\/#{validUrlPath}*)?' + // $6 URL Path
|
||||
'(\\?#{validUrlQueryChars}*#{validUrlQueryEndingChars})?' + // $7 Query String
|
||||
')',
|
||||
"(" + // $1 URL
|
||||
"(#{validUrlPrecedingChars})" + // $2
|
||||
"(https?:\\/\\/)" + // $3 Protocol
|
||||
"(#{validDomain})" + // $4 Domain(s)
|
||||
"(?::(#{validPortNumber}))?" + // $5 Port number (optional)
|
||||
"(\\/#{validUrlPath}*)?" + // $6 URL Path
|
||||
"(\\?#{validUrlQueryChars}*#{validUrlQueryEndingChars})?" + // $7 Query String
|
||||
")",
|
||||
{
|
||||
validUrlPrecedingChars,
|
||||
validDomain,
|
||||
@@ -26,5 +26,5 @@ export const urlRegex = regexSupplant(
|
||||
validUrlQueryChars,
|
||||
validUrlQueryEndingChars,
|
||||
},
|
||||
'gi',
|
||||
"gi",
|
||||
);
|
||||
|
||||
+10
-10
@@ -1,17 +1,17 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
|
||||
import SettingToggle from 'flavours/glitch/features/notifications/components/setting_toggle';
|
||||
import SettingToggle from "flavours/glitch/features/notifications/components/setting_toggle";
|
||||
|
||||
import SettingText from '../../../components/setting_text';
|
||||
import SettingText from "../../../components/setting_text";
|
||||
|
||||
const messages = defineMessages({
|
||||
filter_regex: { id: 'home.column_settings.filter_regex', defaultMessage: 'Filter out by regular expressions' },
|
||||
settings: { id: 'home.settings', defaultMessage: 'Column settings' },
|
||||
filter_regex: { id: "home.column_settings.filter_regex", defaultMessage: "Filter out by regular expressions" },
|
||||
settings: { id: "home.settings", defaultMessage: "Column settings" },
|
||||
});
|
||||
|
||||
class ColumnSettings extends PureComponent {
|
||||
@@ -30,13 +30,13 @@ class ColumnSettings extends PureComponent {
|
||||
<span className='column-settings__section'><FormattedMessage id='home.column_settings.basic' defaultMessage='Basic' /></span>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle settings={settings} settingPath={['conversations']} onChange={onChange} label={<FormattedMessage id='direct.group_by_conversations' defaultMessage='Group by conversation' />} />
|
||||
<SettingToggle settings={settings} settingPath={["conversations"]} onChange={onChange} label={<FormattedMessage id='direct.group_by_conversations' defaultMessage='Group by conversation' />} />
|
||||
</div>
|
||||
|
||||
<span className='column-settings__section'><FormattedMessage id='home.column_settings.advanced' defaultMessage='Advanced' /></span>
|
||||
|
||||
<div className='column-settings__row'>
|
||||
<SettingText settings={settings} settingPath={['regex', 'body']} onChange={onChange} label={intl.formatMessage(messages.filter_regex)} />
|
||||
<SettingText settings={settings} settingPath={["regex", "body"]} onChange={onChange} label={intl.formatMessage(messages.filter_regex)} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
+38
-36
@@ -1,31 +1,31 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import { HotKeys } from 'react-hotkeys';
|
||||
import { HotKeys } from "react-hotkeys";
|
||||
|
||||
import AttachmentList from 'flavours/glitch/components/attachment_list';
|
||||
import AvatarComposite from 'flavours/glitch/components/avatar_composite';
|
||||
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||
import Permalink from 'flavours/glitch/components/permalink';
|
||||
import { RelativeTimestamp } from 'flavours/glitch/components/relative_timestamp';
|
||||
import StatusContent from 'flavours/glitch/components/status_content';
|
||||
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
|
||||
import { autoPlayGif } from 'flavours/glitch/initial_state';
|
||||
import AttachmentList from "flavours/glitch/components/attachment_list";
|
||||
import AvatarComposite from "flavours/glitch/components/avatar_composite";
|
||||
import { IconButton } from "flavours/glitch/components/icon_button";
|
||||
import Permalink from "flavours/glitch/components/permalink";
|
||||
import { RelativeTimestamp } from "flavours/glitch/components/relative_timestamp";
|
||||
import StatusContent from "flavours/glitch/components/status_content";
|
||||
import DropdownMenuContainer from "flavours/glitch/containers/dropdown_menu_container";
|
||||
import { autoPlayGif } from "flavours/glitch/initial_state";
|
||||
|
||||
const messages = defineMessages({
|
||||
more: { id: 'status.more', defaultMessage: 'More' },
|
||||
open: { id: 'conversation.open', defaultMessage: 'View conversation' },
|
||||
reply: { id: 'status.reply', defaultMessage: 'Reply' },
|
||||
markAsRead: { id: 'conversation.mark_as_read', defaultMessage: 'Mark as read' },
|
||||
delete: { id: 'conversation.delete', defaultMessage: 'Delete conversation' },
|
||||
muteConversation: { id: 'status.mute_conversation', defaultMessage: 'Mute conversation' },
|
||||
unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },
|
||||
more: { id: "status.more", defaultMessage: "More" },
|
||||
open: { id: "conversation.open", defaultMessage: "View conversation" },
|
||||
reply: { id: "status.reply", defaultMessage: "Reply" },
|
||||
markAsRead: { id: "conversation.mark_as_read", defaultMessage: "Mark as read" },
|
||||
delete: { id: "conversation.delete", defaultMessage: "Delete conversation" },
|
||||
muteConversation: { id: "status.mute_conversation", defaultMessage: "Mute conversation" },
|
||||
unmuteConversation: { id: "status.unmute_conversation", defaultMessage: "Unmute conversation" },
|
||||
});
|
||||
|
||||
class Conversation extends ImmutablePureComponent {
|
||||
@@ -54,14 +54,16 @@ class Conversation extends ImmutablePureComponent {
|
||||
parseClick = (e, destination) => {
|
||||
const { router } = this.context;
|
||||
const { lastStatus, unread, markRead } = this.props;
|
||||
if (!router) return;
|
||||
if (!router) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.button === 0 && !(e.ctrlKey || e.altKey || e.metaKey)) {
|
||||
if (destination === undefined) {
|
||||
if (unread) {
|
||||
markRead();
|
||||
}
|
||||
destination = `/statuses/${lastStatus.get('id')}`;
|
||||
destination = `/statuses/${lastStatus.get("id")}`;
|
||||
}
|
||||
router.history.push(destination);
|
||||
e.preventDefault();
|
||||
@@ -73,11 +75,11 @@ class Conversation extends ImmutablePureComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
const emojis = currentTarget.querySelectorAll('.custom-emoji');
|
||||
const emojis = currentTarget.querySelectorAll(".custom-emoji");
|
||||
|
||||
for (var i = 0; i < emojis.length; i++) {
|
||||
let emoji = emojis[i];
|
||||
emoji.src = emoji.getAttribute('data-original');
|
||||
emoji.src = emoji.getAttribute("data-original");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -86,11 +88,11 @@ class Conversation extends ImmutablePureComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
const emojis = currentTarget.querySelectorAll('.custom-emoji');
|
||||
const emojis = currentTarget.querySelectorAll(".custom-emoji");
|
||||
|
||||
for (var i = 0; i < emojis.length; i++) {
|
||||
let emoji = emojis[i];
|
||||
emoji.src = emoji.getAttribute('data-static');
|
||||
emoji.src = emoji.getAttribute("data-static");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -105,7 +107,7 @@ class Conversation extends ImmutablePureComponent {
|
||||
markRead();
|
||||
}
|
||||
|
||||
this.context.router.history.push(`/@${lastStatus.getIn(['account', 'acct'])}/${lastStatus.get('id')}`);
|
||||
this.context.router.history.push(`/@${lastStatus.getIn(["account", "acct"])}/${lastStatus.get("id")}`);
|
||||
};
|
||||
|
||||
handleMarkAsRead = () => {
|
||||
@@ -135,7 +137,7 @@ class Conversation extends ImmutablePureComponent {
|
||||
handleShowMore = () => {
|
||||
this.props.onToggleHidden(this.props.lastStatus);
|
||||
|
||||
if (this.props.lastStatus.get('spoiler_text')) {
|
||||
if (this.props.lastStatus.get("spoiler_text")) {
|
||||
this.setExpansion(!this.state.isExpanded);
|
||||
}
|
||||
};
|
||||
@@ -151,14 +153,14 @@ class Conversation extends ImmutablePureComponent {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isExpanded = this.props.settings.getIn(['content_warnings', 'shared_state']) ? !lastStatus.get('hidden') : this.state.isExpanded;
|
||||
const isExpanded = this.props.settings.getIn(["content_warnings", "shared_state"]) ? !lastStatus.get("hidden") : this.state.isExpanded;
|
||||
|
||||
const menu = [
|
||||
{ text: intl.formatMessage(messages.open), action: this.handleClick },
|
||||
null,
|
||||
];
|
||||
|
||||
menu.push({ text: intl.formatMessage(lastStatus.get('muted') ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMute });
|
||||
menu.push({ text: intl.formatMessage(lastStatus.get("muted") ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMute });
|
||||
|
||||
if (unread) {
|
||||
menu.push({ text: intl.formatMessage(messages.markAsRead), action: this.handleMarkAsRead });
|
||||
@@ -167,7 +169,7 @@ class Conversation extends ImmutablePureComponent {
|
||||
|
||||
menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDelete });
|
||||
|
||||
const names = accounts.map(a => <Permalink to={`/@${a.get('acct')}`} href={a.get('url')} key={a.get('id')} title={a.get('acct')}><bdi><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: a.get('display_name_html') }} /></bdi></Permalink>).reduce((prev, cur) => [prev, ', ', cur]);
|
||||
const names = accounts.map(a => <Permalink to={`/@${a.get("acct")}`} href={a.get("url")} key={a.get("id")} title={a.get("acct")}><bdi><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: a.get("display_name_html") }} /></bdi></Permalink>).reduce((prev, cur) => [prev, ", ", cur]);
|
||||
|
||||
const handlers = {
|
||||
reply: this.handleReply,
|
||||
@@ -178,13 +180,13 @@ class Conversation extends ImmutablePureComponent {
|
||||
};
|
||||
|
||||
let media = null;
|
||||
if (lastStatus.get('media_attachments').size > 0) {
|
||||
media = <AttachmentList compact media={lastStatus.get('media_attachments')} />;
|
||||
if (lastStatus.get("media_attachments").size > 0) {
|
||||
media = <AttachmentList compact media={lastStatus.get("media_attachments")} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<HotKeys handlers={handlers}>
|
||||
<div className={classNames('conversation focusable muted', { 'conversation--unread': unread })} tabIndex={0}>
|
||||
<div className={classNames("conversation focusable muted", { "conversation--unread": unread })} tabIndex={0}>
|
||||
<div className='conversation__avatar' onClick={this.handleClick} role='presentation'>
|
||||
<AvatarComposite accounts={accounts} size={48} />
|
||||
</div>
|
||||
@@ -192,7 +194,7 @@ class Conversation extends ImmutablePureComponent {
|
||||
<div className='conversation__content'>
|
||||
<div className='conversation__content__info'>
|
||||
<div className='conversation__content__relative-time'>
|
||||
{unread && <span className='conversation__unread' />} <RelativeTimestamp timestamp={lastStatus.get('created_at')} />
|
||||
{unread && <span className='conversation__unread' />} <RelativeTimestamp timestamp={lastStatus.get("created_at")} />
|
||||
</div>
|
||||
|
||||
<div className='conversation__content__names' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
||||
|
||||
+11
-11
@@ -1,13 +1,13 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
|
||||
import { debounce } from 'lodash';
|
||||
import { debounce } from "lodash";
|
||||
|
||||
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
||||
import ScrollableList from "flavours/glitch/components/scrollable_list";
|
||||
|
||||
import ConversationContainer from '../containers/conversation_container';
|
||||
import ConversationContainer from "../containers/conversation_container";
|
||||
|
||||
export default class ConversationsList extends ImmutablePureComponent {
|
||||
|
||||
@@ -19,7 +19,7 @@ export default class ConversationsList extends ImmutablePureComponent {
|
||||
onLoadMore: PropTypes.func,
|
||||
};
|
||||
|
||||
getCurrentIndex = id => this.props.conversations.findIndex(x => x.get('id') === id);
|
||||
getCurrentIndex = id => this.props.conversations.findIndex(x => x.get("id") === id);
|
||||
|
||||
handleMoveUp = id => {
|
||||
const elementIndex = this.getCurrentIndex(id) - 1;
|
||||
@@ -52,8 +52,8 @@ export default class ConversationsList extends ImmutablePureComponent {
|
||||
handleLoadOlder = debounce(() => {
|
||||
const last = this.props.conversations.last();
|
||||
|
||||
if (last && last.get('last_status')) {
|
||||
this.props.onLoadMore(last.get('last_status'));
|
||||
if (last && last.get("last_status")) {
|
||||
this.props.onLoadMore(last.get("last_status"));
|
||||
}
|
||||
}, 300, { leading: true });
|
||||
|
||||
@@ -64,8 +64,8 @@ export default class ConversationsList extends ImmutablePureComponent {
|
||||
<ScrollableList {...other} isLoading={isLoading} showLoading={isLoading && conversations.isEmpty()} onLoadMore={onLoadMore && this.handleLoadOlder} ref={this.setRef}>
|
||||
{conversations.map(item => (
|
||||
<ConversationContainer
|
||||
key={item.get('id')}
|
||||
conversationId={item.get('id')}
|
||||
key={item.get("id")}
|
||||
conversationId={item.get("id")}
|
||||
onMoveUp={this.handleMoveUp}
|
||||
onMoveDown={this.handleMoveDown}
|
||||
scrollKey={this.props.scrollKey}
|
||||
|
||||
+5
-5
@@ -1,17 +1,17 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { changeSetting } from 'flavours/glitch/actions/settings';
|
||||
import { changeSetting } from "flavours/glitch/actions/settings";
|
||||
|
||||
import ColumnSettings from '../components/column_settings';
|
||||
import ColumnSettings from "../components/column_settings";
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
settings: state.getIn(['settings', 'direct']),
|
||||
settings: state.getIn(["settings", "direct"]),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
||||
onChange (path, checked) {
|
||||
dispatch(changeSetting(['direct', ...path], checked));
|
||||
dispatch(changeSetting(["direct", ...path], checked));
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
+23
-23
@@ -1,32 +1,32 @@
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl } from "react-intl";
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { replyCompose } from 'flavours/glitch/actions/compose';
|
||||
import { markConversationRead, deleteConversation } from 'flavours/glitch/actions/conversations';
|
||||
import { openModal } from 'flavours/glitch/actions/modal';
|
||||
import { muteStatus, unmuteStatus, hideStatus, revealStatus } from 'flavours/glitch/actions/statuses';
|
||||
import { makeGetStatus } from 'flavours/glitch/selectors';
|
||||
import { replyCompose } from "flavours/glitch/actions/compose";
|
||||
import { markConversationRead, deleteConversation } from "flavours/glitch/actions/conversations";
|
||||
import { openModal } from "flavours/glitch/actions/modal";
|
||||
import { muteStatus, unmuteStatus, hideStatus, revealStatus } from "flavours/glitch/actions/statuses";
|
||||
import { makeGetStatus } from "flavours/glitch/selectors";
|
||||
|
||||
import Conversation from '../components/conversation';
|
||||
import Conversation from "../components/conversation";
|
||||
|
||||
const messages = defineMessages({
|
||||
replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
|
||||
replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
|
||||
replyConfirm: { id: "confirmations.reply.confirm", defaultMessage: "Reply" },
|
||||
replyMessage: { id: "confirmations.reply.message", defaultMessage: "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?" },
|
||||
});
|
||||
|
||||
const mapStateToProps = () => {
|
||||
const getStatus = makeGetStatus();
|
||||
|
||||
return (state, { conversationId }) => {
|
||||
const conversation = state.getIn(['conversations', 'items']).find(x => x.get('id') === conversationId);
|
||||
const lastStatusId = conversation.get('last_status', null);
|
||||
const conversation = state.getIn(["conversations", "items"]).find(x => x.get("id") === conversationId);
|
||||
const lastStatusId = conversation.get("last_status", null);
|
||||
|
||||
return {
|
||||
accounts: conversation.get('accounts').map(accountId => state.getIn(['accounts', accountId], null)),
|
||||
unread: conversation.get('unread'),
|
||||
accounts: conversation.get("accounts").map(accountId => state.getIn(["accounts", accountId], null)),
|
||||
unread: conversation.get("unread"),
|
||||
lastStatus: lastStatusId && getStatus(state, { id: lastStatusId }),
|
||||
settings: state.get('local_settings'),
|
||||
settings: state.get("local_settings"),
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -41,9 +41,9 @@ const mapDispatchToProps = (dispatch, { intl, conversationId }) => ({
|
||||
dispatch((_, getState) => {
|
||||
let state = getState();
|
||||
|
||||
if (state.getIn(['compose', 'text']).trim().length !== 0) {
|
||||
if (state.getIn(["compose", "text"]).trim().length !== 0) {
|
||||
dispatch(openModal({
|
||||
modalType: 'CONFIRM',
|
||||
modalType: "CONFIRM",
|
||||
modalProps: {
|
||||
message: intl.formatMessage(messages.replyMessage),
|
||||
confirm: intl.formatMessage(messages.replyConfirm),
|
||||
@@ -61,18 +61,18 @@ const mapDispatchToProps = (dispatch, { intl, conversationId }) => ({
|
||||
},
|
||||
|
||||
onMute (status) {
|
||||
if (status.get('muted')) {
|
||||
dispatch(unmuteStatus(status.get('id')));
|
||||
if (status.get("muted")) {
|
||||
dispatch(unmuteStatus(status.get("id")));
|
||||
} else {
|
||||
dispatch(muteStatus(status.get('id')));
|
||||
dispatch(muteStatus(status.get("id")));
|
||||
}
|
||||
},
|
||||
|
||||
onToggleHidden (status) {
|
||||
if (status.get('hidden')) {
|
||||
dispatch(revealStatus(status.get('id')));
|
||||
if (status.get("hidden")) {
|
||||
dispatch(revealStatus(status.get("id")));
|
||||
} else {
|
||||
dispatch(hideStatus(status.get('id')));
|
||||
dispatch(hideStatus(status.get("id")));
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
+6
-6
@@ -1,13 +1,13 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { expandConversations } from 'flavours/glitch/actions/conversations';
|
||||
import { expandConversations } from "flavours/glitch/actions/conversations";
|
||||
|
||||
import ConversationsList from '../components/conversations_list';
|
||||
import ConversationsList from "../components/conversations_list";
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
conversations: state.getIn(['conversations', 'items']),
|
||||
isLoading: state.getIn(['conversations', 'isLoading'], true),
|
||||
hasMore: state.getIn(['conversations', 'hasMore'], false),
|
||||
conversations: state.getIn(["conversations", "items"]),
|
||||
isLoading: state.getIn(["conversations", "isLoading"], true),
|
||||
hasMore: state.getIn(["conversations", "hasMore"], false),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Helmet } from "react-helmet";
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
|
||||
import { mountConversations, unmountConversations, expandConversations } from 'flavours/glitch/actions/conversations';
|
||||
import { connectDirectStream } from 'flavours/glitch/actions/streaming';
|
||||
import { expandDirectTimeline } from 'flavours/glitch/actions/timelines';
|
||||
import Column from 'flavours/glitch/components/column';
|
||||
import ColumnHeader from 'flavours/glitch/components/column_header';
|
||||
import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
|
||||
import { addColumn, removeColumn, moveColumn } from "flavours/glitch/actions/columns";
|
||||
import { mountConversations, unmountConversations, expandConversations } from "flavours/glitch/actions/conversations";
|
||||
import { connectDirectStream } from "flavours/glitch/actions/streaming";
|
||||
import { expandDirectTimeline } from "flavours/glitch/actions/timelines";
|
||||
import Column from "flavours/glitch/components/column";
|
||||
import ColumnHeader from "flavours/glitch/components/column_header";
|
||||
import StatusListContainer from "flavours/glitch/features/ui/containers/status_list_container";
|
||||
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
import ConversationsListContainer from './containers/conversations_list_container';
|
||||
import ColumnSettingsContainer from "./containers/column_settings_container";
|
||||
import ConversationsListContainer from "./containers/conversations_list_container";
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.direct', defaultMessage: 'Private mentions' },
|
||||
title: { id: "column.direct", defaultMessage: "Private mentions" },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
hasUnread: state.getIn(['timelines', 'direct', 'unread']) > 0,
|
||||
conversationsMode: state.getIn(['settings', 'direct', 'conversations']),
|
||||
hasUnread: state.getIn(["timelines", "direct", "unread"]) > 0,
|
||||
conversationsMode: state.getIn(["settings", "direct", "conversations"]),
|
||||
});
|
||||
|
||||
class DirectTimeline extends PureComponent {
|
||||
@@ -44,7 +44,7 @@ class DirectTimeline extends PureComponent {
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('DIRECT', {}));
|
||||
dispatch(addColumn("DIRECT", {}));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
|
||||
import { FormattedMessage, injectIntl, defineMessages } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import {
|
||||
followAccount,
|
||||
unfollowAccount,
|
||||
unblockAccount,
|
||||
unmuteAccount,
|
||||
} from 'flavours/glitch/actions/accounts';
|
||||
import { openModal } from 'flavours/glitch/actions/modal';
|
||||
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||
import Button from 'flavours/glitch/components/button';
|
||||
import { DisplayName } from 'flavours/glitch/components/display_name';
|
||||
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||
import Permalink from 'flavours/glitch/components/permalink';
|
||||
import { ShortNumber } from 'flavours/glitch/components/short_number';
|
||||
import { autoPlayGif, me, unfollowModal } from 'flavours/glitch/initial_state';
|
||||
import { makeGetAccount } from 'flavours/glitch/selectors';
|
||||
} from "flavours/glitch/actions/accounts";
|
||||
import { openModal } from "flavours/glitch/actions/modal";
|
||||
import { Avatar } from "flavours/glitch/components/avatar";
|
||||
import Button from "flavours/glitch/components/button";
|
||||
import { DisplayName } from "flavours/glitch/components/display_name";
|
||||
import { IconButton } from "flavours/glitch/components/icon_button";
|
||||
import Permalink from "flavours/glitch/components/permalink";
|
||||
import { ShortNumber } from "flavours/glitch/components/short_number";
|
||||
import { autoPlayGif, me, unfollowModal } from "flavours/glitch/initial_state";
|
||||
import { makeGetAccount } from "flavours/glitch/selectors";
|
||||
|
||||
const messages = defineMessages({
|
||||
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
|
||||
follow: { id: 'account.follow', defaultMessage: 'Follow' },
|
||||
cancel_follow_request: { id: 'account.cancel_follow_request', defaultMessage: 'Withdraw follow request' },
|
||||
cancelFollowRequestConfirm: { id: 'confirmations.cancel_follow_request.confirm', defaultMessage: 'Withdraw request' },
|
||||
requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' },
|
||||
unblock: { id: 'account.unblock_short', defaultMessage: 'Unblock' },
|
||||
unmute: { id: 'account.unmute_short', defaultMessage: 'Unmute' },
|
||||
unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' },
|
||||
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
|
||||
dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' },
|
||||
unfollow: { id: "account.unfollow", defaultMessage: "Unfollow" },
|
||||
follow: { id: "account.follow", defaultMessage: "Follow" },
|
||||
cancel_follow_request: { id: "account.cancel_follow_request", defaultMessage: "Withdraw follow request" },
|
||||
cancelFollowRequestConfirm: { id: "confirmations.cancel_follow_request.confirm", defaultMessage: "Withdraw request" },
|
||||
requested: { id: "account.requested", defaultMessage: "Awaiting approval. Click to cancel follow request" },
|
||||
unblock: { id: "account.unblock_short", defaultMessage: "Unblock" },
|
||||
unmute: { id: "account.unmute_short", defaultMessage: "Unmute" },
|
||||
unfollowConfirm: { id: "confirmations.unfollow.confirm", defaultMessage: "Unfollow" },
|
||||
edit_profile: { id: "account.edit_profile", defaultMessage: "Edit profile" },
|
||||
dismissSuggestion: { id: "suggestions.dismiss", defaultMessage: "Dismiss suggestion" },
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
@@ -49,53 +49,53 @@ const makeMapStateToProps = () => {
|
||||
|
||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
onFollow(account) {
|
||||
if (account.getIn(['relationship', 'following'])) {
|
||||
if (account.getIn(["relationship", "following"])) {
|
||||
if (unfollowModal) {
|
||||
dispatch(
|
||||
openModal({
|
||||
modalType: 'CONFIRM',
|
||||
modalType: "CONFIRM",
|
||||
modalProps: {
|
||||
message: (
|
||||
<FormattedMessage
|
||||
id='confirmations.unfollow.message'
|
||||
defaultMessage='Are you sure you want to unfollow {name}?'
|
||||
values={{ name: <strong>@{account.get('acct')}</strong> }}
|
||||
values={{ name: <strong>@{account.get("acct")}</strong> }}
|
||||
/>
|
||||
),
|
||||
confirm: intl.formatMessage(messages.unfollowConfirm),
|
||||
onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
|
||||
onConfirm: () => dispatch(unfollowAccount(account.get("id"))),
|
||||
} }),
|
||||
);
|
||||
} else {
|
||||
dispatch(unfollowAccount(account.get('id')));
|
||||
dispatch(unfollowAccount(account.get("id")));
|
||||
}
|
||||
} else if (account.getIn(['relationship', 'requested'])) {
|
||||
} else if (account.getIn(["relationship", "requested"])) {
|
||||
if (unfollowModal) {
|
||||
dispatch(openModal({
|
||||
modalType: 'CONFIRM',
|
||||
modalType: "CONFIRM",
|
||||
modalProps: {
|
||||
message: <FormattedMessage id='confirmations.cancel_follow_request.message' defaultMessage='Are you sure you want to withdraw your request to follow {name}?' values={{ name: <strong>@{account.get('acct')}</strong> }} />,
|
||||
message: <FormattedMessage id='confirmations.cancel_follow_request.message' defaultMessage='Are you sure you want to withdraw your request to follow {name}?' values={{ name: <strong>@{account.get("acct")}</strong> }} />,
|
||||
confirm: intl.formatMessage(messages.cancelFollowRequestConfirm),
|
||||
onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
|
||||
onConfirm: () => dispatch(unfollowAccount(account.get("id"))),
|
||||
},
|
||||
}));
|
||||
} else {
|
||||
dispatch(unfollowAccount(account.get('id')));
|
||||
dispatch(unfollowAccount(account.get("id")));
|
||||
}
|
||||
} else {
|
||||
dispatch(followAccount(account.get('id')));
|
||||
dispatch(followAccount(account.get("id")));
|
||||
}
|
||||
},
|
||||
|
||||
onBlock(account) {
|
||||
if (account.getIn(['relationship', 'blocking'])) {
|
||||
dispatch(unblockAccount(account.get('id')));
|
||||
if (account.getIn(["relationship", "blocking"])) {
|
||||
dispatch(unblockAccount(account.get("id")));
|
||||
}
|
||||
},
|
||||
|
||||
onMute(account) {
|
||||
if (account.getIn(['relationship', 'muting'])) {
|
||||
dispatch(unmuteAccount(account.get('id')));
|
||||
if (account.getIn(["relationship", "muting"])) {
|
||||
dispatch(unmuteAccount(account.get("id")));
|
||||
}
|
||||
},
|
||||
|
||||
@@ -117,11 +117,11 @@ class AccountCard extends ImmutablePureComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
const emojis = currentTarget.querySelectorAll('.custom-emoji');
|
||||
const emojis = currentTarget.querySelectorAll(".custom-emoji");
|
||||
|
||||
for (var i = 0; i < emojis.length; i++) {
|
||||
let emoji = emojis[i];
|
||||
emoji.src = emoji.getAttribute('data-original');
|
||||
emoji.src = emoji.getAttribute("data-original");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -130,11 +130,11 @@ class AccountCard extends ImmutablePureComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
const emojis = currentTarget.querySelectorAll('.custom-emoji');
|
||||
const emojis = currentTarget.querySelectorAll(".custom-emoji");
|
||||
|
||||
for (var i = 0; i < emojis.length; i++) {
|
||||
let emoji = emojis[i];
|
||||
emoji.src = emoji.getAttribute('data-static');
|
||||
emoji.src = emoji.getAttribute("data-static");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -151,12 +151,12 @@ class AccountCard extends ImmutablePureComponent {
|
||||
};
|
||||
|
||||
handleEditProfile = () => {
|
||||
window.open('/settings/profile', '_blank');
|
||||
window.open("/settings/profile", "_blank");
|
||||
};
|
||||
|
||||
handleDismiss = (e) => {
|
||||
const { account, onDismiss } = this.props;
|
||||
onDismiss(account.get('id'));
|
||||
onDismiss(account.get("id"));
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -167,16 +167,16 @@ class AccountCard extends ImmutablePureComponent {
|
||||
|
||||
let actionBtn;
|
||||
|
||||
if (me !== account.get('id')) {
|
||||
if (!account.get('relationship')) { // Wait until the relationship is loaded
|
||||
actionBtn = '';
|
||||
} else if (account.getIn(['relationship', 'requested'])) {
|
||||
if (me !== account.get("id")) {
|
||||
if (!account.get("relationship")) { // Wait until the relationship is loaded
|
||||
actionBtn = "";
|
||||
} else if (account.getIn(["relationship", "requested"])) {
|
||||
actionBtn = <Button text={intl.formatMessage(messages.cancel_follow_request)} title={intl.formatMessage(messages.requested)} onClick={this.handleFollow} />;
|
||||
} else if (account.getIn(['relationship', 'muting'])) {
|
||||
} else if (account.getIn(["relationship", "muting"])) {
|
||||
actionBtn = <Button text={intl.formatMessage(messages.unmute)} onClick={this.handleMute} />;
|
||||
} else if (!account.getIn(['relationship', 'blocking'])) {
|
||||
actionBtn = <Button disabled={account.getIn(['relationship', 'blocked_by'])} className={classNames({ 'button--destructive': account.getIn(['relationship', 'following']) })} text={intl.formatMessage(account.getIn(['relationship', 'following']) ? messages.unfollow : messages.follow)} onClick={this.handleFollow} />;
|
||||
} else if (account.getIn(['relationship', 'blocking'])) {
|
||||
} else if (!account.getIn(["relationship", "blocking"])) {
|
||||
actionBtn = <Button disabled={account.getIn(["relationship", "blocked_by"])} className={classNames({ "button--destructive": account.getIn(["relationship", "following"]) })} text={intl.formatMessage(account.getIn(["relationship", "following"]) ? messages.unfollow : messages.follow)} onClick={this.handleFollow} />;
|
||||
} else if (account.getIn(["relationship", "blocking"])) {
|
||||
actionBtn = <Button text={intl.formatMessage(messages.unblock)} onClick={this.handleBlock} />;
|
||||
}
|
||||
} else {
|
||||
@@ -185,13 +185,13 @@ class AccountCard extends ImmutablePureComponent {
|
||||
|
||||
return (
|
||||
<div className='account-card'>
|
||||
<Permalink href={account.get('url')} to={`/@${account.get('acct')}`} className='account-card__permalink'>
|
||||
<Permalink href={account.get("url")} to={`/@${account.get("acct")}`} className='account-card__permalink'>
|
||||
<div className='account-card__header'>
|
||||
{this.props.onDismiss && <IconButton className='media-modal__close' title={intl.formatMessage(messages.dismissSuggestion)} icon='times' onClick={this.handleDismiss} size={20} />}
|
||||
|
||||
<img
|
||||
src={
|
||||
autoPlayGif ? account.get('header') : account.get('header_static')
|
||||
autoPlayGif ? account.get("header") : account.get("header_static")
|
||||
}
|
||||
alt=''
|
||||
/>
|
||||
@@ -203,26 +203,26 @@ class AccountCard extends ImmutablePureComponent {
|
||||
</div>
|
||||
</Permalink>
|
||||
|
||||
{account.get('note').length > 0 && (
|
||||
{account.get("note").length > 0 && (
|
||||
<div
|
||||
className='account-card__bio translate'
|
||||
onMouseEnter={this.handleMouseEnter}
|
||||
onMouseLeave={this.handleMouseLeave}
|
||||
dangerouslySetInnerHTML={{ __html: account.get('note_emojified') }}
|
||||
dangerouslySetInnerHTML={{ __html: account.get("note_emojified") }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className='account-card__actions'>
|
||||
<div className='account-card__counters'>
|
||||
<div className='account-card__counters__item'>
|
||||
<ShortNumber value={account.get('statuses_count')} />
|
||||
<ShortNumber value={account.get("statuses_count")} />
|
||||
<small>
|
||||
<FormattedMessage id='account.posts' defaultMessage='Posts' />
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div className='account-card__counters__item'>
|
||||
{account.get('followers_count') < 0 ? '-' : <ShortNumber value={account.get('followers_count')} />}{' '}
|
||||
{account.get("followers_count") < 0 ? "-" : <ShortNumber value={account.get("followers_count")} />}{" "}
|
||||
<small>
|
||||
<FormattedMessage
|
||||
id='account.followers'
|
||||
@@ -232,7 +232,7 @@ class AccountCard extends ImmutablePureComponent {
|
||||
</div>
|
||||
|
||||
<div className='account-card__counters__item'>
|
||||
<ShortNumber value={account.get('following_count')} />{' '}
|
||||
<ShortNumber value={account.get("following_count")} />{" "}
|
||||
<small>
|
||||
<FormattedMessage
|
||||
id='account.following'
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { defineMessages, injectIntl } from "react-intl";
|
||||
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Helmet } from "react-helmet";
|
||||
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
import { List as ImmutableList } from "immutable";
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { addColumn, removeColumn, moveColumn, changeColumnParams } from 'flavours/glitch/actions/columns';
|
||||
import { fetchDirectory, expandDirectory } from 'flavours/glitch/actions/directory';
|
||||
import Column from 'flavours/glitch/components/column';
|
||||
import ColumnHeader from 'flavours/glitch/components/column_header';
|
||||
import { LoadMore } from 'flavours/glitch/components/load_more';
|
||||
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||
import { RadioButton } from 'flavours/glitch/components/radio_button';
|
||||
import ScrollContainer from 'flavours/glitch/containers/scroll_container';
|
||||
import { addColumn, removeColumn, moveColumn, changeColumnParams } from "flavours/glitch/actions/columns";
|
||||
import { fetchDirectory, expandDirectory } from "flavours/glitch/actions/directory";
|
||||
import Column from "flavours/glitch/components/column";
|
||||
import ColumnHeader from "flavours/glitch/components/column_header";
|
||||
import { LoadMore } from "flavours/glitch/components/load_more";
|
||||
import { LoadingIndicator } from "flavours/glitch/components/loading_indicator";
|
||||
import { RadioButton } from "flavours/glitch/components/radio_button";
|
||||
import ScrollContainer from "flavours/glitch/containers/scroll_container";
|
||||
|
||||
import AccountCard from './components/account_card';
|
||||
import AccountCard from "./components/account_card";
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'column.directory', defaultMessage: 'Browse profiles' },
|
||||
recentlyActive: { id: 'directory.recently_active', defaultMessage: 'Recently active' },
|
||||
newArrivals: { id: 'directory.new_arrivals', defaultMessage: 'New arrivals' },
|
||||
local: { id: 'directory.local', defaultMessage: 'From {domain} only' },
|
||||
federated: { id: 'directory.federated', defaultMessage: 'From known fediverse' },
|
||||
title: { id: "column.directory", defaultMessage: "Browse profiles" },
|
||||
recentlyActive: { id: "directory.recently_active", defaultMessage: "Recently active" },
|
||||
newArrivals: { id: "directory.new_arrivals", defaultMessage: "New arrivals" },
|
||||
local: { id: "directory.local", defaultMessage: "From {domain} only" },
|
||||
federated: { id: "directory.federated", defaultMessage: "From known fediverse" },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
accountIds: state.getIn(['user_lists', 'directory', 'items'], ImmutableList()),
|
||||
isLoading: state.getIn(['user_lists', 'directory', 'isLoading'], true),
|
||||
domain: state.getIn(['meta', 'domain']),
|
||||
accountIds: state.getIn(["user_lists", "directory", "items"], ImmutableList()),
|
||||
isLoading: state.getIn(["user_lists", "directory", "isLoading"], true),
|
||||
domain: state.getIn(["meta", "domain"]),
|
||||
});
|
||||
|
||||
class Directory extends PureComponent {
|
||||
@@ -65,12 +65,12 @@ class Directory extends PureComponent {
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('DIRECTORY', this.getParams(this.props, this.state)));
|
||||
dispatch(addColumn("DIRECTORY", this.getParams(this.props, this.state)));
|
||||
}
|
||||
};
|
||||
|
||||
getParams = (props, state) => ({
|
||||
order: state.order === null ? (props.params.order || 'active') : state.order,
|
||||
order: state.order === null ? (props.params.order || "active") : state.order,
|
||||
local: state.local === null ? (props.params.local || false) : state.local,
|
||||
});
|
||||
|
||||
@@ -106,7 +106,7 @@ class Directory extends PureComponent {
|
||||
const { dispatch, columnId } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(changeColumnParams(columnId, ['order'], e.target.value));
|
||||
dispatch(changeColumnParams(columnId, ["order"], e.target.value));
|
||||
} else {
|
||||
this.setState({ order: e.target.value });
|
||||
}
|
||||
@@ -116,9 +116,9 @@ class Directory extends PureComponent {
|
||||
const { dispatch, columnId } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(changeColumnParams(columnId, ['local'], e.target.value === '1'));
|
||||
dispatch(changeColumnParams(columnId, ["local"], e.target.value === "1"));
|
||||
} else {
|
||||
this.setState({ local: e.target.value === '1' });
|
||||
this.setState({ local: e.target.value === "1" });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -136,8 +136,8 @@ class Directory extends PureComponent {
|
||||
<div className='scrollable'>
|
||||
<div className='filter-form'>
|
||||
<div className='filter-form__column' role='group'>
|
||||
<RadioButton name='order' value='active' label={intl.formatMessage(messages.recentlyActive)} checked={order === 'active'} onChange={this.handleChangeOrder} />
|
||||
<RadioButton name='order' value='new' label={intl.formatMessage(messages.newArrivals)} checked={order === 'new'} onChange={this.handleChangeOrder} />
|
||||
<RadioButton name='order' value='active' label={intl.formatMessage(messages.recentlyActive)} checked={order === "active"} onChange={this.handleChangeOrder} />
|
||||
<RadioButton name='order' value='new' label={intl.formatMessage(messages.newArrivals)} checked={order === "new"} onChange={this.handleChangeOrder} />
|
||||
</div>
|
||||
|
||||
<div className='filter-form__column' role='group'>
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Helmet } from "react-helmet";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { debounce } from 'lodash';
|
||||
import { debounce } from "lodash";
|
||||
|
||||
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
||||
import ScrollableList from "flavours/glitch/components/scrollable_list";
|
||||
|
||||
import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks';
|
||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||
import DomainContainer from '../../containers/domain_container';
|
||||
import Column from '../ui/components/column';
|
||||
import { fetchDomainBlocks, expandDomainBlocks } from "../../actions/domain_blocks";
|
||||
import ColumnBackButtonSlim from "../../components/column_back_button_slim";
|
||||
import { LoadingIndicator } from "../../components/loading_indicator";
|
||||
import DomainContainer from "../../containers/domain_container";
|
||||
import Column from "../ui/components/column";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.domain_blocks', defaultMessage: 'Blocked domains' },
|
||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
|
||||
heading: { id: "column.domain_blocks", defaultMessage: "Blocked domains" },
|
||||
unblockDomain: { id: "account.unblock_domain", defaultMessage: "Unblock domain {domain}" },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
domains: state.getIn(['domain_lists', 'blocks', 'items']),
|
||||
hasMore: !!state.getIn(['domain_lists', 'blocks', 'next']),
|
||||
domains: state.getIn(["domain_lists", "blocks", "items"]),
|
||||
hasMore: !!state.getIn(["domain_lists", "blocks", "next"]),
|
||||
});
|
||||
|
||||
class Blocks extends ImmutablePureComponent {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import Trie from 'substring-trie';
|
||||
import Trie from "substring-trie";
|
||||
|
||||
import { autoPlayGif, useSystemEmojiFont } from 'flavours/glitch/initial_state';
|
||||
import { assetHost } from 'flavours/glitch/utils/config';
|
||||
import { autoPlayGif, useSystemEmojiFont } from "flavours/glitch/initial_state";
|
||||
import { assetHost } from "flavours/glitch/utils/config";
|
||||
|
||||
import unicodeMapping from './emoji_unicode_mapping_light';
|
||||
import unicodeMapping from "./emoji_unicode_mapping_light";
|
||||
|
||||
const trie = new Trie(Object.keys(unicodeMapping));
|
||||
|
||||
@@ -13,12 +13,12 @@ const emojiFilenames = (emojis) => {
|
||||
};
|
||||
|
||||
// Emoji requiring extra borders depending on theme
|
||||
const darkEmoji = emojiFilenames(['🎱', '🐜', '⚫', '🖤', '⬛', '◼️', '◾', '◼️', '✒️', '▪️', '💣', '🎳', '📷', '📸', '♣️', '🕶️', '✴️', '🔌', '💂♀️', '📽️', '🍳', '🦍', '💂', '🔪', '🕳️', '🕹️', '🕋', '🖊️', '🖋️', '💂♂️', '🎤', '🎓', '🎥', '🎼', '♠️', '🎩', '🦃', '📼', '📹', '🎮', '🐃', '🏴', '🐞', '🕺', '📱', '📲', '🚲']);
|
||||
const lightEmoji = emojiFilenames(['👽', '⚾', '🐔', '☁️', '💨', '🕊️', '👀', '🍥', '👻', '🐐', '❕', '❔', '⛸️', '🌩️', '🔊', '🔇', '📃', '🌧️', '🐏', '🍚', '🍙', '🐓', '🐑', '💀', '☠️', '🌨️', '🔉', '🔈', '💬', '💭', '🏐', '🏳️', '⚪', '⬜', '◽', '◻️', '▫️']);
|
||||
const darkEmoji = emojiFilenames(["🎱", "🐜", "⚫", "🖤", "⬛", "◼️", "◾", "◼️", "✒️", "▪️", "💣", "🎳", "📷", "📸", "♣️", "🕶️", "✴️", "🔌", "💂♀️", "📽️", "🍳", "🦍", "💂", "🔪", "🕳️", "🕹️", "🕋", "🖊️", "🖋️", "💂♂️", "🎤", "🎓", "🎥", "🎼", "♠️", "🎩", "🦃", "📼", "📹", "🎮", "🐃", "🏴", "🐞", "🕺", "📱", "📲", "🚲"]);
|
||||
const lightEmoji = emojiFilenames(["👽", "⚾", "🐔", "☁️", "💨", "🕊️", "👀", "🍥", "👻", "🐐", "❕", "❔", "⛸️", "🌩️", "🔊", "🔇", "📃", "🌧️", "🐏", "🍚", "🍙", "🐓", "🐑", "💀", "☠️", "🌨️", "🔉", "🔈", "💬", "💭", "🏐", "🏳️", "⚪", "⬜", "◽", "◻️", "▫️"]);
|
||||
|
||||
const emojiFilename = (filename) => {
|
||||
const borderedEmoji = (document.body && document.body.classList.contains('skin-mastodon-light')) ? lightEmoji : darkEmoji;
|
||||
return borderedEmoji.includes(filename) ? (filename + '_border') : filename;
|
||||
const borderedEmoji = (document.body && document.body.classList.contains("skin-mastodon-light")) ? lightEmoji : darkEmoji;
|
||||
return borderedEmoji.includes(filename) ? (filename + "_border") : filename;
|
||||
};
|
||||
|
||||
const emojifyTextNode = (node, customEmojis) => {
|
||||
@@ -39,7 +39,7 @@ const emojifyTextNode = (node, customEmojis) => {
|
||||
i += str.codePointAt(i) < 65536 ? 1 : 2;
|
||||
}
|
||||
} else {
|
||||
while (i < str.length && str[i] !== ':' && (useSystemEmojiFont || !(unicode_emoji = trie.search(str.slice(i))))) {
|
||||
while (i < str.length && str[i] !== ":" && (useSystemEmojiFont || !(unicode_emoji = trie.search(str.slice(i))))) {
|
||||
i += str.codePointAt(i) < 65536 ? 1 : 2;
|
||||
}
|
||||
}
|
||||
@@ -50,8 +50,8 @@ const emojifyTextNode = (node, customEmojis) => {
|
||||
}
|
||||
|
||||
let rend, replacement = null;
|
||||
if (str[i] === ':') { // Potentially the start of a custom emoji :shortcode:
|
||||
rend = str.indexOf(':', i + 1) + 1;
|
||||
if (str[i] === ":") { // Potentially the start of a custom emoji :shortcode:
|
||||
rend = str.indexOf(":", i + 1) + 1;
|
||||
|
||||
// no matching ending ':', skip
|
||||
if (!rend) {
|
||||
@@ -71,14 +71,14 @@ const emojifyTextNode = (node, customEmojis) => {
|
||||
// now got a replacee as ':shortcode:'
|
||||
// if you want additional emoji handler, add statements below which set replacement and return true.
|
||||
const filename = autoPlayGif ? custom_emoji.url : custom_emoji.static_url;
|
||||
replacement = document.createElement('img');
|
||||
replacement.setAttribute('draggable', 'false');
|
||||
replacement.setAttribute('class', 'emojione custom-emoji');
|
||||
replacement.setAttribute('alt', shortcode);
|
||||
replacement.setAttribute('title', shortcode);
|
||||
replacement.setAttribute('src', filename);
|
||||
replacement.setAttribute('data-original', custom_emoji.url);
|
||||
replacement.setAttribute('data-static', custom_emoji.static_url);
|
||||
replacement = document.createElement("img");
|
||||
replacement.setAttribute("draggable", "false");
|
||||
replacement.setAttribute("class", "emojione custom-emoji");
|
||||
replacement.setAttribute("alt", shortcode);
|
||||
replacement.setAttribute("title", shortcode);
|
||||
replacement.setAttribute("src", filename);
|
||||
replacement.setAttribute("data-original", custom_emoji.url);
|
||||
replacement.setAttribute("data-static", custom_emoji.static_url);
|
||||
} else { // start of an unicode emoji
|
||||
rend = i + unicode_emoji.length;
|
||||
|
||||
@@ -89,14 +89,14 @@ const emojifyTextNode = (node, customEmojis) => {
|
||||
}
|
||||
|
||||
const { filename, shortCode } = unicodeMapping[unicode_emoji];
|
||||
const title = shortCode ? `:${shortCode}:` : '';
|
||||
const title = shortCode ? `:${shortCode}:` : "";
|
||||
|
||||
replacement = document.createElement('img');
|
||||
replacement.setAttribute('draggable', 'false');
|
||||
replacement.setAttribute('class', 'emojione');
|
||||
replacement.setAttribute('alt', unicode_emoji);
|
||||
replacement.setAttribute('title', title);
|
||||
replacement.setAttribute('src', `${assetHost}/emoji/${emojiFilename(filename)}.svg`);
|
||||
replacement = document.createElement("img");
|
||||
replacement.setAttribute("draggable", "false");
|
||||
replacement.setAttribute("class", "emojione");
|
||||
replacement.setAttribute("alt", unicode_emoji);
|
||||
replacement.setAttribute("title", title);
|
||||
replacement.setAttribute("src", `${assetHost}/emoji/${emojiFilename(filename)}.svg`);
|
||||
}
|
||||
|
||||
// Add the processed-up-to-now string and the emoji replacement
|
||||
@@ -113,23 +113,25 @@ const emojifyTextNode = (node, customEmojis) => {
|
||||
const emojifyNode = (node, customEmojis) => {
|
||||
for (const child of node.childNodes) {
|
||||
switch(child.nodeType) {
|
||||
case Node.TEXT_NODE:
|
||||
emojifyTextNode(child, customEmojis);
|
||||
break;
|
||||
case Node.ELEMENT_NODE:
|
||||
if (!child.classList.contains('invisible'))
|
||||
emojifyNode(child, customEmojis);
|
||||
break;
|
||||
case Node.TEXT_NODE:
|
||||
emojifyTextNode(child, customEmojis);
|
||||
break;
|
||||
case Node.ELEMENT_NODE:
|
||||
if (!child.classList.contains("invisible")) {
|
||||
emojifyNode(child, customEmojis);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const emojify = (str, customEmojis = {}) => {
|
||||
const wrapper = document.createElement('div');
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.innerHTML = str;
|
||||
|
||||
if (!Object.keys(customEmojis).length)
|
||||
if (!Object.keys(customEmojis).length) {
|
||||
customEmojis = null;
|
||||
}
|
||||
|
||||
emojifyNode(wrapper, customEmojis);
|
||||
|
||||
@@ -143,24 +145,24 @@ export const buildCustomEmojis = (customEmojis) => {
|
||||
const emojis = [];
|
||||
|
||||
customEmojis.forEach(emoji => {
|
||||
const shortcode = emoji.get('shortcode');
|
||||
const url = autoPlayGif ? emoji.get('url') : emoji.get('static_url');
|
||||
const name = shortcode.replace(':', '');
|
||||
const shortcode = emoji.get("shortcode");
|
||||
const url = autoPlayGif ? emoji.get("url") : emoji.get("static_url");
|
||||
const name = shortcode.replace(":", "");
|
||||
|
||||
emojis.push({
|
||||
id: name,
|
||||
name,
|
||||
short_names: [name],
|
||||
text: '',
|
||||
text: "",
|
||||
emoticons: [],
|
||||
keywords: [name],
|
||||
imageUrl: url,
|
||||
custom: true,
|
||||
customCategory: emoji.get('category'),
|
||||
customCategory: emoji.get("category"),
|
||||
});
|
||||
});
|
||||
|
||||
return emojis;
|
||||
};
|
||||
|
||||
export const categoriesFromEmojis = customEmojis => customEmojis.reduce((set, emoji) => set.add(emoji.get('category') ? `custom-${emoji.get('category')}` : 'custom'), new Set(['custom']));
|
||||
export const categoriesFromEmojis = customEmojis => customEmojis.reduce((set, emoji) => set.add(emoji.get("category") ? `custom-${emoji.get("category")}` : "custom"), new Set(["custom"]));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { BaseEmoji, EmojiData, NimbleEmojiIndex } from 'emoji-mart';
|
||||
import type { Category, Data, Emoji } from 'emoji-mart/dist-es/utils/data';
|
||||
import { type BaseEmoji, type EmojiData, type NimbleEmojiIndex } from "emoji-mart";
|
||||
import { type Category, type Data, type Emoji } from "emoji-mart/dist-es/utils/data";
|
||||
|
||||
/*
|
||||
* The 'search' property, although not defined in the [`Emoji`]{@link node_modules/@types/emoji-mart/dist-es/utils/data.d.ts#Emoji} type,
|
||||
@@ -17,15 +17,15 @@ export type Skins = null;
|
||||
|
||||
export type FilenameData = string[] | string[][];
|
||||
export type ShortCodesToEmojiDataKey =
|
||||
| EmojiData['id']
|
||||
| BaseEmoji['native']
|
||||
| keyof NimbleEmojiIndex['emojis'];
|
||||
| EmojiData["id"]
|
||||
| BaseEmoji["native"]
|
||||
| keyof NimbleEmojiIndex["emojis"];
|
||||
|
||||
export type SearchData = [
|
||||
BaseEmoji['native'],
|
||||
Emoji['short_names'],
|
||||
BaseEmoji["native"],
|
||||
Emoji["short_names"],
|
||||
Search,
|
||||
Emoji['unified'],
|
||||
Emoji["unified"],
|
||||
];
|
||||
|
||||
export type ShortCodesToEmojiData = Record<
|
||||
@@ -38,7 +38,7 @@ export type EmojiCompressed = [
|
||||
ShortCodesToEmojiData,
|
||||
Skins,
|
||||
Category[],
|
||||
Data['aliases'],
|
||||
Data["aliases"],
|
||||
EmojisWithoutShortCodes,
|
||||
];
|
||||
|
||||
@@ -49,4 +49,4 @@ export type EmojiCompressed = [
|
||||
*/
|
||||
declare const emojiCompressed: EmojiCompressed;
|
||||
|
||||
export default emojiCompressed; // eslint-disable-line import/no-default-export
|
||||
export default emojiCompressed;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/* eslint-disable import/no-commonjs --
|
||||
We need to use CommonJS here due to preval */
|
||||
|
||||
// @preval
|
||||
// http://www.unicode.org/Public/emoji/5.0/emoji-test.txt
|
||||
// This file contains the compressed version of the emoji data from
|
||||
@@ -7,13 +6,13 @@
|
||||
// It's designed to be emitted in an array format to take up less space
|
||||
// over the wire.
|
||||
|
||||
const { emojiIndex } = require('emoji-mart');
|
||||
let data = require('emoji-mart/data/all.json');
|
||||
const { uncompress: emojiMartUncompress } = require('emoji-mart/dist/utils/data');
|
||||
const { emojiIndex } = require("emoji-mart");
|
||||
let data = require("emoji-mart/data/all.json");
|
||||
const { uncompress: emojiMartUncompress } = require("emoji-mart/dist/utils/data");
|
||||
|
||||
const emojiMap = require('./emoji_map.json');
|
||||
const { unicodeToFilename } = require('./unicode_to_filename');
|
||||
const { unicodeToUnifiedName } = require('./unicode_to_unified_name');
|
||||
const emojiMap = require("./emoji_map.json");
|
||||
const { unicodeToFilename } = require("./unicode_to_filename");
|
||||
const { unicodeToUnifiedName } = require("./unicode_to_unified_name");
|
||||
|
||||
|
||||
if(data.compressed) {
|
||||
@@ -22,8 +21,8 @@ if(data.compressed) {
|
||||
|
||||
const emojiMartData = data;
|
||||
|
||||
const excluded = ['®', '©', '™'];
|
||||
const skinTones = ['🏻', '🏼', '🏽', '🏾', '🏿'];
|
||||
const excluded = ["®", "©", "™"];
|
||||
const skinTones = ["🏻", "🏼", "🏽", "🏾", "🏿"];
|
||||
const shortcodeMap = {};
|
||||
|
||||
const shortCodesToEmojiData = {};
|
||||
@@ -33,8 +32,8 @@ Object.keys(emojiIndex.emojis).forEach(key => {
|
||||
let emoji = emojiIndex.emojis[key];
|
||||
|
||||
// Emojis with skin tone modifiers are stored like this
|
||||
if (Object.prototype.hasOwnProperty.call(emoji, '1')) {
|
||||
emoji = emoji['1'];
|
||||
if (Object.prototype.hasOwnProperty.call(emoji, "1")) {
|
||||
emoji = emoji["1"];
|
||||
}
|
||||
|
||||
shortcodeMap[emoji.native] = emoji.id;
|
||||
@@ -42,7 +41,7 @@ Object.keys(emojiIndex.emojis).forEach(key => {
|
||||
|
||||
const stripModifiers = unicode => {
|
||||
skinTones.forEach(tone => {
|
||||
unicode = unicode.replace(tone, '');
|
||||
unicode = unicode.replace(tone, "");
|
||||
});
|
||||
|
||||
return unicode;
|
||||
@@ -58,7 +57,7 @@ Object.keys(emojiMap).forEach(key => {
|
||||
let shortcode = shortcodeMap[normalizedKey];
|
||||
|
||||
if (!shortcode) {
|
||||
shortcode = shortcodeMap[normalizedKey + '\uFE0F'];
|
||||
shortcode = shortcodeMap[normalizedKey + "\uFE0F"];
|
||||
}
|
||||
|
||||
const filename = emojiMap[key];
|
||||
@@ -70,7 +69,7 @@ Object.keys(emojiMap).forEach(key => {
|
||||
filenameData.push(filename);
|
||||
}
|
||||
|
||||
if (typeof shortcode === 'undefined') {
|
||||
if (typeof shortcode === "undefined") {
|
||||
emojisWithoutShortCodes.push(filenameData);
|
||||
} else {
|
||||
if (!Array.isArray(shortCodesToEmojiData[shortcode])) {
|
||||
@@ -85,17 +84,17 @@ Object.keys(emojiIndex.emojis).forEach(key => {
|
||||
let emoji = emojiIndex.emojis[key];
|
||||
|
||||
// Emojis with skin tone modifiers are stored like this
|
||||
if (Object.prototype.hasOwnProperty.call(emoji, '1')) {
|
||||
emoji = emoji['1'];
|
||||
if (Object.prototype.hasOwnProperty.call(emoji, "1")) {
|
||||
emoji = emoji["1"];
|
||||
}
|
||||
|
||||
const { native } = emoji;
|
||||
let { short_names, search, unified } = emojiMartData.emojis[key];
|
||||
|
||||
if (short_names[0] !== key) {
|
||||
throw new Error('The compresser expects the first short_code to be the ' +
|
||||
'key. It may need to be rewritten if the emoji change such that this ' +
|
||||
'is no longer the case.');
|
||||
throw new Error("The compresser expects the first short_code to be the " +
|
||||
"key. It may need to be rewritten if the emoji change such that this " +
|
||||
"is no longer the case.");
|
||||
}
|
||||
|
||||
short_names = short_names.slice(1); // first short name can be inferred from the key
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
// The output of this module is designed to mimic emoji-mart's
|
||||
// "data" object, such that we can use it for a light version of emoji-mart's
|
||||
// emojiIndex.search functionality.
|
||||
import type { BaseEmoji } from 'emoji-mart';
|
||||
import type { Emoji } from 'emoji-mart/dist-es/utils/data';
|
||||
import { type BaseEmoji } from "emoji-mart";
|
||||
import { type Emoji } from "emoji-mart/dist-es/utils/data";
|
||||
|
||||
import type { Search, ShortCodesToEmojiData } from './emoji_compressed';
|
||||
import emojiCompressed from './emoji_compressed';
|
||||
import { unicodeToUnifiedName } from './unicode_to_unified_name';
|
||||
import { type Search, type ShortCodesToEmojiData } from "./emoji_compressed";
|
||||
import emojiCompressed from "./emoji_compressed";
|
||||
import { unicodeToUnifiedName } from "./unicode_to_unified_name";
|
||||
|
||||
type Emojis = {
|
||||
[key in NonNullable<keyof ShortCodesToEmojiData>]: {
|
||||
native: BaseEmoji['native'];
|
||||
search: Search;
|
||||
short_names: Emoji['short_names'];
|
||||
unified: Emoji['unified'];
|
||||
native: BaseEmoji["native"],
|
||||
search: Search,
|
||||
short_names: Emoji["short_names"],
|
||||
unified: Emoji["unified"],
|
||||
};
|
||||
};
|
||||
|
||||
@@ -40,7 +40,9 @@ Object.keys(shortCodesToEmojiData).forEach((shortCode) => {
|
||||
unified = unicodeToUnifiedName(native);
|
||||
}
|
||||
|
||||
if (short_names) short_names = [shortCode].concat(short_names);
|
||||
if (short_names) {
|
||||
short_names = [shortCode].concat(short_names);
|
||||
}
|
||||
emojis[shortCode] = {
|
||||
native,
|
||||
search,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// This code is largely borrowed from:
|
||||
// https://github.com/missive/emoji-mart/blob/5f2ffcc/src/utils/emoji-index.js
|
||||
|
||||
import * as data from './emoji_mart_data_light';
|
||||
import { getData, getSanitizedData, uniq, intersect } from './emoji_utils';
|
||||
import * as data from "./emoji_mart_data_light";
|
||||
import { getData, getSanitizedData, uniq, intersect } from "./emoji_utils";
|
||||
|
||||
let originalPool = {};
|
||||
let index = {};
|
||||
@@ -39,7 +39,9 @@ function clearCustomEmojis(pool) {
|
||||
}
|
||||
|
||||
function addCustomToPool(custom, pool) {
|
||||
if (customEmojisList.length) clearCustomEmojis(pool);
|
||||
if (customEmojisList.length) {
|
||||
clearCustomEmojis(pool);
|
||||
}
|
||||
|
||||
custom.forEach((emoji) => {
|
||||
let emojiId = emoji.id || emoji.short_names[0];
|
||||
@@ -56,8 +58,9 @@ function addCustomToPool(custom, pool) {
|
||||
|
||||
function search(value, { emojisToShowFilter, maxResults, include, exclude, custom } = {}) {
|
||||
if (custom !== undefined) {
|
||||
if (customEmojisList !== custom)
|
||||
if (customEmojisList !== custom) {
|
||||
addCustomToPool(custom, originalPool);
|
||||
}
|
||||
} else {
|
||||
custom = [];
|
||||
}
|
||||
@@ -70,8 +73,8 @@ function search(value, { emojisToShowFilter, maxResults, include, exclude, custo
|
||||
pool = originalPool;
|
||||
|
||||
if (value.length) {
|
||||
if (value === '-' || value === '-1') {
|
||||
return [emojisList['-1']];
|
||||
if (value === "-" || value === "-1") {
|
||||
return [emojisList["-1"]];
|
||||
}
|
||||
|
||||
let values = value.toLowerCase().split(/[\s|,\-_]+/),
|
||||
@@ -95,8 +98,8 @@ function search(value, { emojisToShowFilter, maxResults, include, exclude, custo
|
||||
});
|
||||
|
||||
if (custom.length) {
|
||||
let customIsIncluded = include && include.length ? include.indexOf('custom') > -1 : true;
|
||||
let customIsExcluded = exclude && exclude.length ? exclude.indexOf('custom') > -1 : false;
|
||||
let customIsIncluded = include && include.length ? include.indexOf("custom") > -1 : true;
|
||||
let customIsExcluded = exclude && exclude.length ? exclude.indexOf("custom") > -1 : false;
|
||||
if (customIsIncluded && !customIsExcluded) {
|
||||
addCustomToPool(custom, pool);
|
||||
}
|
||||
@@ -129,7 +132,9 @@ function search(value, { emojisToShowFilter, maxResults, include, exclude, custo
|
||||
|
||||
if (subIndex !== -1) {
|
||||
let score = subIndex + 1;
|
||||
if (sub === id) score = 0;
|
||||
if (sub === id) {
|
||||
score = 0;
|
||||
}
|
||||
|
||||
aIndex.results.push(emojisList[id]);
|
||||
aIndex.pool[id] = emoji;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Emoji from 'emoji-mart/dist-es/components/emoji/emoji';
|
||||
import Picker from 'emoji-mart/dist-es/components/picker/picker';
|
||||
import Emoji from "emoji-mart/dist-es/components/emoji/emoji";
|
||||
import Picker from "emoji-mart/dist-es/components/picker/picker";
|
||||
|
||||
export {
|
||||
Picker,
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// (i.e. the svg filename) and a shortCode intended to be shown
|
||||
// as a "title" attribute in an HTML element (aka tooltip).
|
||||
|
||||
import emojiCompressed from './emoji_compressed';
|
||||
import { unicodeToFilename } from './unicode_to_filename';
|
||||
import emojiCompressed from "./emoji_compressed";
|
||||
import { unicodeToFilename } from "./unicode_to_filename";
|
||||
|
||||
const [
|
||||
shortCodesToEmojiData,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This code is largely borrowed from:
|
||||
// https://github.com/missive/emoji-mart/blob/5f2ffcc/src/utils/index.js
|
||||
|
||||
import * as data from './emoji_mart_data_light';
|
||||
import * as data from "./emoji_mart_data_light";
|
||||
|
||||
const buildSearch = (data) => {
|
||||
const search = [];
|
||||
@@ -27,7 +27,7 @@ const buildSearch = (data) => {
|
||||
addToSearch(data.keywords, false);
|
||||
addToSearch(data.emoticons, false);
|
||||
|
||||
return search.join(',');
|
||||
return search.join(",");
|
||||
};
|
||||
|
||||
const _String = String;
|
||||
@@ -40,9 +40,9 @@ const stringFromCodePoint = _String.fromCodePoint || function () {
|
||||
let index = -1;
|
||||
let length = arguments.length;
|
||||
if (!length) {
|
||||
return '';
|
||||
return "";
|
||||
}
|
||||
let result = '';
|
||||
let result = "";
|
||||
while (++index < length) {
|
||||
let codePoint = Number(arguments[index]);
|
||||
if (
|
||||
@@ -51,7 +51,7 @@ const stringFromCodePoint = _String.fromCodePoint || function () {
|
||||
codePoint > 0x10FFFF || // not a valid Unicode code point
|
||||
Math.floor(codePoint) !== codePoint // not an integer
|
||||
) {
|
||||
throw RangeError('Invalid code point: ' + codePoint);
|
||||
throw RangeError("Invalid code point: " + codePoint);
|
||||
}
|
||||
if (codePoint <= 0xFFFF) { // BMP code point
|
||||
codeUnits.push(codePoint);
|
||||
@@ -75,12 +75,12 @@ const _JSON = JSON;
|
||||
|
||||
const COLONS_REGEX = /^(?::([^:]+):)(?::skin-tone-(\d):)?$/;
|
||||
const SKINS = [
|
||||
'1F3FA', '1F3FB', '1F3FC',
|
||||
'1F3FD', '1F3FE', '1F3FF',
|
||||
"1F3FA", "1F3FB", "1F3FC",
|
||||
"1F3FD", "1F3FE", "1F3FF",
|
||||
];
|
||||
|
||||
function unifiedToNative(unified) {
|
||||
let unicodes = unified.split('-'),
|
||||
let unicodes = unified.split("-"),
|
||||
codePoints = unicodes.map((u) => `0x${u}`);
|
||||
|
||||
return stringFromCodePoint.apply(null, codePoints);
|
||||
@@ -124,7 +124,7 @@ function getSanitizedData() {
|
||||
function getData(emoji, skin, set) {
|
||||
let emojiData = {};
|
||||
|
||||
if (typeof emoji === 'string') {
|
||||
if (typeof emoji === "string") {
|
||||
let matches = emoji.match(COLONS_REGEX);
|
||||
|
||||
if (matches) {
|
||||
@@ -220,7 +220,7 @@ function deepMerge(a, b) {
|
||||
value = b[key];
|
||||
}
|
||||
|
||||
if (typeof value === 'object') {
|
||||
if (typeof value === "object") {
|
||||
value = deepMerge(originalValue, value);
|
||||
}
|
||||
|
||||
@@ -232,13 +232,13 @@ function deepMerge(a, b) {
|
||||
|
||||
// https://github.com/sonicdoe/measure-scrollbar
|
||||
function measureScrollbar() {
|
||||
const div = document.createElement('div');
|
||||
const div = document.createElement("div");
|
||||
|
||||
div.style.width = '100px';
|
||||
div.style.height = '100px';
|
||||
div.style.overflow = 'scroll';
|
||||
div.style.position = 'absolute';
|
||||
div.style.top = '-9999px';
|
||||
div.style.width = "100px";
|
||||
div.style.height = "100px";
|
||||
div.style.overflow = "scroll";
|
||||
div.style.position = "absolute";
|
||||
div.style.top = "-9999px";
|
||||
|
||||
document.body.appendChild(div);
|
||||
const scrollbarWidth = div.offsetWidth - div.clientWidth;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
/* eslint-disable import/no-commonjs --
|
||||
We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */
|
||||
|
||||
|
||||
// taken from:
|
||||
// https://github.com/twitter/twemoji/blob/47732c7/twemoji-generator.js#L848-L866
|
||||
exports.unicodeToFilename = (str) => {
|
||||
let result = '';
|
||||
let result = "";
|
||||
let charCode = 0;
|
||||
let p = 0;
|
||||
let i = 0;
|
||||
@@ -12,7 +11,7 @@ exports.unicodeToFilename = (str) => {
|
||||
charCode = str.charCodeAt(i++);
|
||||
if (p) {
|
||||
if (result.length > 0) {
|
||||
result += '-';
|
||||
result += "-";
|
||||
}
|
||||
result += (0x10000 + ((p - 0xD800) << 10) + (charCode - 0xDC00)).toString(16);
|
||||
p = 0;
|
||||
@@ -20,7 +19,7 @@ exports.unicodeToFilename = (str) => {
|
||||
p = charCode;
|
||||
} else {
|
||||
if (result.length > 0) {
|
||||
result += '-';
|
||||
result += "-";
|
||||
}
|
||||
result += charCode.toString(16);
|
||||
}
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
/* eslint-disable import/no-commonjs --
|
||||
We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */
|
||||
|
||||
|
||||
function padLeft(str, num) {
|
||||
while (str.length < num) {
|
||||
str = '0' + str;
|
||||
str = "0" + str;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
exports.unicodeToUnifiedName = (str) => {
|
||||
let output = '';
|
||||
let output = "";
|
||||
|
||||
for (let i = 0; i < str.length; i += 2) {
|
||||
if (i > 0) {
|
||||
output += '-';
|
||||
output += "-";
|
||||
}
|
||||
|
||||
output += padLeft(str.codePointAt(i).toString(16).toUpperCase(), 4);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
export const SearchSection = ({ title, onClickMore, children }) => (
|
||||
<div className='search-results__section'>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import classNames from 'classnames';
|
||||
import classNames from "classnames";
|
||||
|
||||
import { Blurhash } from 'flavours/glitch/components/blurhash';
|
||||
import { accountsCountRenderer } from 'flavours/glitch/components/hashtag';
|
||||
import { RelativeTimestamp } from 'flavours/glitch/components/relative_timestamp';
|
||||
import { ShortNumber } from 'flavours/glitch/components/short_number';
|
||||
import { Skeleton } from 'flavours/glitch/components/skeleton';
|
||||
import { Blurhash } from "flavours/glitch/components/blurhash";
|
||||
import { accountsCountRenderer } from "flavours/glitch/components/hashtag";
|
||||
import { RelativeTimestamp } from "flavours/glitch/components/relative_timestamp";
|
||||
import { ShortNumber } from "flavours/glitch/components/short_number";
|
||||
import { Skeleton } from "flavours/glitch/components/skeleton";
|
||||
|
||||
|
||||
export default class Story extends PureComponent {
|
||||
@@ -40,17 +40,17 @@ export default class Story extends PureComponent {
|
||||
const { thumbnailLoaded } = this.state;
|
||||
|
||||
return (
|
||||
<a className={classNames('story', { expanded })} href={url} target='blank' rel='noopener'>
|
||||
<a className={classNames("story", { expanded })} href={url} target='blank' rel='noopener'>
|
||||
<div className='story__details'>
|
||||
<div className='story__details__publisher'>{publisher ? <span lang={lang}>{publisher}</span> : <Skeleton width={50} />}{publishedAt && <> · <RelativeTimestamp timestamp={publishedAt} /></>}</div>
|
||||
<div className='story__details__title' lang={lang}>{title ? title : <Skeleton />}</div>
|
||||
<div className='story__details__shared'>{author && <><FormattedMessage id='link_preview.author' defaultMessage='By {name}' values={{ name: <strong>{author}</strong> }} /> · </>}{typeof sharedTimes === 'number' ? <ShortNumber value={sharedTimes} renderer={accountsCountRenderer} /> : <Skeleton width={100} />}</div>
|
||||
<div className='story__details__shared'>{author && <><FormattedMessage id='link_preview.author' defaultMessage='By {name}' values={{ name: <strong>{author}</strong> }} /> · </>}{typeof sharedTimes === "number" ? <ShortNumber value={sharedTimes} renderer={accountsCountRenderer} /> : <Skeleton width={100} />}</div>
|
||||
</div>
|
||||
|
||||
<div className='story__thumbnail'>
|
||||
{thumbnail ? (
|
||||
<>
|
||||
<div className={classNames('story__thumbnail__preview', { 'story__thumbnail__preview--hidden': thumbnailLoaded })}><Blurhash hash={blurhash} /></div>
|
||||
<div className={classNames("story__thumbnail__preview", { "story__thumbnail__preview--hidden": thumbnailLoaded })}><Blurhash hash={blurhash} /></div>
|
||||
<img src={thumbnail} onLoad={this.handleImageLoad} alt={thumbnailDescription} title={thumbnailDescription} lang={lang} />
|
||||
</>
|
||||
) : <Skeleton />}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { NavLink, Switch, Route } from 'react-router-dom';
|
||||
import { Helmet } from "react-helmet";
|
||||
import { NavLink, Switch, Route } from "react-router-dom";
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import Column from 'flavours/glitch/components/column';
|
||||
import ColumnHeader from 'flavours/glitch/components/column_header';
|
||||
import Search from 'flavours/glitch/features/compose/containers/search_container';
|
||||
import { trendsEnabled } from 'flavours/glitch/initial_state';
|
||||
import Column from "flavours/glitch/components/column";
|
||||
import ColumnHeader from "flavours/glitch/components/column_header";
|
||||
import Search from "flavours/glitch/features/compose/containers/search_container";
|
||||
import { trendsEnabled } from "flavours/glitch/initial_state";
|
||||
|
||||
import Links from './links';
|
||||
import SearchResults from './results';
|
||||
import Statuses from './statuses';
|
||||
import Suggestions from './suggestions';
|
||||
import Tags from './tags';
|
||||
import Links from "./links";
|
||||
import SearchResults from "./results";
|
||||
import Statuses from "./statuses";
|
||||
import Suggestions from "./suggestions";
|
||||
import Tags from "./tags";
|
||||
|
||||
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'explore.title', defaultMessage: 'Explore' },
|
||||
searchResults: { id: 'explore.search_results', defaultMessage: 'Search results' },
|
||||
title: { id: "explore.title", defaultMessage: "Explore" },
|
||||
searchResults: { id: "explore.search_results", defaultMessage: "Search results" },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
layout: state.getIn(['meta', 'layout']),
|
||||
isSearching: state.getIn(['search', 'submitted']) || !trendsEnabled,
|
||||
layout: state.getIn(["meta", "layout"]),
|
||||
isSearching: state.getIn(["search", "submitted"]) || !trendsEnabled,
|
||||
});
|
||||
|
||||
class Explore extends PureComponent {
|
||||
@@ -59,7 +59,7 @@ class Explore extends PureComponent {
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
|
||||
<ColumnHeader
|
||||
icon={isSearching ? 'search' : 'hashtag'}
|
||||
icon={isSearching ? "search" : "hashtag"}
|
||||
title={intl.formatMessage(isSearching ? messages.searchResults : messages.title)}
|
||||
onClick={this.handleHeaderClick}
|
||||
multiColumn={multiColumn}
|
||||
@@ -98,14 +98,14 @@ class Explore extends PureComponent {
|
||||
<Route path='/explore/tags' component={Tags} />
|
||||
<Route path='/explore/links' component={Links} />
|
||||
<Route path='/explore/suggestions' component={Suggestions} />
|
||||
<Route exact path={['/explore', '/explore/posts', '/search']}>
|
||||
<Route exact path={["/explore", "/explore/posts", "/search"]}>
|
||||
<Statuses multiColumn={multiColumn} />
|
||||
</Route>
|
||||
</Switch>
|
||||
|
||||
<Helmet>
|
||||
<title>{intl.formatMessage(messages.title)}</title>
|
||||
<meta name='robots' content={isSearching ? 'noindex' : 'all'} />
|
||||
<meta name='robots' content={isSearching ? "noindex" : "all"} />
|
||||
</Helmet>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { fetchTrendingLinks } from 'flavours/glitch/actions/trends';
|
||||
import { DismissableBanner } from 'flavours/glitch/components/dismissable_banner';
|
||||
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||
import { fetchTrendingLinks } from "flavours/glitch/actions/trends";
|
||||
import { DismissableBanner } from "flavours/glitch/components/dismissable_banner";
|
||||
import { LoadingIndicator } from "flavours/glitch/components/loading_indicator";
|
||||
|
||||
import Story from './components/story';
|
||||
import Story from "./components/story";
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
links: state.getIn(['trends', 'links', 'items']),
|
||||
isLoading: state.getIn(['trends', 'links', 'isLoading']),
|
||||
links: state.getIn(["trends", "links", "items"]),
|
||||
isLoading: state.getIn(["trends", "links", "isLoading"]),
|
||||
});
|
||||
|
||||
class Links extends PureComponent {
|
||||
@@ -57,18 +57,18 @@ class Links extends PureComponent {
|
||||
|
||||
{isLoading ? (<LoadingIndicator />) : links.map((link, i) => (
|
||||
<Story
|
||||
key={link.get('id')}
|
||||
key={link.get("id")}
|
||||
expanded={i === 0}
|
||||
lang={link.get('language')}
|
||||
url={link.get('url')}
|
||||
title={link.get('title')}
|
||||
publisher={link.get('provider_name')}
|
||||
publishedAt={link.get('published_at')}
|
||||
author={link.get('author_name')}
|
||||
sharedTimes={link.getIn(['history', 0, 'accounts']) * 1 + link.getIn(['history', 1, 'accounts']) * 1}
|
||||
thumbnail={link.get('image')}
|
||||
thumbnailDescription={link.get('image_description')}
|
||||
blurhash={link.get('blurhash')}
|
||||
lang={link.get("language")}
|
||||
url={link.get("url")}
|
||||
title={link.get("title")}
|
||||
publisher={link.get("provider_name")}
|
||||
publishedAt={link.get("published_at")}
|
||||
author={link.get("author_name")}
|
||||
sharedTimes={link.getIn(["history", 0, "accounts"]) * 1 + link.getIn(["history", 1, "accounts"]) * 1}
|
||||
thumbnail={link.get("image")}
|
||||
thumbnailDescription={link.get("image_description")}
|
||||
blurhash={link.get("blurhash")}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||
import { injectIntl, defineMessages, FormattedMessage } from "react-intl";
|
||||
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Helmet } from "react-helmet";
|
||||
|
||||
import { List as ImmutableList } from 'immutable';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
import { List as ImmutableList } from "immutable";
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { submitSearch, expandSearch } from 'flavours/glitch/actions/search';
|
||||
import { ImmutableHashtag as Hashtag } from 'flavours/glitch/components/hashtag';
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
||||
import Account from 'flavours/glitch/containers/account_container';
|
||||
import Status from 'flavours/glitch/containers/status_container';
|
||||
import { submitSearch, expandSearch } from "flavours/glitch/actions/search";
|
||||
import { ImmutableHashtag as Hashtag } from "flavours/glitch/components/hashtag";
|
||||
import { Icon } from "flavours/glitch/components/icon";
|
||||
import ScrollableList from "flavours/glitch/components/scrollable_list";
|
||||
import Account from "flavours/glitch/containers/account_container";
|
||||
import Status from "flavours/glitch/containers/status_container";
|
||||
|
||||
import { SearchSection } from './components/search_section';
|
||||
import { SearchSection } from "./components/search_section";
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'search_results.title', defaultMessage: 'Search for {q}' },
|
||||
title: { id: "search_results.title", defaultMessage: "Search for {q}" },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
isLoading: state.getIn(['search', 'isLoading']),
|
||||
results: state.getIn(['search', 'results']),
|
||||
q: state.getIn(['search', 'searchTerm']),
|
||||
submittedType: state.getIn(['search', 'type']),
|
||||
isLoading: state.getIn(["search", "isLoading"]),
|
||||
results: state.getIn(["search", "results"]),
|
||||
q: state.getIn(["search", "searchTerm"]),
|
||||
submittedType: state.getIn(["search", "type"]),
|
||||
});
|
||||
|
||||
const INITIAL_PAGE_LIMIT = 10;
|
||||
@@ -45,7 +45,7 @@ const renderAccounts = accounts => hidePeek(accounts).map(id => (
|
||||
));
|
||||
|
||||
const renderHashtags = hashtags => hidePeek(hashtags).map(hashtag => (
|
||||
<Hashtag key={hashtag.get('name')} hashtag={hashtag} />
|
||||
<Hashtag key={hashtag.get("name")} hashtag={hashtag} />
|
||||
));
|
||||
|
||||
const renderStatuses = statuses => hidePeek(statuses).map(id => (
|
||||
@@ -65,17 +65,17 @@ class Results extends PureComponent {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
q: PropTypes.string,
|
||||
intl: PropTypes.object,
|
||||
submittedType: PropTypes.oneOf(['accounts', 'statuses', 'hashtags']),
|
||||
submittedType: PropTypes.oneOf(["accounts", "statuses", "hashtags"]),
|
||||
};
|
||||
|
||||
state = {
|
||||
type: this.props.submittedType || 'all',
|
||||
type: this.props.submittedType || "all",
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps(props, state) {
|
||||
if (props.submittedType !== state.type) {
|
||||
return {
|
||||
type: props.submittedType || 'all',
|
||||
type: props.submittedType || "all",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ class Results extends PureComponent {
|
||||
dispatch(submitSearch());
|
||||
}
|
||||
|
||||
this.setState({ type: 'all' });
|
||||
this.setState({ type: "all" });
|
||||
};
|
||||
|
||||
handleSelectAccounts = () => {
|
||||
@@ -99,11 +99,11 @@ class Results extends PureComponent {
|
||||
|
||||
// If we originally searched for something else (but not everything),
|
||||
// we need to resubmit the query for this specific type
|
||||
if (submittedType !== 'accounts') {
|
||||
dispatch(submitSearch('accounts'));
|
||||
if (submittedType !== "accounts") {
|
||||
dispatch(submitSearch("accounts"));
|
||||
}
|
||||
|
||||
this.setState({ type: 'accounts' });
|
||||
this.setState({ type: "accounts" });
|
||||
};
|
||||
|
||||
handleSelectHashtags = () => {
|
||||
@@ -111,11 +111,11 @@ class Results extends PureComponent {
|
||||
|
||||
// If we originally searched for something else (but not everything),
|
||||
// we need to resubmit the query for this specific type
|
||||
if (submittedType !== 'hashtags') {
|
||||
dispatch(submitSearch('hashtags'));
|
||||
if (submittedType !== "hashtags") {
|
||||
dispatch(submitSearch("hashtags"));
|
||||
}
|
||||
|
||||
this.setState({ type: 'hashtags' });
|
||||
this.setState({ type: "hashtags" });
|
||||
};
|
||||
|
||||
handleSelectStatuses = () => {
|
||||
@@ -123,16 +123,16 @@ class Results extends PureComponent {
|
||||
|
||||
// If we originally searched for something else (but not everything),
|
||||
// we need to resubmit the query for this specific type
|
||||
if (submittedType !== 'statuses') {
|
||||
dispatch(submitSearch('statuses'));
|
||||
if (submittedType !== "statuses") {
|
||||
dispatch(submitSearch("statuses"));
|
||||
}
|
||||
|
||||
this.setState({ type: 'statuses' });
|
||||
this.setState({ type: "statuses" });
|
||||
};
|
||||
|
||||
handleLoadMoreAccounts = () => this._loadMore('accounts');
|
||||
handleLoadMoreStatuses = () => this._loadMore('statuses');
|
||||
handleLoadMoreHashtags = () => this._loadMore('hashtags');
|
||||
handleLoadMoreAccounts = () => this._loadMore("accounts");
|
||||
handleLoadMoreStatuses = () => this._loadMore("statuses");
|
||||
handleLoadMoreHashtags = () => this._loadMore("hashtags");
|
||||
|
||||
_loadMore (type) {
|
||||
const { dispatch } = this.props;
|
||||
@@ -142,7 +142,7 @@ class Results extends PureComponent {
|
||||
handleLoadMore = () => {
|
||||
const { type } = this.state;
|
||||
|
||||
if (type !== 'all') {
|
||||
if (type !== "all") {
|
||||
this._loadMore(type);
|
||||
}
|
||||
};
|
||||
@@ -152,56 +152,56 @@ class Results extends PureComponent {
|
||||
const { type } = this.state;
|
||||
|
||||
// We request 1 more result than we display so we can tell if there'd be a next page
|
||||
const hasMore = type !== 'all' ? results.get(type, ImmutableList()).size > INITIAL_PAGE_LIMIT && results.get(type).size % INITIAL_PAGE_LIMIT === 1 : false;
|
||||
const hasMore = type !== "all" ? results.get(type, ImmutableList()).size > INITIAL_PAGE_LIMIT && results.get(type).size % INITIAL_PAGE_LIMIT === 1 : false;
|
||||
|
||||
let filteredResults;
|
||||
|
||||
const accounts = results.get('accounts', ImmutableList());
|
||||
const hashtags = results.get('hashtags', ImmutableList());
|
||||
const statuses = results.get('statuses', ImmutableList());
|
||||
const accounts = results.get("accounts", ImmutableList());
|
||||
const hashtags = results.get("hashtags", ImmutableList());
|
||||
const statuses = results.get("statuses", ImmutableList());
|
||||
|
||||
switch(type) {
|
||||
case 'all':
|
||||
filteredResults = (accounts.size + hashtags.size + statuses.size) > 0 ? (
|
||||
<>
|
||||
{accounts.size > 0 && (
|
||||
<SearchSection key='accounts' title={<><Icon id='users' fixedWidth /><FormattedMessage id='search_results.accounts' defaultMessage='Profiles' /></>} onClickMore={this.handleLoadMoreAccounts}>
|
||||
{accounts.take(INITIAL_DISPLAY).map(id => <Account key={id} id={id} />)}
|
||||
</SearchSection>
|
||||
)}
|
||||
case "all":
|
||||
filteredResults = (accounts.size + hashtags.size + statuses.size) > 0 ? (
|
||||
<>
|
||||
{accounts.size > 0 && (
|
||||
<SearchSection key='accounts' title={<><Icon id='users' fixedWidth /><FormattedMessage id='search_results.accounts' defaultMessage='Profiles' /></>} onClickMore={this.handleLoadMoreAccounts}>
|
||||
{accounts.take(INITIAL_DISPLAY).map(id => <Account key={id} id={id} />)}
|
||||
</SearchSection>
|
||||
)}
|
||||
|
||||
{hashtags.size > 0 && (
|
||||
<SearchSection key='hashtags' title={<><Icon id='hashtag' fixedWidth /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></>} onClickMore={this.handleLoadMoreHashtags}>
|
||||
{hashtags.take(INITIAL_DISPLAY).map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
|
||||
</SearchSection>
|
||||
)}
|
||||
{hashtags.size > 0 && (
|
||||
<SearchSection key='hashtags' title={<><Icon id='hashtag' fixedWidth /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></>} onClickMore={this.handleLoadMoreHashtags}>
|
||||
{hashtags.take(INITIAL_DISPLAY).map(hashtag => <Hashtag key={hashtag.get("name")} hashtag={hashtag} />)}
|
||||
</SearchSection>
|
||||
)}
|
||||
|
||||
{statuses.size > 0 && (
|
||||
<SearchSection key='statuses' title={<><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></>} onClickMore={this.handleLoadMoreStatuses}>
|
||||
{statuses.take(INITIAL_DISPLAY).map(id => <Status key={id} id={id} />)}
|
||||
</SearchSection>
|
||||
)}
|
||||
</>
|
||||
) : [];
|
||||
break;
|
||||
case 'accounts':
|
||||
filteredResults = renderAccounts(accounts);
|
||||
break;
|
||||
case 'hashtags':
|
||||
filteredResults = renderHashtags(hashtags);
|
||||
break;
|
||||
case 'statuses':
|
||||
filteredResults = renderStatuses(statuses);
|
||||
break;
|
||||
{statuses.size > 0 && (
|
||||
<SearchSection key='statuses' title={<><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></>} onClickMore={this.handleLoadMoreStatuses}>
|
||||
{statuses.take(INITIAL_DISPLAY).map(id => <Status key={id} id={id} />)}
|
||||
</SearchSection>
|
||||
)}
|
||||
</>
|
||||
) : [];
|
||||
break;
|
||||
case "accounts":
|
||||
filteredResults = renderAccounts(accounts);
|
||||
break;
|
||||
case "hashtags":
|
||||
filteredResults = renderHashtags(hashtags);
|
||||
break;
|
||||
case "statuses":
|
||||
filteredResults = renderStatuses(statuses);
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='account__section-headline'>
|
||||
<button onClick={this.handleSelectAll} className={type === 'all' ? 'active' : undefined}><FormattedMessage id='search_results.all' defaultMessage='All' /></button>
|
||||
<button onClick={this.handleSelectAccounts} className={type === 'accounts' ? 'active' : undefined}><FormattedMessage id='search_results.accounts' defaultMessage='Profiles' /></button>
|
||||
<button onClick={this.handleSelectHashtags} className={type === 'hashtags' ? 'active' : undefined}><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></button>
|
||||
<button onClick={this.handleSelectStatuses} className={type === 'statuses' ? 'active' : undefined}><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></button>
|
||||
<button onClick={this.handleSelectAll} className={type === "all" ? "active" : undefined}><FormattedMessage id='search_results.all' defaultMessage='All' /></button>
|
||||
<button onClick={this.handleSelectAccounts} className={type === "accounts" ? "active" : undefined}><FormattedMessage id='search_results.accounts' defaultMessage='Profiles' /></button>
|
||||
<button onClick={this.handleSelectHashtags} className={type === "hashtags" ? "active" : undefined}><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></button>
|
||||
<button onClick={this.handleSelectStatuses} className={type === "statuses" ? "active" : undefined}><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></button>
|
||||
</div>
|
||||
|
||||
<div className='explore__search-results'>
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { debounce } from 'lodash';
|
||||
import { debounce } from "lodash";
|
||||
|
||||
import { fetchTrendingStatuses, expandTrendingStatuses } from 'flavours/glitch/actions/trends';
|
||||
import { DismissableBanner } from 'flavours/glitch/components/dismissable_banner';
|
||||
import StatusList from 'flavours/glitch/components/status_list';
|
||||
import { getStatusList } from 'flavours/glitch/selectors';
|
||||
import { fetchTrendingStatuses, expandTrendingStatuses } from "flavours/glitch/actions/trends";
|
||||
import { DismissableBanner } from "flavours/glitch/components/dismissable_banner";
|
||||
import StatusList from "flavours/glitch/components/status_list";
|
||||
import { getStatusList } from "flavours/glitch/selectors";
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
statusIds: getStatusList(state, 'trending'),
|
||||
isLoading: state.getIn(['status_lists', 'trending', 'isLoading'], true),
|
||||
hasMore: !!state.getIn(['status_lists', 'trending', 'next']),
|
||||
statusIds: getStatusList(state, "trending"),
|
||||
isLoading: state.getIn(["status_lists", "trending", "isLoading"], true),
|
||||
hasMore: !!state.getIn(["status_lists", "trending", "next"]),
|
||||
});
|
||||
|
||||
class Statuses extends PureComponent {
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { fetchSuggestions, dismissSuggestion } from 'flavours/glitch/actions/suggestions';
|
||||
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||
import AccountCard from 'flavours/glitch/features/directory/components/account_card';
|
||||
import { fetchSuggestions, dismissSuggestion } from "flavours/glitch/actions/suggestions";
|
||||
import { LoadingIndicator } from "flavours/glitch/components/loading_indicator";
|
||||
import AccountCard from "flavours/glitch/features/directory/components/account_card";
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
suggestions: state.getIn(['suggestions', 'items']),
|
||||
isLoading: state.getIn(['suggestions', 'isLoading']),
|
||||
suggestions: state.getIn(["suggestions", "items"]),
|
||||
isLoading: state.getIn(["suggestions", "isLoading"]),
|
||||
});
|
||||
|
||||
class Suggestions extends PureComponent {
|
||||
@@ -49,7 +49,7 @@ class Suggestions extends PureComponent {
|
||||
return (
|
||||
<div className='explore__suggestions'>
|
||||
{isLoading ? <LoadingIndicator /> : suggestions.map(suggestion => (
|
||||
<AccountCard key={suggestion.get('account')} id={suggestion.get('account')} onDismiss={suggestion.get('source') === 'past_interactions' ? this.handleDismiss : null} />
|
||||
<AccountCard key={suggestion.get("account")} id={suggestion.get("account")} onDismiss={suggestion.get("source") === "past_interactions" ? this.handleDismiss : null} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
import PropTypes from "prop-types";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { fetchTrendingHashtags } from 'flavours/glitch/actions/trends';
|
||||
import { DismissableBanner } from 'flavours/glitch/components/dismissable_banner';
|
||||
import { ImmutableHashtag as Hashtag } from 'flavours/glitch/components/hashtag';
|
||||
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||
import { fetchTrendingHashtags } from "flavours/glitch/actions/trends";
|
||||
import { DismissableBanner } from "flavours/glitch/components/dismissable_banner";
|
||||
import { ImmutableHashtag as Hashtag } from "flavours/glitch/components/hashtag";
|
||||
import { LoadingIndicator } from "flavours/glitch/components/loading_indicator";
|
||||
|
||||
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
hashtags: state.getIn(['trends', 'tags', 'items']),
|
||||
isLoadingHashtags: state.getIn(['trends', 'tags', 'isLoading']),
|
||||
hashtags: state.getIn(["trends", "tags", "items"]),
|
||||
isLoadingHashtags: state.getIn(["trends", "tags", "isLoading"]),
|
||||
});
|
||||
|
||||
class Tags extends PureComponent {
|
||||
@@ -57,7 +57,7 @@ class Tags extends PureComponent {
|
||||
{banner}
|
||||
|
||||
{isLoading ? (<LoadingIndicator />) : hashtags.map(hashtag => (
|
||||
<Hashtag key={hashtag.get('name')} hashtag={hashtag} />
|
||||
<Hashtag key={hashtag.get("name")} hashtag={hashtag} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from "react-intl";
|
||||
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Helmet } from "react-helmet";
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePropTypes from "react-immutable-proptypes";
|
||||
import ImmutablePureComponent from "react-immutable-pure-component";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import { debounce } from 'lodash';
|
||||
import { debounce } from "lodash";
|
||||
|
||||
import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
|
||||
import { fetchFavouritedStatuses, expandFavouritedStatuses } from 'flavours/glitch/actions/favourites';
|
||||
import ColumnHeader from 'flavours/glitch/components/column_header';
|
||||
import StatusList from 'flavours/glitch/components/status_list';
|
||||
import Column from 'flavours/glitch/features/ui/components/column';
|
||||
import { getStatusList } from 'flavours/glitch/selectors';
|
||||
import { addColumn, removeColumn, moveColumn } from "flavours/glitch/actions/columns";
|
||||
import { fetchFavouritedStatuses, expandFavouritedStatuses } from "flavours/glitch/actions/favourites";
|
||||
import ColumnHeader from "flavours/glitch/components/column_header";
|
||||
import StatusList from "flavours/glitch/components/status_list";
|
||||
import Column from "flavours/glitch/features/ui/components/column";
|
||||
import { getStatusList } from "flavours/glitch/selectors";
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.favourites', defaultMessage: 'Favorites' },
|
||||
heading: { id: "column.favourites", defaultMessage: "Favorites" },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
statusIds: getStatusList(state, 'favourites'),
|
||||
isLoading: state.getIn(['status_lists', 'favourites', 'isLoading'], true),
|
||||
hasMore: !!state.getIn(['status_lists', 'favourites', 'next']),
|
||||
statusIds: getStatusList(state, "favourites"),
|
||||
isLoading: state.getIn(["status_lists", "favourites", "isLoading"], true),
|
||||
hasMore: !!state.getIn(["status_lists", "favourites", "next"]),
|
||||
});
|
||||
|
||||
class Favourites extends ImmutablePureComponent {
|
||||
@@ -49,7 +49,7 @@ class Favourites extends ImmutablePureComponent {
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('FAVOURITES', {}));
|
||||
dispatch(addColumn("FAVOURITES", {}));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user