Merge commit '89269e4b713e3291a5c8c29b8d2e7b950b60eb35' into glitch-soc/merge-upstream
Conflicts: - `tsconfig.json`: Upstream changed the config to properly process imports. Glitch-soc had previously already done so. Changed the config to better match upstream.pull/2216/head
commit
8b568755ad
|
@ -1,10 +1,11 @@
|
||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
|
import type { LayoutType } from '../is_mobile';
|
||||||
|
|
||||||
export const focusApp = createAction('APP_FOCUS');
|
export const focusApp = createAction('APP_FOCUS');
|
||||||
export const unfocusApp = createAction('APP_UNFOCUS');
|
export const unfocusApp = createAction('APP_UNFOCUS');
|
||||||
|
|
||||||
type ChangeLayoutPayload = {
|
type ChangeLayoutPayload = {
|
||||||
layout: 'mobile' | 'single-column' | 'multi-column';
|
layout: LayoutType;
|
||||||
};
|
};
|
||||||
export const changeLayout =
|
export const changeLayout =
|
||||||
createAction<ChangeLayoutPayload>('APP_LAYOUT_CHANGE');
|
createAction<ChangeLayoutPayload>('APP_LAYOUT_CHANGE');
|
||||||
|
|
|
@ -151,7 +151,7 @@ class Account extends ImmutablePureComponent {
|
||||||
const firstVerifiedField = account.get('fields').find(item => !!item.get('verified_at'));
|
const firstVerifiedField = account.get('fields').find(item => !!item.get('verified_at'));
|
||||||
|
|
||||||
if (firstVerifiedField) {
|
if (firstVerifiedField) {
|
||||||
verification = <>· <VerifiedBadge link={firstVerifiedField.get('value')} verifiedAt={firstVerifiedField.get('verified_at')} /></>;
|
verification = <>· <VerifiedBadge link={firstVerifiedField.get('value')} /></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const Check = () => (
|
export const Check: React.FC = () => (
|
||||||
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='currentColor'>
|
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='currentColor'>
|
||||||
<path fillRule='evenodd' d='M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z' clipRule='evenodd' />
|
<path fillRule='evenodd' d='M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z' clipRule='evenodd' />
|
||||||
</svg>
|
</svg>
|
|
@ -1,43 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import IconButton from './icon_button';
|
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
|
|
||||||
});
|
|
||||||
|
|
||||||
class Account extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
domain: PropTypes.string,
|
|
||||||
onUnblockDomain: PropTypes.func.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
handleDomainUnblock = () => {
|
|
||||||
this.props.onUnblockDomain(this.props.domain);
|
|
||||||
};
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { domain, intl } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='domain'>
|
|
||||||
<div className='domain__wrapper'>
|
|
||||||
<span className='domain__domain-name'>
|
|
||||||
<strong>{domain}</strong>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div className='domain__buttons'>
|
|
||||||
<IconButton active icon='unlock' title={intl.formatMessage(messages.unblockDomain, { domain })} onClick={this.handleDomainUnblock} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default injectIntl(Account);
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import React, { useCallback } from 'react';
|
||||||
|
import IconButton from './icon_button';
|
||||||
|
import { InjectedIntl, defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
unblockDomain: {
|
||||||
|
id: 'account.unblock_domain',
|
||||||
|
defaultMessage: 'Unblock domain {domain}',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
domain: string;
|
||||||
|
onUnblockDomain: (domain: string) => void;
|
||||||
|
intl: InjectedIntl;
|
||||||
|
};
|
||||||
|
const _Domain: React.FC<Props> = ({ domain, onUnblockDomain, intl }) => {
|
||||||
|
const handleDomainUnblock = useCallback(() => {
|
||||||
|
onUnblockDomain(domain);
|
||||||
|
}, [domain, onUnblockDomain]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='domain'>
|
||||||
|
<div className='domain__wrapper'>
|
||||||
|
<span className='domain__domain-name'>
|
||||||
|
<strong>{domain}</strong>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div className='domain__buttons'>
|
||||||
|
<IconButton
|
||||||
|
active
|
||||||
|
icon='unlock'
|
||||||
|
title={intl.formatMessage(messages.unblockDomain, { domain })}
|
||||||
|
onClick={handleDomainUnblock}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Domain = injectIntl(_Domain);
|
|
@ -5,9 +5,7 @@ import { FormattedMessage } from 'react-intl';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
// @ts-expect-error
|
|
||||||
import ShortNumber from 'mastodon/components/short_number';
|
import ShortNumber from 'mastodon/components/short_number';
|
||||||
// @ts-expect-error
|
|
||||||
import Skeleton from 'mastodon/components/skeleton';
|
import Skeleton from 'mastodon/components/skeleton';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Blurhash from './blurhash';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
export default class Image extends React.PureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
src: PropTypes.string,
|
|
||||||
srcSet: PropTypes.string,
|
|
||||||
blurhash: PropTypes.string,
|
|
||||||
className: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
state = {
|
|
||||||
loaded: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
handleLoad = () => this.setState({ loaded: true });
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { src, srcSet, blurhash, className } = this.props;
|
|
||||||
const { loaded } = this.state;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classNames('image', { loaded }, className)} role='presentation'>
|
|
||||||
{blurhash && <Blurhash hash={blurhash} className='image__preview' />}
|
|
||||||
<img src={src} srcSet={srcSet} alt='' onLoad={this.handleLoad} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import React, { useCallback, useState } from 'react';
|
||||||
|
import Blurhash from './blurhash';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
src: string;
|
||||||
|
srcSet?: string;
|
||||||
|
blurhash?: string;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Image: React.FC<Props> = ({ src, srcSet, blurhash, className }) => {
|
||||||
|
const [loaded, setLoaded] = useState(false);
|
||||||
|
|
||||||
|
const handleLoad = useCallback(() => {
|
||||||
|
setLoaded(true);
|
||||||
|
}, [setLoaded]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classNames('image', { loaded }, className)} role='presentation'>
|
||||||
|
{blurhash && <Blurhash hash={blurhash} className='image__preview' />}
|
||||||
|
<img src={src} srcSet={srcSet} alt='' onLoad={handleLoad} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Image;
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
const NotSignedInIndicator = () => (
|
export const NotSignedInIndicator: React.FC = () => (
|
||||||
<div className='scrollable scrollable--flex'>
|
<div className='scrollable scrollable--flex'>
|
||||||
<div className='empty-column-indicator'>
|
<div className='empty-column-indicator'>
|
||||||
<FormattedMessage id='not_signed_in_indicator.not_signed_in' defaultMessage='You need to sign in to access this resource.' />
|
<FormattedMessage id='not_signed_in_indicator.not_signed_in' defaultMessage='You need to sign in to access this resource.' />
|
|
@ -1,35 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
export default class RadioButton extends React.PureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
value: PropTypes.string.isRequired,
|
|
||||||
checked: PropTypes.bool,
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
label: PropTypes.node.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { name, value, checked, onChange, label } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<label className='radio-button'>
|
|
||||||
<input
|
|
||||||
name={name}
|
|
||||||
type='radio'
|
|
||||||
value={value}
|
|
||||||
checked={checked}
|
|
||||||
onChange={onChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<span className={classNames('radio-button__input', { checked })} />
|
|
||||||
|
|
||||||
<span>{label}</span>
|
|
||||||
</label>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import React from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
value: string;
|
||||||
|
checked: boolean;
|
||||||
|
name: string;
|
||||||
|
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
label: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RadioButton: React.FC<Props> = ({ name, value, checked, onChange, label }) => {
|
||||||
|
return (
|
||||||
|
<label className='radio-button'>
|
||||||
|
<input
|
||||||
|
name={name}
|
||||||
|
type='radio'
|
||||||
|
value={value}
|
||||||
|
checked={checked}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span className={classNames('radio-button__input', { checked })} />
|
||||||
|
|
||||||
|
<span>{label}</span>
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RadioButton;
|
|
@ -8,6 +8,7 @@ import IntersectionObserverWrapper from '../features/ui/util/intersection_observ
|
||||||
import { throttle } from 'lodash';
|
import { throttle } from 'lodash';
|
||||||
import { List as ImmutableList } from 'immutable';
|
import { List as ImmutableList } from 'immutable';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||||
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../features/ui/util/fullscreen';
|
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../features/ui/util/fullscreen';
|
||||||
import LoadingIndicator from './loading_indicator';
|
import LoadingIndicator from './loading_indicator';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
@ -236,10 +237,10 @@ class ScrollableList extends PureComponent {
|
||||||
attachScrollListener () {
|
attachScrollListener () {
|
||||||
if (this.props.bindToDocument) {
|
if (this.props.bindToDocument) {
|
||||||
document.addEventListener('scroll', this.handleScroll);
|
document.addEventListener('scroll', this.handleScroll);
|
||||||
document.addEventListener('wheel', this.handleWheel);
|
document.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : undefined);
|
||||||
} else {
|
} else {
|
||||||
this.node.addEventListener('scroll', this.handleScroll);
|
this.node.addEventListener('scroll', this.handleScroll);
|
||||||
this.node.addEventListener('wheel', this.handleWheel);
|
this.node.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Icon from 'mastodon/components/icon';
|
|
||||||
|
|
||||||
class VerifiedBadge extends React.PureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
link: PropTypes.string.isRequired,
|
|
||||||
verifiedAt: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { link } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span className='verified-badge'>
|
|
||||||
<Icon id='check' className='verified-badge__mark' />
|
|
||||||
<span dangerouslySetInnerHTML={{ __html: link }} />
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default VerifiedBadge;
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Icon } from './icon';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
link: string;
|
||||||
|
};
|
||||||
|
export const VerifiedBadge: React.FC<Props> = ({ link }) => (
|
||||||
|
<span className='verified-badge'>
|
||||||
|
<Icon id='check' className='verified-badge__mark' />
|
||||||
|
<span dangerouslySetInnerHTML={{ __html: link }} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default VerifiedBadge;
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { blockDomain, unblockDomain } from '../actions/domain_blocks';
|
import { blockDomain, unblockDomain } from '../actions/domain_blocks';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import Domain from '../components/domain';
|
import { Domain } from '../components/domain';
|
||||||
import { openModal } from '../actions/modal';
|
import { openModal } from '../actions/modal';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
declare module '*.avif' {
|
||||||
|
const path: string;
|
||||||
|
export default path;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.gif' {
|
||||||
|
const path: string;
|
||||||
|
export default path;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.jpg' {
|
||||||
|
const path: string;
|
||||||
|
export default path;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.jpg' {
|
||||||
|
const path: string;
|
||||||
|
export default path;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.png' {
|
||||||
|
const path: string;
|
||||||
|
export default path;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.svg' {
|
||||||
|
const path: string;
|
||||||
|
export default path;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.webp' {
|
||||||
|
const path: string;
|
||||||
|
export default path;
|
||||||
|
}
|
|
@ -8,14 +8,17 @@
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"baseUrl": ".",
|
"baseUrl": "./",
|
||||||
"paths": {
|
"paths": {
|
||||||
"*": ["app/javascript/*"]
|
"*": ["app/javascript/*"],
|
||||||
|
"mastodon": ["app/javascript/mastodon"],
|
||||||
|
"mastodon/*": ["app/javascript/mastodon/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"app/javascript/mastodon",
|
"app/javascript/mastodon",
|
||||||
"app/javascript/flavours/glitch",
|
"app/javascript/packs",
|
||||||
"app/javascript/packs"
|
"app/javascript/types",
|
||||||
|
"app/javascript/flavours/glitch"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue