Merge remote-tracking branch 'parent/main' into kb_migration_development
This commit is contained in:
commit
551a676161
67 changed files with 751 additions and 548 deletions
29
.eslintrc.js
29
.eslintrc.js
|
@ -9,6 +9,7 @@ module.exports = {
|
||||||
'plugin:import/recommended',
|
'plugin:import/recommended',
|
||||||
'plugin:promise/recommended',
|
'plugin:promise/recommended',
|
||||||
'plugin:jsdoc/recommended',
|
'plugin:jsdoc/recommended',
|
||||||
|
'plugin:prettier/recommended',
|
||||||
],
|
],
|
||||||
|
|
||||||
env: {
|
env: {
|
||||||
|
@ -62,20 +63,9 @@ module.exports = {
|
||||||
},
|
},
|
||||||
|
|
||||||
rules: {
|
rules: {
|
||||||
'brace-style': 'warn',
|
|
||||||
'comma-dangle': ['error', 'always-multiline'],
|
|
||||||
'comma-spacing': [
|
|
||||||
'warn',
|
|
||||||
{
|
|
||||||
before: false,
|
|
||||||
after: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'comma-style': ['warn', 'last'],
|
|
||||||
'consistent-return': 'error',
|
'consistent-return': 'error',
|
||||||
'dot-notation': 'error',
|
'dot-notation': 'error',
|
||||||
eqeqeq: ['error', 'always', { 'null': 'ignore' }],
|
eqeqeq: ['error', 'always', { 'null': 'ignore' }],
|
||||||
indent: ['warn', 2],
|
|
||||||
'jsx-quotes': ['error', 'prefer-single'],
|
'jsx-quotes': ['error', 'prefer-single'],
|
||||||
'no-case-declarations': 'off',
|
'no-case-declarations': 'off',
|
||||||
'no-catch-shadow': 'error',
|
'no-catch-shadow': 'error',
|
||||||
|
@ -95,7 +85,6 @@ module.exports = {
|
||||||
{ property: 'substr', message: 'Use .slice instead of .substr.' },
|
{ property: 'substr', message: 'Use .slice instead of .substr.' },
|
||||||
],
|
],
|
||||||
'no-self-assign': 'off',
|
'no-self-assign': 'off',
|
||||||
'no-trailing-spaces': 'warn',
|
|
||||||
'no-unused-expressions': 'error',
|
'no-unused-expressions': 'error',
|
||||||
'no-unused-vars': 'off',
|
'no-unused-vars': 'off',
|
||||||
'@typescript-eslint/no-unused-vars': [
|
'@typescript-eslint/no-unused-vars': [
|
||||||
|
@ -107,29 +96,14 @@ module.exports = {
|
||||||
ignoreRestSiblings: true,
|
ignoreRestSiblings: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
'object-curly-spacing': ['error', 'always'],
|
|
||||||
'padded-blocks': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
classes: 'always',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
quotes: ['error', 'single'],
|
|
||||||
semi: 'error',
|
|
||||||
'valid-typeof': 'error',
|
'valid-typeof': 'error',
|
||||||
|
|
||||||
'react/jsx-filename-extension': ['error', { extensions: ['.jsx', 'tsx'] }],
|
'react/jsx-filename-extension': ['error', { extensions: ['.jsx', 'tsx'] }],
|
||||||
'react/jsx-boolean-value': 'error',
|
'react/jsx-boolean-value': 'error',
|
||||||
'react/jsx-closing-bracket-location': ['error', 'line-aligned'],
|
|
||||||
'react/jsx-curly-spacing': 'error',
|
|
||||||
'react/display-name': 'off',
|
'react/display-name': 'off',
|
||||||
'react/jsx-equals-spacing': 'error',
|
'react/jsx-equals-spacing': 'error',
|
||||||
'react/jsx-first-prop-new-line': ['error', 'multiline-multiprop'],
|
|
||||||
'react/jsx-indent': ['error', 2],
|
|
||||||
'react/jsx-no-bind': 'error',
|
'react/jsx-no-bind': 'error',
|
||||||
'react/jsx-no-target-blank': 'off',
|
'react/jsx-no-target-blank': 'off',
|
||||||
'react/jsx-tag-spacing': 'error',
|
|
||||||
'react/jsx-wrap-multilines': 'error',
|
|
||||||
'react/no-deprecated': 'off',
|
'react/no-deprecated': 'off',
|
||||||
'react/no-unknown-property': 'off',
|
'react/no-unknown-property': 'off',
|
||||||
'react/self-closing-comp': 'error',
|
'react/self-closing-comp': 'error',
|
||||||
|
@ -291,6 +265,7 @@ module.exports = {
|
||||||
'plugin:import/typescript',
|
'plugin:import/typescript',
|
||||||
'plugin:promise/recommended',
|
'plugin:promise/recommended',
|
||||||
'plugin:jsdoc/recommended',
|
'plugin:jsdoc/recommended',
|
||||||
|
'plugin:prettier/recommended',
|
||||||
],
|
],
|
||||||
|
|
||||||
rules: {
|
rules: {
|
||||||
|
|
4
.github/dependabot.yml
vendored
4
.github/dependabot.yml
vendored
|
@ -17,10 +17,6 @@ updates:
|
||||||
- dependency-name: '@rails/ujs'
|
- dependency-name: '@rails/ujs'
|
||||||
versions:
|
versions:
|
||||||
- '>= 7'
|
- '>= 7'
|
||||||
# TODO: This was ignored in https://github.com/mastodon/mastodon/pull/19120
|
|
||||||
- dependency-name: 'uuid'
|
|
||||||
versions:
|
|
||||||
- '>= 9'
|
|
||||||
# TODO: This requires code changes for migration
|
# TODO: This requires code changes for migration
|
||||||
- dependency-name: 'tesseract.js'
|
- dependency-name: 'tesseract.js'
|
||||||
versions:
|
versions:
|
||||||
|
|
|
@ -70,8 +70,6 @@ app/javascript/styles/mastodon/reset.scss
|
||||||
# Ignore Javascript pending https://github.com/mastodon/mastodon/pull/23631
|
# Ignore Javascript pending https://github.com/mastodon/mastodon/pull/23631
|
||||||
*.js
|
*.js
|
||||||
*.jsx
|
*.jsx
|
||||||
*.ts
|
|
||||||
*.tsx
|
|
||||||
|
|
||||||
# Ignore HTML till cleaned and included in CI
|
# Ignore HTML till cleaned and included in CI
|
||||||
*.html
|
*.html
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
singleQuote: true
|
singleQuote: true,
|
||||||
|
jsxSingleQuote: true
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,7 +165,7 @@ Metrics/MethodLength:
|
||||||
- 'lib/mastodon/*_cli.rb'
|
- 'lib/mastodon/*_cli.rb'
|
||||||
|
|
||||||
# Reason:
|
# Reason:
|
||||||
# https://docs.rubocop.org/rubocop/cops_style.html#stylerescuestandarderror
|
# https://docs.rubocop.org/rubocop/cops_metrics.html#metricsmodulelength
|
||||||
Metrics/ModuleLength:
|
Metrics/ModuleLength:
|
||||||
CountAsOne: [array, heredoc]
|
CountAsOne: [array, heredoc]
|
||||||
|
|
||||||
|
|
|
@ -98,9 +98,9 @@ export const decode83 = (str: string) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const intToRGB = (int: number) => ({
|
export const intToRGB = (int: number) => ({
|
||||||
r: Math.max(0, (int >> 16)),
|
r: Math.max(0, int >> 16),
|
||||||
g: Math.max(0, (int >> 8) & 255),
|
g: Math.max(0, (int >> 8) & 255),
|
||||||
b: Math.max(0, (int & 255)),
|
b: Math.max(0, int & 255),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getAverageFromBlurhash = (blurhash: string) => {
|
export const getAverageFromBlurhash = (blurhash: string) => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export function compareId (id1: string, id2: string) {
|
export function compareId(id1: string, id2: string) {
|
||||||
if (id1 === id2) {
|
if (id1 === id2) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import renderer from 'react-test-renderer';
|
import renderer from 'react-test-renderer';
|
||||||
import { fromJS } from 'immutable';
|
import { fromJS } from 'immutable';
|
||||||
import DisplayName from '../display_name';
|
import { DisplayName } from '../display_name';
|
||||||
|
|
||||||
describe('<DisplayName />', () => {
|
describe('<DisplayName />', () => {
|
||||||
it('renders display name + account name', () => {
|
it('renders display name + account name', () => {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Avatar } from './avatar';
|
import { Avatar } from './avatar';
|
||||||
import DisplayName from './display_name';
|
import { DisplayName } from './display_name';
|
||||||
import { IconButton } from './icon_button';
|
import { IconButton } from './icon_button';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
|
@ -16,13 +16,10 @@ const obfuscatedCount = (count: number) => {
|
||||||
type Props = {
|
type Props = {
|
||||||
value: number;
|
value: number;
|
||||||
obfuscate?: boolean;
|
obfuscate?: boolean;
|
||||||
}
|
};
|
||||||
export const AnimatedNumber: React.FC<Props> = ({
|
export const AnimatedNumber: React.FC<Props> = ({ value, obfuscate }) => {
|
||||||
value,
|
|
||||||
obfuscate,
|
|
||||||
})=> {
|
|
||||||
const [previousValue, setPreviousValue] = useState(value);
|
const [previousValue, setPreviousValue] = useState(value);
|
||||||
const [direction, setDirection] = useState<1|-1>(1);
|
const [direction, setDirection] = useState<1 | -1>(1);
|
||||||
|
|
||||||
if (previousValue !== value) {
|
if (previousValue !== value) {
|
||||||
setPreviousValue(value);
|
setPreviousValue(value);
|
||||||
|
@ -30,24 +27,45 @@ export const AnimatedNumber: React.FC<Props> = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
const willEnter = useCallback(() => ({ y: -1 * direction }), [direction]);
|
const willEnter = useCallback(() => ({ y: -1 * direction }), [direction]);
|
||||||
const willLeave = useCallback(() => ({ y: spring(1 * direction, { damping: 35, stiffness: 400 }) }), [direction]);
|
const willLeave = useCallback(
|
||||||
|
() => ({ y: spring(1 * direction, { damping: 35, stiffness: 400 }) }),
|
||||||
|
[direction]
|
||||||
|
);
|
||||||
|
|
||||||
if (reduceMotion) {
|
if (reduceMotion) {
|
||||||
return obfuscate ? <>{obfuscatedCount(value)}</> : <ShortNumber value={value} />;
|
return obfuscate ? (
|
||||||
|
<>{obfuscatedCount(value)}</>
|
||||||
|
) : (
|
||||||
|
<ShortNumber value={value} />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = [{
|
const styles = [
|
||||||
key: `${value}`,
|
{
|
||||||
data: value,
|
key: `${value}`,
|
||||||
style: { y: spring(0, { damping: 35, stiffness: 400 }) },
|
data: value,
|
||||||
}];
|
style: { y: spring(0, { damping: 35, stiffness: 400 }) },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TransitionMotion styles={styles} willEnter={willEnter} willLeave={willLeave}>
|
<TransitionMotion
|
||||||
{items => (
|
styles={styles}
|
||||||
|
willEnter={willEnter}
|
||||||
|
willLeave={willLeave}
|
||||||
|
>
|
||||||
|
{(items) => (
|
||||||
<span className='animated-number'>
|
<span className='animated-number'>
|
||||||
{items.map(({ key, data, style }) => (
|
{items.map(({ key, data, style }) => (
|
||||||
<span key={key} style={{ position: (direction * style.y) > 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}>{obfuscate ? obfuscatedCount(data) : <ShortNumber value={data} />}</span>
|
<span
|
||||||
|
key={key}
|
||||||
|
style={{
|
||||||
|
position: direction * style.y > 0 ? 'absolute' : 'static',
|
||||||
|
transform: `translateY(${style.y * 100}%)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{obfuscate ? obfuscatedCount(data) : <ShortNumber value={data} />}
|
||||||
|
</span>
|
||||||
))}
|
))}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -18,13 +18,19 @@ export const AvatarOverlay: React.FC<Props> = ({
|
||||||
baseSize = 36,
|
baseSize = 36,
|
||||||
overlaySize = 24,
|
overlaySize = 24,
|
||||||
}) => {
|
}) => {
|
||||||
const { hovering, handleMouseEnter, handleMouseLeave } = useHovering(autoPlayGif);
|
const { hovering, handleMouseEnter, handleMouseLeave } =
|
||||||
const accountSrc = hovering ? account?.get('avatar') : account?.get('avatar_static');
|
useHovering(autoPlayGif);
|
||||||
const friendSrc = hovering ? friend?.get('avatar') : friend?.get('avatar_static');
|
const accountSrc = hovering
|
||||||
|
? account?.get('avatar')
|
||||||
|
: account?.get('avatar_static');
|
||||||
|
const friendSrc = hovering
|
||||||
|
? friend?.get('avatar')
|
||||||
|
: friend?.get('avatar_static');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='account__avatar-overlay' style={{ width: size, height: size }}
|
className='account__avatar-overlay'
|
||||||
|
style={{ width: size, height: size }}
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
>
|
>
|
||||||
|
|
|
@ -8,7 +8,7 @@ type Props = {
|
||||||
dummy?: boolean; // Whether dummy mode is enabled. If enabled, nothing is rendered and canvas left untouched
|
dummy?: boolean; // Whether dummy mode is enabled. If enabled, nothing is rendered and canvas left untouched
|
||||||
children?: never;
|
children?: never;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
};
|
||||||
const Blurhash: React.FC<Props> = ({
|
const Blurhash: React.FC<Props> = ({
|
||||||
hash,
|
hash,
|
||||||
width = 32,
|
width = 32,
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export const Check: React.FC = () => (
|
export const Check: React.FC = () => (
|
||||||
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='currentColor'>
|
<svg
|
||||||
<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' />
|
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'
|
||||||
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { autoPlayGif } from 'mastodon/initial_state';
|
|
||||||
import Skeleton from 'mastodon/components/skeleton';
|
|
||||||
|
|
||||||
export default class DisplayName extends React.PureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
account: ImmutablePropTypes.map,
|
|
||||||
others: ImmutablePropTypes.list,
|
|
||||||
localDomain: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMouseEnter = ({ currentTarget }) => {
|
|
||||||
if (autoPlayGif) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const emojis = currentTarget.querySelectorAll('.custom-emoji');
|
|
||||||
|
|
||||||
for (var i = 0; i < emojis.length; i++) {
|
|
||||||
let emoji = emojis[i];
|
|
||||||
emoji.src = emoji.getAttribute('data-original');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleMouseLeave = ({ currentTarget }) => {
|
|
||||||
if (autoPlayGif) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const emojis = currentTarget.querySelectorAll('.custom-emoji');
|
|
||||||
|
|
||||||
for (var i = 0; i < emojis.length; i++) {
|
|
||||||
let emoji = emojis[i];
|
|
||||||
emoji.src = emoji.getAttribute('data-static');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { others, localDomain } = this.props;
|
|
||||||
|
|
||||||
let displayName, suffix, account;
|
|
||||||
|
|
||||||
if (others && others.size > 1) {
|
|
||||||
displayName = others.take(2).map(a => <bdi key={a.get('id')}><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: a.get('display_name_html') }} /></bdi>).reduce((prev, cur) => [prev, ', ', cur]);
|
|
||||||
|
|
||||||
if (others.size - 2 > 0) {
|
|
||||||
suffix = `+${others.size - 2}`;
|
|
||||||
}
|
|
||||||
} else if ((others && others.size > 0) || this.props.account) {
|
|
||||||
if (others && others.size > 0) {
|
|
||||||
account = others.first();
|
|
||||||
} else {
|
|
||||||
account = this.props.account;
|
|
||||||
}
|
|
||||||
|
|
||||||
let acct = account.get('acct');
|
|
||||||
|
|
||||||
if (acct.indexOf('@') === -1 && localDomain) {
|
|
||||||
acct = `${acct}@${localDomain}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
displayName = <bdi><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} /></bdi>;
|
|
||||||
suffix = <span className='display-name__account'>@{acct}</span>;
|
|
||||||
} else {
|
|
||||||
displayName = <bdi><strong className='display-name__html'><Skeleton width='10ch' /></strong></bdi>;
|
|
||||||
suffix = <span className='display-name__account'><Skeleton width='7ch' /></span>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span className='display-name' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
|
||||||
{displayName} {suffix}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
115
app/javascript/mastodon/components/display_name.tsx
Normal file
115
app/javascript/mastodon/components/display_name.tsx
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { autoPlayGif } from '..//initial_state';
|
||||||
|
import Skeleton from './skeleton';
|
||||||
|
import { Account } from '../../types/resources';
|
||||||
|
import { List } from 'immutable';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
account: Account;
|
||||||
|
others: List<Account>;
|
||||||
|
localDomain: string;
|
||||||
|
};
|
||||||
|
export class DisplayName extends React.PureComponent<Props> {
|
||||||
|
handleMouseEnter: React.ReactEventHandler<HTMLSpanElement> = ({
|
||||||
|
currentTarget,
|
||||||
|
}) => {
|
||||||
|
if (autoPlayGif) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const emojis =
|
||||||
|
currentTarget.querySelectorAll<HTMLImageElement>('img.custom-emoji');
|
||||||
|
|
||||||
|
emojis.forEach((emoji) => {
|
||||||
|
const originalSrc = emoji.getAttribute('data-original');
|
||||||
|
if (originalSrc != null) emoji.src = originalSrc;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleMouseLeave: React.ReactEventHandler<HTMLSpanElement> = ({
|
||||||
|
currentTarget,
|
||||||
|
}) => {
|
||||||
|
if (autoPlayGif) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const emojis =
|
||||||
|
currentTarget.querySelectorAll<HTMLImageElement>('img.custom-emoji');
|
||||||
|
|
||||||
|
emojis.forEach((emoji) => {
|
||||||
|
const staticSrc = emoji.getAttribute('data-static');
|
||||||
|
if (staticSrc != null) emoji.src = staticSrc;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { others, localDomain } = this.props;
|
||||||
|
|
||||||
|
let displayName: React.ReactNode, suffix: React.ReactNode, account: Account;
|
||||||
|
|
||||||
|
if (others && others.size > 1) {
|
||||||
|
displayName = others
|
||||||
|
.take(2)
|
||||||
|
.map((a) => (
|
||||||
|
<bdi key={a.get('id')}>
|
||||||
|
<strong
|
||||||
|
className='display-name__html'
|
||||||
|
dangerouslySetInnerHTML={{ __html: a.get('display_name_html') }}
|
||||||
|
/>
|
||||||
|
</bdi>
|
||||||
|
))
|
||||||
|
.reduce((prev, cur) => [prev, ', ', cur]);
|
||||||
|
|
||||||
|
if (others.size - 2 > 0) {
|
||||||
|
suffix = `+${others.size - 2}`;
|
||||||
|
}
|
||||||
|
} else if ((others && others.size > 0) || this.props.account) {
|
||||||
|
if (others && others.size > 0) {
|
||||||
|
account = others.first();
|
||||||
|
} else {
|
||||||
|
account = this.props.account;
|
||||||
|
}
|
||||||
|
|
||||||
|
let acct = account.get('acct');
|
||||||
|
|
||||||
|
if (acct.indexOf('@') === -1 && localDomain) {
|
||||||
|
acct = `${acct}@${localDomain}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
displayName = (
|
||||||
|
<bdi>
|
||||||
|
<strong
|
||||||
|
className='display-name__html'
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: account.get('display_name_html'),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</bdi>
|
||||||
|
);
|
||||||
|
suffix = <span className='display-name__account'>@{acct}</span>;
|
||||||
|
} else {
|
||||||
|
displayName = (
|
||||||
|
<bdi>
|
||||||
|
<strong className='display-name__html'>
|
||||||
|
<Skeleton width='10ch' />
|
||||||
|
</strong>
|
||||||
|
</bdi>
|
||||||
|
);
|
||||||
|
suffix = (
|
||||||
|
<span className='display-name__account'>
|
||||||
|
<Skeleton width='7ch' />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
className='display-name'
|
||||||
|
onMouseEnter={this.handleMouseEnter}
|
||||||
|
onMouseLeave={this.handleMouseLeave}
|
||||||
|
>
|
||||||
|
{displayName} {suffix}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ type Props = {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const GIFV: React.FC<Props> = ({
|
export const GIFV: React.FC<Props> = ({
|
||||||
src,
|
src,
|
||||||
|
@ -17,19 +17,23 @@ export const GIFV: React.FC<Props> = ({
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
onClick,
|
onClick,
|
||||||
})=> {
|
}) => {
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
const handleLoadedData: React.ReactEventHandler<HTMLVideoElement> = useCallback(() => {
|
const handleLoadedData: React.ReactEventHandler<HTMLVideoElement> =
|
||||||
setLoading(false);
|
useCallback(() => {
|
||||||
}, [setLoading]);
|
setLoading(false);
|
||||||
|
}, [setLoading]);
|
||||||
|
|
||||||
const handleClick: React.MouseEventHandler = useCallback((e) => {
|
const handleClick: React.MouseEventHandler = useCallback(
|
||||||
if (onClick) {
|
(e) => {
|
||||||
e.stopPropagation();
|
if (onClick) {
|
||||||
onClick();
|
e.stopPropagation();
|
||||||
}
|
onClick();
|
||||||
}, [onClick]);
|
}
|
||||||
|
},
|
||||||
|
[onClick]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='gifv' style={{ position: 'relative' }}>
|
<div className='gifv' style={{ position: 'relative' }}>
|
||||||
|
|
|
@ -7,6 +7,15 @@ type Props = {
|
||||||
fixedWidth?: boolean;
|
fixedWidth?: boolean;
|
||||||
children?: never;
|
children?: never;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
};
|
||||||
export const Icon: React.FC<Props> = ({ id, className, fixedWidth, ...other }) =>
|
export const Icon: React.FC<Props> = ({
|
||||||
<i className={classNames('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })} {...other} />;
|
id,
|
||||||
|
className,
|
||||||
|
fixedWidth,
|
||||||
|
...other
|
||||||
|
}) => (
|
||||||
|
<i
|
||||||
|
className={classNames('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })}
|
||||||
|
{...other}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
|
@ -25,13 +25,12 @@ type Props = {
|
||||||
obfuscateCount?: boolean;
|
obfuscateCount?: boolean;
|
||||||
href?: string;
|
href?: string;
|
||||||
ariaHidden: boolean;
|
ariaHidden: boolean;
|
||||||
}
|
};
|
||||||
type States = {
|
type States = {
|
||||||
activate: boolean,
|
activate: boolean;
|
||||||
deactivate: boolean,
|
deactivate: boolean;
|
||||||
}
|
};
|
||||||
export class IconButton extends React.PureComponent<Props, States> {
|
export class IconButton extends React.PureComponent<Props, States> {
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
size: 18,
|
size: 18,
|
||||||
active: false,
|
active: false,
|
||||||
|
@ -47,7 +46,7 @@ export class IconButton extends React.PureComponent<Props, States> {
|
||||||
deactivate: false,
|
deactivate: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
UNSAFE_componentWillReceiveProps (nextProps: Props) {
|
UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||||
if (!nextProps.animate) return;
|
if (!nextProps.animate) return;
|
||||||
|
|
||||||
if (this.props.active && !nextProps.active) {
|
if (this.props.active && !nextProps.active) {
|
||||||
|
@ -57,7 +56,7 @@ export class IconButton extends React.PureComponent<Props, States> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClick: React.MouseEventHandler<HTMLButtonElement> = (e) => {
|
handleClick: React.MouseEventHandler<HTMLButtonElement> = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (!this.props.disabled && this.props.onClick != null) {
|
if (!this.props.disabled && this.props.onClick != null) {
|
||||||
|
@ -83,7 +82,7 @@ export class IconButton extends React.PureComponent<Props, States> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render() {
|
||||||
const style = {
|
const style = {
|
||||||
fontSize: `${this.props.size}px`,
|
fontSize: `${this.props.size}px`,
|
||||||
width: `${this.props.size * 1.28571429}px`,
|
width: `${this.props.size * 1.28571429}px`,
|
||||||
|
@ -109,10 +108,7 @@ export class IconButton extends React.PureComponent<Props, States> {
|
||||||
ariaHidden,
|
ariaHidden,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const { activate, deactivate } = this.state;
|
||||||
activate,
|
|
||||||
deactivate,
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
const classes = classNames(className, 'icon-button', {
|
const classes = classNames(className, 'icon-button', {
|
||||||
active,
|
active,
|
||||||
|
@ -130,7 +126,12 @@ export class IconButton extends React.PureComponent<Props, States> {
|
||||||
|
|
||||||
let contents = (
|
let contents = (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Icon id={icon} fixedWidth aria-hidden='true' /> {typeof counter !== 'undefined' && <span className='icon-button__counter'><AnimatedNumber value={counter} obfuscate={obfuscateCount} /></span>}
|
<Icon id={icon} fixedWidth aria-hidden='true' />{' '}
|
||||||
|
{typeof counter !== 'undefined' && (
|
||||||
|
<span className='icon-button__counter'>
|
||||||
|
<AnimatedNumber value={counter} obfuscate={obfuscateCount} />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -162,5 +163,4 @@ export class IconButton extends React.PureComponent<Props, States> {
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,25 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Icon } from './icon';
|
import { Icon } from './icon';
|
||||||
|
|
||||||
const formatNumber = (num: number): number | string => num > 40 ? '40+' : num;
|
const formatNumber = (num: number): number | string => (num > 40 ? '40+' : num);
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
id: string;
|
id: string;
|
||||||
count: number;
|
count: number;
|
||||||
issueBadge: boolean;
|
issueBadge: boolean;
|
||||||
className: string;
|
className: string;
|
||||||
}
|
};
|
||||||
export const IconWithBadge: React.FC<Props> = ({ id, count, issueBadge, className }) => (
|
export const IconWithBadge: React.FC<Props> = ({
|
||||||
|
id,
|
||||||
|
count,
|
||||||
|
issueBadge,
|
||||||
|
className,
|
||||||
|
}) => (
|
||||||
<i className='icon-with-badge'>
|
<i className='icon-with-badge'>
|
||||||
<Icon id={id} fixedWidth className={className} />
|
<Icon id={id} fixedWidth className={className} />
|
||||||
{count > 0 && <i className='icon-with-badge__badge'>{formatNumber(count)}</i>}
|
{count > 0 && (
|
||||||
|
<i className='icon-with-badge__badge'>{formatNumber(count)}</i>
|
||||||
|
)}
|
||||||
{issueBadge && <i className='icon-with-badge__issue-badge' />}
|
{issueBadge && <i className='icon-with-badge__issue-badge' />}
|
||||||
</i>
|
</i>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,7 +4,10 @@ import { FormattedMessage } from 'react-intl';
|
||||||
export const NotSignedInIndicator: React.FC = () => (
|
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.'
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,7 +9,13 @@ type Props = {
|
||||||
label: React.ReactNode;
|
label: React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RadioButton: React.FC<Props> = ({ name, value, checked, onChange, label }) => {
|
export const RadioButton: React.FC<Props> = ({
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
checked,
|
||||||
|
onChange,
|
||||||
|
label,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<label className='radio-button'>
|
<label className='radio-button'>
|
||||||
<input
|
<input
|
||||||
|
|
|
@ -4,20 +4,50 @@ import { injectIntl, defineMessages, InjectedIntl } from 'react-intl';
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
today: { id: 'relative_time.today', defaultMessage: 'today' },
|
today: { id: 'relative_time.today', defaultMessage: 'today' },
|
||||||
just_now: { id: 'relative_time.just_now', defaultMessage: 'now' },
|
just_now: { id: 'relative_time.just_now', defaultMessage: 'now' },
|
||||||
just_now_full: { id: 'relative_time.full.just_now', defaultMessage: 'just now' },
|
just_now_full: {
|
||||||
|
id: 'relative_time.full.just_now',
|
||||||
|
defaultMessage: 'just now',
|
||||||
|
},
|
||||||
seconds: { id: 'relative_time.seconds', defaultMessage: '{number}s' },
|
seconds: { id: 'relative_time.seconds', defaultMessage: '{number}s' },
|
||||||
seconds_full: { id: 'relative_time.full.seconds', defaultMessage: '{number, plural, one {# second} other {# seconds}} ago' },
|
seconds_full: {
|
||||||
|
id: 'relative_time.full.seconds',
|
||||||
|
defaultMessage: '{number, plural, one {# second} other {# seconds}} ago',
|
||||||
|
},
|
||||||
minutes: { id: 'relative_time.minutes', defaultMessage: '{number}m' },
|
minutes: { id: 'relative_time.minutes', defaultMessage: '{number}m' },
|
||||||
minutes_full: { id: 'relative_time.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}} ago' },
|
minutes_full: {
|
||||||
|
id: 'relative_time.full.minutes',
|
||||||
|
defaultMessage: '{number, plural, one {# minute} other {# minutes}} ago',
|
||||||
|
},
|
||||||
hours: { id: 'relative_time.hours', defaultMessage: '{number}h' },
|
hours: { id: 'relative_time.hours', defaultMessage: '{number}h' },
|
||||||
hours_full: { id: 'relative_time.full.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}} ago' },
|
hours_full: {
|
||||||
|
id: 'relative_time.full.hours',
|
||||||
|
defaultMessage: '{number, plural, one {# hour} other {# hours}} ago',
|
||||||
|
},
|
||||||
days: { id: 'relative_time.days', defaultMessage: '{number}d' },
|
days: { id: 'relative_time.days', defaultMessage: '{number}d' },
|
||||||
days_full: { id: 'relative_time.full.days', defaultMessage: '{number, plural, one {# day} other {# days}} ago' },
|
days_full: {
|
||||||
moments_remaining: { id: 'time_remaining.moments', defaultMessage: 'Moments remaining' },
|
id: 'relative_time.full.days',
|
||||||
seconds_remaining: { id: 'time_remaining.seconds', defaultMessage: '{number, plural, one {# second} other {# seconds}} left' },
|
defaultMessage: '{number, plural, one {# day} other {# days}} ago',
|
||||||
minutes_remaining: { id: 'time_remaining.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}} left' },
|
},
|
||||||
hours_remaining: { id: 'time_remaining.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}} left' },
|
moments_remaining: {
|
||||||
days_remaining: { id: 'time_remaining.days', defaultMessage: '{number, plural, one {# day} other {# days}} left' },
|
id: 'time_remaining.moments',
|
||||||
|
defaultMessage: 'Moments remaining',
|
||||||
|
},
|
||||||
|
seconds_remaining: {
|
||||||
|
id: 'time_remaining.seconds',
|
||||||
|
defaultMessage: '{number, plural, one {# second} other {# seconds}} left',
|
||||||
|
},
|
||||||
|
minutes_remaining: {
|
||||||
|
id: 'time_remaining.minutes',
|
||||||
|
defaultMessage: '{number, plural, one {# minute} other {# minutes}} left',
|
||||||
|
},
|
||||||
|
hours_remaining: {
|
||||||
|
id: 'time_remaining.hours',
|
||||||
|
defaultMessage: '{number, plural, one {# hour} other {# hours}} left',
|
||||||
|
},
|
||||||
|
days_remaining: {
|
||||||
|
id: 'time_remaining.days',
|
||||||
|
defaultMessage: '{number, plural, one {# day} other {# days}} left',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const dateFormatOptions = {
|
const dateFormatOptions = {
|
||||||
|
@ -36,8 +66,8 @@ const shortDateFormatOptions = {
|
||||||
|
|
||||||
const SECOND = 1000;
|
const SECOND = 1000;
|
||||||
const MINUTE = 1000 * 60;
|
const MINUTE = 1000 * 60;
|
||||||
const HOUR = 1000 * 60 * 60;
|
const HOUR = 1000 * 60 * 60;
|
||||||
const DAY = 1000 * 60 * 60 * 24;
|
const DAY = 1000 * 60 * 60 * 24;
|
||||||
|
|
||||||
const MAX_DELAY = 2147483647;
|
const MAX_DELAY = 2147483647;
|
||||||
|
|
||||||
|
@ -57,20 +87,27 @@ const selectUnits = (delta: number) => {
|
||||||
|
|
||||||
const getUnitDelay = (units: string) => {
|
const getUnitDelay = (units: string) => {
|
||||||
switch (units) {
|
switch (units) {
|
||||||
case 'second':
|
case 'second':
|
||||||
return SECOND;
|
return SECOND;
|
||||||
case 'minute':
|
case 'minute':
|
||||||
return MINUTE;
|
return MINUTE;
|
||||||
case 'hour':
|
case 'hour':
|
||||||
return HOUR;
|
return HOUR;
|
||||||
case 'day':
|
case 'day':
|
||||||
return DAY;
|
return DAY;
|
||||||
default:
|
default:
|
||||||
return MAX_DELAY;
|
return MAX_DELAY;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const timeAgoString = (intl: InjectedIntl, date: Date, now: number, year: number, timeGiven: boolean, short?: boolean) => {
|
export const timeAgoString = (
|
||||||
|
intl: InjectedIntl,
|
||||||
|
date: Date,
|
||||||
|
now: number,
|
||||||
|
year: number,
|
||||||
|
timeGiven: boolean,
|
||||||
|
short?: boolean
|
||||||
|
) => {
|
||||||
const delta = now - date.getTime();
|
const delta = now - date.getTime();
|
||||||
|
|
||||||
let relativeTime;
|
let relativeTime;
|
||||||
|
@ -78,27 +115,49 @@ export const timeAgoString = (intl: InjectedIntl, date: Date, now: number, year:
|
||||||
if (delta < DAY && !timeGiven) {
|
if (delta < DAY && !timeGiven) {
|
||||||
relativeTime = intl.formatMessage(messages.today);
|
relativeTime = intl.formatMessage(messages.today);
|
||||||
} else if (delta < 10 * SECOND) {
|
} else if (delta < 10 * SECOND) {
|
||||||
relativeTime = intl.formatMessage(short ? messages.just_now : messages.just_now_full);
|
relativeTime = intl.formatMessage(
|
||||||
|
short ? messages.just_now : messages.just_now_full
|
||||||
|
);
|
||||||
} else if (delta < 7 * DAY) {
|
} else if (delta < 7 * DAY) {
|
||||||
if (delta < MINUTE) {
|
if (delta < MINUTE) {
|
||||||
relativeTime = intl.formatMessage(short ? messages.seconds : messages.seconds_full, { number: Math.floor(delta / SECOND) });
|
relativeTime = intl.formatMessage(
|
||||||
|
short ? messages.seconds : messages.seconds_full,
|
||||||
|
{ number: Math.floor(delta / SECOND) }
|
||||||
|
);
|
||||||
} else if (delta < HOUR) {
|
} else if (delta < HOUR) {
|
||||||
relativeTime = intl.formatMessage(short ? messages.minutes : messages.minutes_full, { number: Math.floor(delta / MINUTE) });
|
relativeTime = intl.formatMessage(
|
||||||
|
short ? messages.minutes : messages.minutes_full,
|
||||||
|
{ number: Math.floor(delta / MINUTE) }
|
||||||
|
);
|
||||||
} else if (delta < DAY) {
|
} else if (delta < DAY) {
|
||||||
relativeTime = intl.formatMessage(short ? messages.hours : messages.hours_full, { number: Math.floor(delta / HOUR) });
|
relativeTime = intl.formatMessage(
|
||||||
|
short ? messages.hours : messages.hours_full,
|
||||||
|
{ number: Math.floor(delta / HOUR) }
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
relativeTime = intl.formatMessage(short ? messages.days : messages.days_full, { number: Math.floor(delta / DAY) });
|
relativeTime = intl.formatMessage(
|
||||||
|
short ? messages.days : messages.days_full,
|
||||||
|
{ number: Math.floor(delta / DAY) }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if (date.getFullYear() === year) {
|
} else if (date.getFullYear() === year) {
|
||||||
relativeTime = intl.formatDate(date, shortDateFormatOptions);
|
relativeTime = intl.formatDate(date, shortDateFormatOptions);
|
||||||
} else {
|
} else {
|
||||||
relativeTime = intl.formatDate(date, { ...shortDateFormatOptions, year: 'numeric' });
|
relativeTime = intl.formatDate(date, {
|
||||||
|
...shortDateFormatOptions,
|
||||||
|
year: 'numeric',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return relativeTime;
|
return relativeTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
const timeRemainingString = (intl: InjectedIntl, date: Date, now: number, timeGiven = true) => {
|
const timeRemainingString = (
|
||||||
|
intl: InjectedIntl,
|
||||||
|
date: Date,
|
||||||
|
now: number,
|
||||||
|
timeGiven = true
|
||||||
|
) => {
|
||||||
const delta = date.getTime() - now;
|
const delta = date.getTime() - now;
|
||||||
|
|
||||||
let relativeTime;
|
let relativeTime;
|
||||||
|
@ -108,13 +167,21 @@ const timeRemainingString = (intl: InjectedIntl, date: Date, now: number, timeGi
|
||||||
} else if (delta < 10 * SECOND) {
|
} else if (delta < 10 * SECOND) {
|
||||||
relativeTime = intl.formatMessage(messages.moments_remaining);
|
relativeTime = intl.formatMessage(messages.moments_remaining);
|
||||||
} else if (delta < MINUTE) {
|
} else if (delta < MINUTE) {
|
||||||
relativeTime = intl.formatMessage(messages.seconds_remaining, { number: Math.floor(delta / SECOND) });
|
relativeTime = intl.formatMessage(messages.seconds_remaining, {
|
||||||
|
number: Math.floor(delta / SECOND),
|
||||||
|
});
|
||||||
} else if (delta < HOUR) {
|
} else if (delta < HOUR) {
|
||||||
relativeTime = intl.formatMessage(messages.minutes_remaining, { number: Math.floor(delta / MINUTE) });
|
relativeTime = intl.formatMessage(messages.minutes_remaining, {
|
||||||
|
number: Math.floor(delta / MINUTE),
|
||||||
|
});
|
||||||
} else if (delta < DAY) {
|
} else if (delta < DAY) {
|
||||||
relativeTime = intl.formatMessage(messages.hours_remaining, { number: Math.floor(delta / HOUR) });
|
relativeTime = intl.formatMessage(messages.hours_remaining, {
|
||||||
|
number: Math.floor(delta / HOUR),
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
relativeTime = intl.formatMessage(messages.days_remaining, { number: Math.floor(delta / DAY) });
|
relativeTime = intl.formatMessage(messages.days_remaining, {
|
||||||
|
number: Math.floor(delta / DAY),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return relativeTime;
|
return relativeTime;
|
||||||
|
@ -126,78 +193,86 @@ type Props = {
|
||||||
year: number;
|
year: number;
|
||||||
futureDate?: boolean;
|
futureDate?: boolean;
|
||||||
short?: boolean;
|
short?: boolean;
|
||||||
}
|
};
|
||||||
type States = {
|
type States = {
|
||||||
now: number;
|
now: number;
|
||||||
}
|
};
|
||||||
class RelativeTimestamp extends React.Component<Props, States> {
|
class RelativeTimestamp extends React.Component<Props, States> {
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
now: this.props.intl.now(),
|
now: this.props.intl.now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
year: (new Date()).getFullYear(),
|
year: new Date().getFullYear(),
|
||||||
short: true,
|
short: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
_timer: number | undefined;
|
_timer: number | undefined;
|
||||||
|
|
||||||
shouldComponentUpdate (nextProps: Props, nextState: States) {
|
shouldComponentUpdate(nextProps: Props, nextState: States) {
|
||||||
// As of right now the locale doesn't change without a new page load,
|
// As of right now the locale doesn't change without a new page load,
|
||||||
// but we might as well check in case that ever changes.
|
// but we might as well check in case that ever changes.
|
||||||
return this.props.timestamp !== nextProps.timestamp ||
|
return (
|
||||||
|
this.props.timestamp !== nextProps.timestamp ||
|
||||||
this.props.intl.locale !== nextProps.intl.locale ||
|
this.props.intl.locale !== nextProps.intl.locale ||
|
||||||
this.state.now !== nextState.now;
|
this.state.now !== nextState.now
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE_componentWillReceiveProps (nextProps: Props) {
|
UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||||
if (this.props.timestamp !== nextProps.timestamp) {
|
if (this.props.timestamp !== nextProps.timestamp) {
|
||||||
this.setState({ now: this.props.intl.now() });
|
this.setState({ now: this.props.intl.now() });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount() {
|
||||||
this._scheduleNextUpdate(this.props, this.state);
|
this._scheduleNextUpdate(this.props, this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE_componentWillUpdate (nextProps: Props, nextState: States) {
|
UNSAFE_componentWillUpdate(nextProps: Props, nextState: States) {
|
||||||
this._scheduleNextUpdate(nextProps, nextState);
|
this._scheduleNextUpdate(nextProps, nextState);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount() {
|
||||||
window.clearTimeout(this._timer);
|
window.clearTimeout(this._timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
_scheduleNextUpdate (props: Props, state: States) {
|
_scheduleNextUpdate(props: Props, state: States) {
|
||||||
window.clearTimeout(this._timer);
|
window.clearTimeout(this._timer);
|
||||||
|
|
||||||
const { timestamp } = props;
|
const { timestamp } = props;
|
||||||
const delta = (new Date(timestamp)).getTime() - state.now;
|
const delta = new Date(timestamp).getTime() - state.now;
|
||||||
const unitDelay = getUnitDelay(selectUnits(delta));
|
const unitDelay = getUnitDelay(selectUnits(delta));
|
||||||
const unitRemainder = Math.abs(delta % unitDelay);
|
const unitRemainder = Math.abs(delta % unitDelay);
|
||||||
const updateInterval = 1000 * 10;
|
const updateInterval = 1000 * 10;
|
||||||
const delay = delta < 0 ? Math.max(updateInterval, unitDelay - unitRemainder) : Math.max(updateInterval, unitRemainder);
|
const delay =
|
||||||
|
delta < 0
|
||||||
|
? Math.max(updateInterval, unitDelay - unitRemainder)
|
||||||
|
: Math.max(updateInterval, unitRemainder);
|
||||||
|
|
||||||
this._timer = window.setTimeout(() => {
|
this._timer = window.setTimeout(() => {
|
||||||
this.setState({ now: this.props.intl.now() });
|
this.setState({ now: this.props.intl.now() });
|
||||||
}, delay);
|
}, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render() {
|
||||||
const { timestamp, intl, year, futureDate, short } = this.props;
|
const { timestamp, intl, year, futureDate, short } = this.props;
|
||||||
|
|
||||||
const timeGiven = timestamp.includes('T');
|
const timeGiven = timestamp.includes('T');
|
||||||
const date = new Date(timestamp);
|
const date = new Date(timestamp);
|
||||||
const relativeTime = futureDate ? timeRemainingString(intl, date, this.state.now, timeGiven) : timeAgoString(intl, date, this.state.now, year, timeGiven, short);
|
const relativeTime = futureDate
|
||||||
|
? timeRemainingString(intl, date, this.state.now, timeGiven)
|
||||||
|
: timeAgoString(intl, date, this.state.now, year, timeGiven, short);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<time dateTime={timestamp} title={intl.formatDate(date, dateFormatOptions)}>
|
<time
|
||||||
|
dateTime={timestamp}
|
||||||
|
title={intl.formatDate(date, dateFormatOptions)}
|
||||||
|
>
|
||||||
{relativeTime}
|
{relativeTime}
|
||||||
</time>
|
</time>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const RelativeTimestampWithIntl = injectIntl(RelativeTimestamp);
|
const RelativeTimestampWithIntl = injectIntl(RelativeTimestamp);
|
||||||
|
|
|
@ -7,7 +7,7 @@ import ShortNumber from 'mastodon/components/short_number';
|
||||||
import Skeleton from 'mastodon/components/skeleton';
|
import Skeleton from 'mastodon/components/skeleton';
|
||||||
import Account from 'mastodon/containers/account_container';
|
import Account from 'mastodon/containers/account_container';
|
||||||
import { domain } from 'mastodon/initial_state';
|
import { domain } from 'mastodon/initial_state';
|
||||||
import { Image } from 'mastodon/components/image';
|
import { ServerHeroImage } from 'mastodon/components/server_hero_image';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
@ -41,7 +41,7 @@ class ServerBanner extends React.PureComponent {
|
||||||
<FormattedMessage id='server_banner.introduction' defaultMessage='{domain} is part of the decentralized social network powered by {mastodon}.' values={{ domain: <strong>{domain}</strong>, mastodon: <a href='https://joinmastodon.org' target='_blank'>Mastodon</a> }} />
|
<FormattedMessage id='server_banner.introduction' defaultMessage='{domain} is part of the decentralized social network powered by {mastodon}.' values={{ domain: <strong>{domain}</strong>, mastodon: <a href='https://joinmastodon.org' target='_blank'>Mastodon</a> }} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Image blurhash={server.getIn(['thumbnail', 'blurhash'])} src={server.getIn(['thumbnail', 'url'])} className='server-banner__hero' />
|
<ServerHeroImage blurhash={server.getIn(['thumbnail', 'blurhash'])} src={server.getIn(['thumbnail', 'url'])} className='server-banner__hero' />
|
||||||
|
|
||||||
<div className='server-banner__description'>
|
<div className='server-banner__description'>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
|
|
|
@ -7,9 +7,14 @@ type Props = {
|
||||||
srcSet?: string;
|
srcSet?: string;
|
||||||
blurhash?: string;
|
blurhash?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const Image: React.FC<Props> = ({ src, srcSet, blurhash, className }) => {
|
export const ServerHeroImage: React.FC<Props> = ({
|
||||||
|
src,
|
||||||
|
srcSet,
|
||||||
|
blurhash,
|
||||||
|
className,
|
||||||
|
}) => {
|
||||||
const [loaded, setLoaded] = useState(false);
|
const [loaded, setLoaded] = useState(false);
|
||||||
|
|
||||||
const handleLoad = useCallback(() => {
|
const handleLoad = useCallback(() => {
|
||||||
|
@ -17,7 +22,10 @@ export const Image: React.FC<Props> = ({ src, srcSet, blurhash, className }) =>
|
||||||
}, [setLoaded]);
|
}, [setLoaded]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames('image', { loaded }, className)} role='presentation'>
|
<div
|
||||||
|
className={classNames('image', { loaded }, className)}
|
||||||
|
role='presentation'
|
||||||
|
>
|
||||||
{blurhash && <Blurhash hash={blurhash} className='image__preview' />}
|
{blurhash && <Blurhash hash={blurhash} className='image__preview' />}
|
||||||
<img src={src} srcSet={srcSet} alt='' onLoad={handleLoad} />
|
<img src={src} srcSet={srcSet} alt='' onLoad={handleLoad} />
|
||||||
</div>
|
</div>
|
|
@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
|
||||||
import { Avatar } from './avatar';
|
import { Avatar } from './avatar';
|
||||||
import { AvatarOverlay } from './avatar_overlay';
|
import { AvatarOverlay } from './avatar_overlay';
|
||||||
import { RelativeTimestamp } from './relative_timestamp';
|
import { RelativeTimestamp } from './relative_timestamp';
|
||||||
import DisplayName from './display_name';
|
import { DisplayName } from './display_name';
|
||||||
import StatusContent from './status_content';
|
import StatusContent from './status_content';
|
||||||
import StatusActionBar from './status_action_bar';
|
import StatusActionBar from './status_action_bar';
|
||||||
import StatusEmojiReactionsBar from './status_emoji_reactions_bar';
|
import StatusEmojiReactionsBar from './status_emoji_reactions_bar';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { store } from '../store/configureStore';
|
import { store } from '../store';
|
||||||
import { hydrateStore } from '../actions/store';
|
import { hydrateStore } from '../actions/store';
|
||||||
import { IntlProvider, addLocaleData } from 'react-intl';
|
import { IntlProvider, addLocaleData } from 'react-intl';
|
||||||
import { getLocale } from '../locales';
|
import { getLocale } from '../locales';
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { IntlProvider, addLocaleData } from 'react-intl';
|
||||||
import { Provider as ReduxProvider } from 'react-redux';
|
import { Provider as ReduxProvider } from 'react-redux';
|
||||||
import { BrowserRouter, Route } from 'react-router-dom';
|
import { BrowserRouter, Route } from 'react-router-dom';
|
||||||
import { ScrollContext } from 'react-router-scroll-4';
|
import { ScrollContext } from 'react-router-scroll-4';
|
||||||
import { store } from 'mastodon/store/configureStore';
|
import { store } from 'mastodon/store';
|
||||||
import UI from 'mastodon/features/ui';
|
import UI from 'mastodon/features/ui';
|
||||||
import { fetchCustomEmojis } from 'mastodon/actions/custom_emojis';
|
import { fetchCustomEmojis } from 'mastodon/actions/custom_emojis';
|
||||||
import { hydrateStore } from 'mastodon/actions/store';
|
import { hydrateStore } from 'mastodon/actions/store';
|
||||||
|
|
|
@ -11,7 +11,7 @@ import Account from 'mastodon/containers/account_container';
|
||||||
import Skeleton from 'mastodon/components/skeleton';
|
import Skeleton from 'mastodon/components/skeleton';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Image } from 'mastodon/components/image';
|
import { ServerHeroImage } from 'mastodon/components/server_hero_image';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
title: { id: 'column.about', defaultMessage: 'About' },
|
title: { id: 'column.about', defaultMessage: 'About' },
|
||||||
|
@ -121,7 +121,7 @@ class About extends React.PureComponent {
|
||||||
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}>
|
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}>
|
||||||
<div className='scrollable about'>
|
<div className='scrollable about'>
|
||||||
<div className='about__header'>
|
<div className='about__header'>
|
||||||
<Image 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' />
|
<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>
|
<h1>{isLoading ? <Skeleton width='10ch' /> : server.get('domain')}</h1>
|
||||||
<p><FormattedMessage id='about.powered_by' defaultMessage='Decentralized social media powered by {mastodon}' values={{ mastodon: <a href='https://joinmastodon.org' className='about__mail' target='_blank'>Mastodon</a> }} /></p>
|
<p><FormattedMessage id='about.powered_by' defaultMessage='Decentralized social media powered by {mastodon}' values={{ mastodon: <a href='https://joinmastodon.org' className='about__mail' target='_blank'>Mastodon</a> }} /></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { AvatarOverlay } from '../../../components/avatar_overlay';
|
import { AvatarOverlay } from '../../../components/avatar_overlay';
|
||||||
import DisplayName from '../../../components/display_name';
|
import { DisplayName } from '../../../components/display_name';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
export default class MovedNote extends ImmutablePureComponent {
|
export default class MovedNote extends ImmutablePureComponent {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Avatar } from '../../../components/avatar';
|
import { Avatar } from '../../../components/avatar';
|
||||||
import DisplayName from '../../../components/display_name';
|
import { DisplayName } from '../../../components/display_name';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Avatar } from '../../../components/avatar';
|
import { Avatar } from '../../../components/avatar';
|
||||||
import { IconButton } from '../../../components/icon_button';
|
import { IconButton } from '../../../components/icon_button';
|
||||||
import DisplayName from '../../../components/display_name';
|
import { DisplayName } from '../../../components/display_name';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import AttachmentList from 'mastodon/components/attachment_list';
|
import AttachmentList from 'mastodon/components/attachment_list';
|
||||||
|
|
|
@ -5,7 +5,7 @@ import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { makeGetAccount } from 'mastodon/selectors';
|
import { makeGetAccount } from 'mastodon/selectors';
|
||||||
import { Avatar } from 'mastodon/components/avatar';
|
import { Avatar } from 'mastodon/components/avatar';
|
||||||
import DisplayName from 'mastodon/components/display_name';
|
import { DisplayName } from 'mastodon/components/display_name';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import Button from 'mastodon/components/button';
|
import Button from 'mastodon/components/button';
|
||||||
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
|
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
|
||||||
|
|
|
@ -3,7 +3,7 @@ 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';
|
||||||
import { Avatar } from '../../../components/avatar';
|
import { Avatar } from '../../../components/avatar';
|
||||||
import DisplayName from '../../../components/display_name';
|
import { DisplayName } from '../../../components/display_name';
|
||||||
import { IconButton } from '../../../components/icon_button';
|
import { IconButton } from '../../../components/icon_button';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { makeGetAccount } from '../../../selectors';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { Avatar } from '../../../components/avatar';
|
import { Avatar } from '../../../components/avatar';
|
||||||
import DisplayName from '../../../components/display_name';
|
import { DisplayName } from '../../../components/display_name';
|
||||||
import { injectIntl } from 'react-intl';
|
import { injectIntl } from 'react-intl';
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
const makeMapStateToProps = () => {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { makeGetAccount } from '../../../selectors';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { Avatar } from '../../../components/avatar';
|
import { Avatar } from '../../../components/avatar';
|
||||||
import DisplayName from '../../../components/display_name';
|
import { DisplayName } from '../../../components/display_name';
|
||||||
import { IconButton } from '../../../components/icon_button';
|
import { IconButton } from '../../../components/icon_button';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
import { removeFromListEditor, addToListEditor } from '../../../actions/lists';
|
import { removeFromListEditor, addToListEditor } from '../../../actions/lists';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Avatar } from 'mastodon/components/avatar';
|
import { Avatar } from 'mastodon/components/avatar';
|
||||||
import DisplayName from 'mastodon/components/display_name';
|
import { DisplayName } from 'mastodon/components/display_name';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { IconButton } from 'mastodon/components/icon_button';
|
import { IconButton } from 'mastodon/components/icon_button';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
|
@ -6,7 +6,7 @@ import PropTypes from 'prop-types';
|
||||||
import { IconButton } from 'mastodon/components/icon_button';
|
import { IconButton } from 'mastodon/components/icon_button';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { Avatar } from 'mastodon/components/avatar';
|
import { Avatar } from 'mastodon/components/avatar';
|
||||||
import DisplayName from 'mastodon/components/display_name';
|
import { DisplayName } from 'mastodon/components/display_name';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
|
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import StatusContent from 'mastodon/components/status_content';
|
import StatusContent from 'mastodon/components/status_content';
|
||||||
import { Avatar } from 'mastodon/components/avatar';
|
import { Avatar } from 'mastodon/components/avatar';
|
||||||
import DisplayName from 'mastodon/components/display_name';
|
import { DisplayName } from 'mastodon/components/display_name';
|
||||||
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
|
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
|
||||||
import Option from './option';
|
import Option from './option';
|
||||||
import MediaAttachments from 'mastodon/components/media_attachments';
|
import MediaAttachments from 'mastodon/components/media_attachments';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { Avatar } from '../../../components/avatar';
|
import { Avatar } from '../../../components/avatar';
|
||||||
import DisplayName from '../../../components/display_name';
|
import { DisplayName } from '../../../components/display_name';
|
||||||
import StatusContent from '../../../components/status_content';
|
import StatusContent from '../../../components/status_content';
|
||||||
import StatusEmojiReactionsBar from '../../../components/status_emoji_reactions_bar';
|
import StatusEmojiReactionsBar from '../../../components/status_emoji_reactions_bar';
|
||||||
import MediaGallery from '../../../components/media_gallery';
|
import MediaGallery from '../../../components/media_gallery';
|
||||||
|
|
|
@ -7,7 +7,7 @@ import Button from '../../../components/button';
|
||||||
import StatusContent from '../../../components/status_content';
|
import StatusContent from '../../../components/status_content';
|
||||||
import { Avatar } from '../../../components/avatar';
|
import { Avatar } from '../../../components/avatar';
|
||||||
import { RelativeTimestamp } from '../../../components/relative_timestamp';
|
import { RelativeTimestamp } from '../../../components/relative_timestamp';
|
||||||
import DisplayName from '../../../components/display_name';
|
import { DisplayName } from '../../../components/display_name';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import AttachmentList from 'mastodon/components/attachment_list';
|
import AttachmentList from 'mastodon/components/attachment_list';
|
||||||
|
|
|
@ -16,10 +16,6 @@ export const layoutFromWindow = (): LayoutType => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-expect-error
|
|
||||||
const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && window.MSStream != null;
|
|
||||||
|
|
||||||
const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
|
const listenerOptions = supportsPassiveEvents ? { passive: true } : false;
|
||||||
|
|
||||||
let userTouching = false;
|
let userTouching = false;
|
||||||
|
@ -33,5 +29,3 @@ const touchListener = () => {
|
||||||
window.addEventListener('touchstart', touchListener, listenerOptions);
|
window.addEventListener('touchstart', touchListener, listenerOptions);
|
||||||
|
|
||||||
export const isUserTouching = () => userTouching;
|
export const isUserTouching = () => userTouching;
|
||||||
|
|
||||||
export const isIOS = () => iOS;
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import { setupBrowserNotifications } from 'mastodon/actions/notifications';
|
import { setupBrowserNotifications } from 'mastodon/actions/notifications';
|
||||||
import Mastodon from 'mastodon/containers/mastodon';
|
import Mastodon from 'mastodon/containers/mastodon';
|
||||||
import { store } from 'mastodon/store/configureStore';
|
import { store } from 'mastodon/store';
|
||||||
import { me } from 'mastodon/initial_state';
|
import { me } from 'mastodon/initial_state';
|
||||||
import ready from 'mastodon/ready';
|
import ready from 'mastodon/ready';
|
||||||
import * as perf from 'mastodon/performance';
|
import * as perf from 'mastodon/performance';
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
import { showLoading, hideLoading } from 'react-redux-loading-bar';
|
|
||||||
|
|
||||||
const defaultTypeSuffixes = ['PENDING', 'FULFILLED', 'REJECTED'];
|
|
||||||
|
|
||||||
export default function loadingBarMiddleware(config = {}) {
|
|
||||||
const promiseTypeSuffixes = config.promiseTypeSuffixes || defaultTypeSuffixes;
|
|
||||||
|
|
||||||
return ({ dispatch }) => next => (action) => {
|
|
||||||
if (action.type && !action.skipLoading) {
|
|
||||||
const [PENDING, FULFILLED, REJECTED] = promiseTypeSuffixes;
|
|
||||||
|
|
||||||
const isPending = new RegExp(`${PENDING}$`, 'g');
|
|
||||||
const isFulfilled = new RegExp(`${FULFILLED}$`, 'g');
|
|
||||||
const isRejected = new RegExp(`${REJECTED}$`, 'g');
|
|
||||||
|
|
||||||
if (action.type.match(isPending)) {
|
|
||||||
dispatch(showLoading());
|
|
||||||
} else if (action.type.match(isFulfilled) || action.type.match(isRejected)) {
|
|
||||||
dispatch(hideLoading());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return next(action);
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
export const PERMISSION_INVITE_USERS = 0x0000000000010000;
|
export const PERMISSION_INVITE_USERS = 0x0000000000010000;
|
||||||
export const PERMISSION_MANAGE_USERS = 0x0000000000000400;
|
export const PERMISSION_MANAGE_USERS = 0x0000000000000400;
|
||||||
export const PERMISSION_MANAGE_FEDERATION = 0x0000000000000020;
|
export const PERMISSION_MANAGE_FEDERATION = 0x0000000000000020;
|
||||||
export const PERMISSION_MANAGE_REPORTS = 0x0000000000000010;
|
export const PERMISSION_MANAGE_REPORTS = 0x0000000000000010;
|
||||||
|
|
|
@ -1,26 +1,16 @@
|
||||||
import 'intl';
|
import 'intl';
|
||||||
import 'intl/locale-data/jsonp/en';
|
import 'intl/locale-data/jsonp/en';
|
||||||
import 'es6-symbol/implement';
|
import 'core-js/features/object/assign';
|
||||||
import assign from 'object-assign';
|
import 'core-js/features/object/values';
|
||||||
import values from 'object.values';
|
import 'core-js/features/symbol';
|
||||||
import { decode as decodeBase64 } from './utils/base64';
|
import 'core-js/features/promise/finally';
|
||||||
import promiseFinally from 'promise.prototype.finally';
|
import { decode as decodeBase64 } from '../utils/base64';
|
||||||
|
|
||||||
if (!Object.assign) {
|
|
||||||
Object.assign = assign;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Object.values) {
|
|
||||||
values.shim();
|
|
||||||
}
|
|
||||||
|
|
||||||
promiseFinally.shim();
|
|
||||||
|
|
||||||
if (!HTMLCanvasElement.prototype.toBlob) {
|
if (!HTMLCanvasElement.prototype.toBlob) {
|
||||||
const BASE64_MARKER = ';base64,';
|
const BASE64_MARKER = ';base64,';
|
||||||
|
|
||||||
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
|
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
|
||||||
value(callback, type = 'image/png', quality) {
|
value(callback: BlobCallback, type = 'image/png', quality: any) {
|
||||||
const dataURL = this.toDataURL(type, quality);
|
const dataURL = this.toDataURL(type, quality);
|
||||||
let data;
|
let data;
|
||||||
|
|
|
@ -10,14 +10,14 @@ function importExtraPolyfills() {
|
||||||
return import(/* webpackChunkName: "extra_polyfills" */ './extra_polyfills');
|
return import(/* webpackChunkName: "extra_polyfills" */ './extra_polyfills');
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadPolyfills() {
|
export function loadPolyfills() {
|
||||||
const needsBasePolyfills = !(
|
const needsBasePolyfills = !(
|
||||||
HTMLCanvasElement.prototype.toBlob &&
|
'toBlob' in HTMLCanvasElement.prototype &&
|
||||||
window.Intl &&
|
'Intl' in window &&
|
||||||
Object.assign &&
|
'assign' in Object &&
|
||||||
Object.values &&
|
'values' in Object &&
|
||||||
window.Symbol &&
|
'Symbol' in window &&
|
||||||
Promise.prototype.finally
|
'finally' in Promise.prototype
|
||||||
);
|
);
|
||||||
|
|
||||||
// Latest version of Firefox and Safari do not have IntersectionObserver.
|
// Latest version of Firefox and Safari do not have IntersectionObserver.
|
||||||
|
@ -36,5 +36,3 @@ function loadPolyfills() {
|
||||||
needsExtraPolyfills && importExtraPolyfills(),
|
needsExtraPolyfills && importExtraPolyfills(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default loadPolyfills;
|
|
|
@ -93,4 +93,6 @@ const reducers = {
|
||||||
followed_tags,
|
followed_tags,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default combineReducers(reducers);
|
const rootReducer = combineReducers(reducers);
|
||||||
|
|
||||||
|
export { rootReducer };
|
|
@ -14,18 +14,18 @@ const initialState = Record<MissedUpdatesState>({
|
||||||
|
|
||||||
export function missedUpdatesReducer(
|
export function missedUpdatesReducer(
|
||||||
state = initialState,
|
state = initialState,
|
||||||
action: Action<string>,
|
action: Action<string>
|
||||||
) {
|
) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case focusApp.type:
|
case focusApp.type:
|
||||||
return state.set('focused', true).set('unread', 0);
|
return state.set('focused', true).set('unread', 0);
|
||||||
case unfocusApp.type:
|
case unfocusApp.type:
|
||||||
return state.set('focused', false);
|
return state.set('focused', false);
|
||||||
case NOTIFICATIONS_UPDATE:
|
case NOTIFICATIONS_UPDATE:
|
||||||
return state.get('focused')
|
return state.get('focused')
|
||||||
? state
|
? state
|
||||||
: state.update('unread', (x) => x + 1);
|
: state.update('unread', (x) => x + 1);
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,23 @@
|
||||||
const easingOutQuint = (x: number, t: number, b: number, c: number, d: number) => c * ((t = t / d - 1) * t * t * t * t + 1) + b;
|
const easingOutQuint = (
|
||||||
const scroll = (node: Element, key: 'scrollTop' | 'scrollLeft', target: number) => {
|
x: number,
|
||||||
|
t: number,
|
||||||
|
b: number,
|
||||||
|
c: number,
|
||||||
|
d: number
|
||||||
|
) => c * ((t = t / d - 1) * t * t * t * t + 1) + b;
|
||||||
|
const scroll = (
|
||||||
|
node: Element,
|
||||||
|
key: 'scrollTop' | 'scrollLeft',
|
||||||
|
target: number
|
||||||
|
) => {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
const offset = node[key];
|
const offset = node[key];
|
||||||
const gap = target - offset;
|
const gap = target - offset;
|
||||||
const duration = 1000;
|
const duration = 1000;
|
||||||
let interrupt = false;
|
let interrupt = false;
|
||||||
|
|
||||||
const step = () => {
|
const step = () => {
|
||||||
const elapsed = Date.now() - startTime;
|
const elapsed = Date.now() - startTime;
|
||||||
const percentage = elapsed / duration;
|
const percentage = elapsed / duration;
|
||||||
|
|
||||||
if (percentage > 1 || interrupt) {
|
if (percentage > 1 || interrupt) {
|
||||||
|
@ -25,7 +35,14 @@ const scroll = (node: Element, key: 'scrollTop' | 'scrollLeft', target: number)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const isScrollBehaviorSupported = 'scrollBehavior' in document.documentElement.style;
|
const isScrollBehaviorSupported =
|
||||||
|
'scrollBehavior' in document.documentElement.style;
|
||||||
|
|
||||||
export const scrollRight = (node: Element, position: number) => isScrollBehaviorSupported ? node.scrollTo({ left: position, behavior: 'smooth' }) : scroll(node, 'scrollLeft', position);
|
export const scrollRight = (node: Element, position: number) =>
|
||||||
export const scrollTop = (node: Element) => isScrollBehaviorSupported ? node.scrollTo({ top: 0, behavior: 'smooth' }) : scroll(node, 'scrollTop', 0);
|
isScrollBehaviorSupported
|
||||||
|
? node.scrollTo({ left: position, behavior: 'smooth' })
|
||||||
|
: scroll(node, 'scrollLeft', position);
|
||||||
|
export const scrollTop = (node: Element) =>
|
||||||
|
isScrollBehaviorSupported
|
||||||
|
? node.scrollTo({ top: 0, behavior: 'smooth' })
|
||||||
|
: scroll(node, 'scrollTop', 0);
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
import { configureStore } from '@reduxjs/toolkit';
|
|
||||||
import thunk from 'redux-thunk';
|
|
||||||
import appReducer from '../reducers';
|
|
||||||
import loadingBarMiddleware from '../middleware/loading_bar';
|
|
||||||
import errorsMiddleware from '../middleware/errors';
|
|
||||||
import soundsMiddleware from '../middleware/sounds';
|
|
||||||
|
|
||||||
export const store = configureStore({
|
|
||||||
reducer: appReducer,
|
|
||||||
middleware: [
|
|
||||||
thunk,
|
|
||||||
loadingBarMiddleware({ promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'] }),
|
|
||||||
errorsMiddleware(),
|
|
||||||
soundsMiddleware(),
|
|
||||||
],
|
|
||||||
});
|
|
27
app/javascript/mastodon/store/index.ts
Normal file
27
app/javascript/mastodon/store/index.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { configureStore } from '@reduxjs/toolkit';
|
||||||
|
import { rootReducer } from '../reducers';
|
||||||
|
import { loadingBarMiddleware } from './middlewares/loading_bar';
|
||||||
|
import { errorsMiddleware } from './middlewares/errors';
|
||||||
|
import { soundsMiddleware } from './middlewares/sounds';
|
||||||
|
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
export const store = configureStore({
|
||||||
|
reducer: rootReducer,
|
||||||
|
middleware: (getDefaultMiddleware) =>
|
||||||
|
getDefaultMiddleware()
|
||||||
|
.concat(
|
||||||
|
loadingBarMiddleware({
|
||||||
|
promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.concat(errorsMiddleware)
|
||||||
|
.concat(soundsMiddleware()),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Infer the `RootState` and `AppDispatch` types from the store itself
|
||||||
|
export type RootState = ReturnType<typeof rootReducer>;
|
||||||
|
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
|
||||||
|
export type AppDispatch = typeof store.dispatch;
|
||||||
|
|
||||||
|
export const useAppDispatch: () => AppDispatch = useDispatch;
|
||||||
|
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
|
@ -1,9 +1,13 @@
|
||||||
import { showAlertForError } from '../actions/alerts';
|
import { Middleware } from 'redux';
|
||||||
|
import { showAlertForError } from '../../actions/alerts';
|
||||||
|
import { RootState } from '..';
|
||||||
|
|
||||||
const defaultFailSuffix = 'FAIL';
|
const defaultFailSuffix = 'FAIL';
|
||||||
|
|
||||||
export default function errorsMiddleware() {
|
export const errorsMiddleware: Middleware<Record<string, never>, RootState> =
|
||||||
return ({ dispatch }) => next => action => {
|
({ dispatch }) =>
|
||||||
|
(next) =>
|
||||||
|
(action) => {
|
||||||
if (action.type && !action.skipAlert) {
|
if (action.type && !action.skipAlert) {
|
||||||
const isFail = new RegExp(`${defaultFailSuffix}$`, 'g');
|
const isFail = new RegExp(`${defaultFailSuffix}$`, 'g');
|
||||||
|
|
||||||
|
@ -14,4 +18,3 @@ export default function errorsMiddleware() {
|
||||||
|
|
||||||
return next(action);
|
return next(action);
|
||||||
};
|
};
|
||||||
}
|
|
42
app/javascript/mastodon/store/middlewares/loading_bar.ts
Normal file
42
app/javascript/mastodon/store/middlewares/loading_bar.ts
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import { showLoading, hideLoading } from 'react-redux-loading-bar';
|
||||||
|
import { Middleware } from 'redux';
|
||||||
|
import { RootState } from '..';
|
||||||
|
|
||||||
|
interface Config {
|
||||||
|
promiseTypeSuffixes?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultTypeSuffixes: Config['promiseTypeSuffixes'] = [
|
||||||
|
'PENDING',
|
||||||
|
'FULFILLED',
|
||||||
|
'REJECTED',
|
||||||
|
];
|
||||||
|
|
||||||
|
export const loadingBarMiddleware = (
|
||||||
|
config: Config = {}
|
||||||
|
): Middleware<Record<string, never>, RootState> => {
|
||||||
|
const promiseTypeSuffixes = config.promiseTypeSuffixes || defaultTypeSuffixes;
|
||||||
|
|
||||||
|
return ({ dispatch }) =>
|
||||||
|
(next) =>
|
||||||
|
(action) => {
|
||||||
|
if (action.type && !action.skipLoading) {
|
||||||
|
const [PENDING, FULFILLED, REJECTED] = promiseTypeSuffixes;
|
||||||
|
|
||||||
|
const isPending = new RegExp(`${PENDING}$`, 'g');
|
||||||
|
const isFulfilled = new RegExp(`${FULFILLED}$`, 'g');
|
||||||
|
const isRejected = new RegExp(`${REJECTED}$`, 'g');
|
||||||
|
|
||||||
|
if (action.type.match(isPending)) {
|
||||||
|
dispatch(showLoading());
|
||||||
|
} else if (
|
||||||
|
action.type.match(isFulfilled) ||
|
||||||
|
action.type.match(isRejected)
|
||||||
|
) {
|
||||||
|
dispatch(hideLoading());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return next(action);
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,4 +1,12 @@
|
||||||
const createAudio = sources => {
|
import { Middleware, AnyAction } from 'redux';
|
||||||
|
import { RootState } from '..';
|
||||||
|
|
||||||
|
interface AudioSource {
|
||||||
|
src: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const createAudio = (sources: AudioSource[]) => {
|
||||||
const audio = new Audio();
|
const audio = new Audio();
|
||||||
sources.forEach(({ type, src }) => {
|
sources.forEach(({ type, src }) => {
|
||||||
const source = document.createElement('source');
|
const source = document.createElement('source');
|
||||||
|
@ -9,7 +17,7 @@ const createAudio = sources => {
|
||||||
return audio;
|
return audio;
|
||||||
};
|
};
|
||||||
|
|
||||||
const play = audio => {
|
const play = (audio: HTMLAudioElement) => {
|
||||||
if (!audio.paused) {
|
if (!audio.paused) {
|
||||||
audio.pause();
|
audio.pause();
|
||||||
if (typeof audio.fastSeek === 'function') {
|
if (typeof audio.fastSeek === 'function') {
|
||||||
|
@ -22,8 +30,11 @@ const play = audio => {
|
||||||
audio.play();
|
audio.play();
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function soundsMiddleware() {
|
export const soundsMiddleware = (): Middleware<
|
||||||
const soundCache = {
|
Record<string, never>,
|
||||||
|
RootState
|
||||||
|
> => {
|
||||||
|
const soundCache: { [key: string]: HTMLAudioElement } = {
|
||||||
boop: createAudio([
|
boop: createAudio([
|
||||||
{
|
{
|
||||||
src: '/sounds/boop.ogg',
|
src: '/sounds/boop.ogg',
|
||||||
|
@ -36,11 +47,13 @@ export default function soundsMiddleware() {
|
||||||
]),
|
]),
|
||||||
};
|
};
|
||||||
|
|
||||||
return () => next => action => {
|
return () => (next) => (action: AnyAction) => {
|
||||||
if (action.meta && action.meta.sound && soundCache[action.meta.sound]) {
|
const sound = action?.meta?.sound;
|
||||||
play(soundCache[action.meta.sound]);
|
|
||||||
|
if (sound && soundCache[sound]) {
|
||||||
|
play(soundCache[sound]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return next(action);
|
return next(action);
|
||||||
};
|
};
|
||||||
}
|
};
|
|
@ -1,16 +1,16 @@
|
||||||
export const toServerSideType = (columnType: string) => {
|
export const toServerSideType = (columnType: string) => {
|
||||||
switch (columnType) {
|
switch (columnType) {
|
||||||
case 'home':
|
case 'home':
|
||||||
case 'notifications':
|
case 'notifications':
|
||||||
case 'public':
|
case 'public':
|
||||||
case 'thread':
|
case 'thread':
|
||||||
case 'account':
|
case 'account':
|
||||||
return columnType;
|
return columnType;
|
||||||
default:
|
default:
|
||||||
if (columnType.indexOf('list:') > -1) {
|
if (columnType.indexOf('list:') > -1) {
|
||||||
return 'home';
|
return 'home';
|
||||||
} else {
|
} else {
|
||||||
return 'public'; // community, account, hashtag
|
return 'public'; // community, account, hashtag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,17 +5,8 @@ const WORD = '\\p{L}\\p{M}\\p{N}\\p{Pc}';
|
||||||
const buildHashtagPatternRegex = () => {
|
const buildHashtagPatternRegex = () => {
|
||||||
try {
|
try {
|
||||||
return new RegExp(
|
return new RegExp(
|
||||||
'(?:^|[^\\/\\)\\w])#((' +
|
`(?:^|[^\\/\\)\\w])#(([${WORD}_][${WORD}${HASHTAG_SEPARATORS}]*[${ALPHA}${HASHTAG_SEPARATORS}][${WORD}${HASHTAG_SEPARATORS}]*[${WORD}_])|([${WORD}_]*[${ALPHA}][${WORD}_]*))`,
|
||||||
'[' + WORD + '_]' +
|
'iu'
|
||||||
'[' + WORD + HASHTAG_SEPARATORS + ']*' +
|
|
||||||
'[' + ALPHA + HASHTAG_SEPARATORS + ']' +
|
|
||||||
'[' + WORD + HASHTAG_SEPARATORS +']*' +
|
|
||||||
'[' + WORD + '_]' +
|
|
||||||
')|(' +
|
|
||||||
'[' + WORD + '_]*' +
|
|
||||||
'[' + ALPHA + ']' +
|
|
||||||
'[' + WORD + '_]*' +
|
|
||||||
'))', 'iu',
|
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
return /(?:^|[^/)\w])#(\w*[a-zA-Z·]\w*)/i;
|
return /(?:^|[^/)\w])#(\w*[a-zA-Z·]\w*)/i;
|
||||||
|
@ -25,17 +16,8 @@ const buildHashtagPatternRegex = () => {
|
||||||
const buildHashtagRegex = () => {
|
const buildHashtagRegex = () => {
|
||||||
try {
|
try {
|
||||||
return new RegExp(
|
return new RegExp(
|
||||||
'^((' +
|
`^(([${WORD}_][${WORD}${HASHTAG_SEPARATORS}]*[${ALPHA}${HASHTAG_SEPARATORS}][${WORD}${HASHTAG_SEPARATORS}]*[${WORD}_])|([${WORD}_]*[${ALPHA}][${WORD}_]*))$`,
|
||||||
'[' + WORD + '_]' +
|
'iu'
|
||||||
'[' + WORD + HASHTAG_SEPARATORS + ']*' +
|
|
||||||
'[' + ALPHA + HASHTAG_SEPARATORS + ']' +
|
|
||||||
'[' + WORD + HASHTAG_SEPARATORS +']*' +
|
|
||||||
'[' + WORD + '_]' +
|
|
||||||
')|(' +
|
|
||||||
'[' + WORD + '_]*' +
|
|
||||||
'[' + ALPHA + ']' +
|
|
||||||
'[' + WORD + '_]*' +
|
|
||||||
'))$', 'iu',
|
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
return /^(\w*[a-zA-Z·]\w*)$/i;
|
return /^(\w*[a-zA-Z·]\w*)$/i;
|
||||||
|
|
|
@ -21,7 +21,7 @@ const TEN_MILLIONS = DECIMAL_UNITS.MILLION * 10;
|
||||||
* shortNumber(5936);
|
* shortNumber(5936);
|
||||||
* // => [5.936, 1000, 1]
|
* // => [5.936, 1000, 1]
|
||||||
*/
|
*/
|
||||||
export type ShortNumber = [number, DecimalUnits, 0 | 1] // Array of: shorten number, unit of shorten number and maximum fraction digits
|
export type ShortNumber = [number, DecimalUnits, 0 | 1]; // Array of: shorten number, unit of shorten number and maximum fraction digits
|
||||||
export function toShortNumber(sourceNumber: number): ShortNumber {
|
export function toShortNumber(sourceNumber: number): ShortNumber {
|
||||||
if (sourceNumber < DECIMAL_UNITS.THOUSAND) {
|
if (sourceNumber < DECIMAL_UNITS.THOUSAND) {
|
||||||
return [sourceNumber, DECIMAL_UNITS.ONE, 0];
|
return [sourceNumber, DECIMAL_UNITS.ONE, 0];
|
||||||
|
@ -38,11 +38,7 @@ export function toShortNumber(sourceNumber: number): ShortNumber {
|
||||||
sourceNumber < TEN_MILLIONS ? 1 : 0,
|
sourceNumber < TEN_MILLIONS ? 1 : 0,
|
||||||
];
|
];
|
||||||
} else if (sourceNumber < DECIMAL_UNITS.TRILLION) {
|
} else if (sourceNumber < DECIMAL_UNITS.TRILLION) {
|
||||||
return [
|
return [sourceNumber / DECIMAL_UNITS.BILLION, DECIMAL_UNITS.BILLION, 0];
|
||||||
sourceNumber / DECIMAL_UNITS.BILLION,
|
|
||||||
DECIMAL_UNITS.BILLION,
|
|
||||||
0,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [sourceNumber, DECIMAL_UNITS.ONE, 0];
|
return [sourceNumber, DECIMAL_UNITS.ONE, 0];
|
||||||
|
@ -56,7 +52,10 @@ export function toShortNumber(sourceNumber: number): ShortNumber {
|
||||||
* pluralReady(1793, DECIMAL_UNITS.THOUSAND)
|
* pluralReady(1793, DECIMAL_UNITS.THOUSAND)
|
||||||
* // => 1790
|
* // => 1790
|
||||||
*/
|
*/
|
||||||
export function pluralReady(sourceNumber: number, division: DecimalUnits): number {
|
export function pluralReady(
|
||||||
|
sourceNumber: number,
|
||||||
|
division: DecimalUnits
|
||||||
|
): number {
|
||||||
if (division == null || division < DECIMAL_UNITS.HUNDRED) {
|
if (division == null || division < DECIMAL_UNITS.HUNDRED) {
|
||||||
return sourceNumber;
|
return sourceNumber;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
export function uuid(a?: string): string {
|
export function uuid(a?: string): string {
|
||||||
return a
|
return a
|
||||||
? (
|
? (
|
||||||
(a as any as number) ^
|
(a as any as number) ^
|
||||||
((Math.random() * 16) >> ((a as any as number) / 4))
|
((Math.random() * 16) >> ((a as any as number) / 4))
|
||||||
).toString(16)
|
).toString(16)
|
||||||
: ('' + 1e7 + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid);
|
: ('' + 1e7 + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import './public-path';
|
import './public-path';
|
||||||
import loadPolyfills from '../mastodon/load_polyfills';
|
import { loadPolyfills } from '../mastodon/polyfills';
|
||||||
import { start } from '../mastodon/common';
|
import { start } from '../mastodon/common';
|
||||||
|
|
||||||
start();
|
start();
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import './public-path';
|
import './public-path';
|
||||||
import loadPolyfills from '../mastodon/load_polyfills';
|
import escapeTextContentForBrowser from 'escape-html';
|
||||||
|
import { loadPolyfills } from '../mastodon/polyfills';
|
||||||
|
import ready from '../mastodon/ready';
|
||||||
import { start } from '../mastodon/common';
|
import { start } from '../mastodon/common';
|
||||||
|
|
||||||
import escapeTextContentForBrowser from 'escape-html';
|
|
||||||
import ready from '../mastodon/ready';
|
|
||||||
import loadKeyboardExtensions from '../mastodon/load_keyboard_extensions';
|
import loadKeyboardExtensions from '../mastodon/load_keyboard_extensions';
|
||||||
import 'cocoon-js-vanilla';
|
import 'cocoon-js-vanilla';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
@ -12,7 +12,7 @@ import { defineMessages } from 'react-intl';
|
||||||
import * as IntlMessageFormat from 'intl-messageformat';
|
import * as IntlMessageFormat from 'intl-messageformat';
|
||||||
import { timeAgoString } from '../mastodon/components/relative_timestamp';
|
import { timeAgoString } from '../mastodon/components/relative_timestamp';
|
||||||
import { delegate } from '@rails/ujs';
|
import { delegate } from '@rails/ujs';
|
||||||
import * as emojify from '../mastodon/features/emoji/emoji';
|
import emojify from '../mastodon/features/emoji/emoji';
|
||||||
import { getLocale } from '../mastodon/locales';
|
import { getLocale } from '../mastodon/locales';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import './public-path';
|
import './public-path';
|
||||||
import loadPolyfills from '../mastodon/load_polyfills';
|
import { loadPolyfills } from '../mastodon/polyfills';
|
||||||
import { start } from '../mastodon/common';
|
import { start } from '../mastodon/common';
|
||||||
import ready from '../mastodon/ready';
|
import ready from '../mastodon/ready';
|
||||||
import ComposeContainer from '../mastodon/containers/compose_container';
|
import ComposeContainer from '../mastodon/containers/compose_container';
|
||||||
|
|
|
@ -1,10 +1,54 @@
|
||||||
import type { Record } from 'immutable';
|
import type { Record } from 'immutable';
|
||||||
|
|
||||||
type AccountValues = {
|
type CustomEmoji = Record<{
|
||||||
id: number;
|
shortcode: string;
|
||||||
|
static_url: string;
|
||||||
|
url: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
type AccountField = Record<{
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
verified_at: string | null;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
type AccountApiResponseValues = {
|
||||||
|
acct: string;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
avatar_static: string;
|
avatar_static: string;
|
||||||
[key: string]: any;
|
bot: boolean;
|
||||||
|
created_at: string;
|
||||||
|
discoverable: boolean;
|
||||||
|
display_name: string;
|
||||||
|
emojis: CustomEmoji[];
|
||||||
|
fields: AccountField[];
|
||||||
|
followers_count: number;
|
||||||
|
following_count: number;
|
||||||
|
group: boolean;
|
||||||
|
header: string;
|
||||||
|
header_static: string;
|
||||||
|
id: string;
|
||||||
|
last_status_at: string;
|
||||||
|
locked: boolean;
|
||||||
|
note: string;
|
||||||
|
statuses_count: number;
|
||||||
|
url: string;
|
||||||
|
username: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Account = Record<AccountValues>;
|
type NormalizedAccountField = Record<{
|
||||||
|
name_emojified: string;
|
||||||
|
value_emojified: string;
|
||||||
|
value_plain: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
type NormalizedAccountValues = {
|
||||||
|
display_name_html: string;
|
||||||
|
fields: NormalizedAccountField[];
|
||||||
|
note_emojified: string;
|
||||||
|
note_plain: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Account = Record<
|
||||||
|
AccountApiResponseValues & NormalizedAccountValues
|
||||||
|
>;
|
||||||
|
|
|
@ -11,7 +11,7 @@ module Mastodon
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
option :severity, required: true, enum: %w(no_access sign_up_requires_approval), desc: 'Severity of the block'
|
option :severity, required: true, enum: %w(no_access sign_up_requires_approval sign_up_block), desc: 'Severity of the block'
|
||||||
option :comment, aliases: [:c], desc: 'Optional comment'
|
option :comment, aliases: [:c], desc: 'Optional comment'
|
||||||
option :duration, aliases: [:d], type: :numeric, desc: 'Duration of the block in seconds'
|
option :duration, aliases: [:d], type: :numeric, desc: 'Duration of the block in seconds'
|
||||||
option :force, type: :boolean, aliases: [:f], desc: 'Overwrite existing blocks'
|
option :force, type: :boolean, aliases: [:f], desc: 'Overwrite existing blocks'
|
||||||
|
@ -36,6 +36,12 @@ module Mastodon
|
||||||
failed = 0
|
failed = 0
|
||||||
|
|
||||||
addresses.each do |address|
|
addresses.each do |address|
|
||||||
|
unless valid_ip_address?(address)
|
||||||
|
say("#{address} is invalid", :red)
|
||||||
|
failed += 1
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
ip_block = IpBlock.find_by(ip: address)
|
ip_block = IpBlock.find_by(ip: address)
|
||||||
|
|
||||||
if ip_block.present? && !options[:force]
|
if ip_block.present? && !options[:force]
|
||||||
|
@ -79,6 +85,12 @@ module Mastodon
|
||||||
skipped = 0
|
skipped = 0
|
||||||
|
|
||||||
addresses.each do |address|
|
addresses.each do |address|
|
||||||
|
unless valid_ip_address?(address)
|
||||||
|
say("#{address} is invalid", :yellow)
|
||||||
|
skipped += 1
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
ip_blocks = if options[:force]
|
ip_blocks = if options[:force]
|
||||||
IpBlock.where('ip >>= ?', address)
|
IpBlock.where('ip >>= ?', address)
|
||||||
else
|
else
|
||||||
|
@ -126,5 +138,12 @@ module Mastodon
|
||||||
:red
|
:red
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def valid_ip_address?(ip_address)
|
||||||
|
IPAddr.new(ip_address)
|
||||||
|
true
|
||||||
|
rescue IPAddr::InvalidAddressError
|
||||||
|
false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
15
package.json
15
package.json
|
@ -52,13 +52,13 @@
|
||||||
"cocoon-js-vanilla": "^1.3.0",
|
"cocoon-js-vanilla": "^1.3.0",
|
||||||
"color-blend": "^4.0.0",
|
"color-blend": "^4.0.0",
|
||||||
"compression-webpack-plugin": "^6.1.1",
|
"compression-webpack-plugin": "^6.1.1",
|
||||||
|
"core-js": "^3.30.2",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"css-loader": "^5.2.7",
|
"css-loader": "^5.2.7",
|
||||||
"cssnano": "^6.0.1",
|
"cssnano": "^6.0.1",
|
||||||
"detect-passive-events": "^2.0.3",
|
"detect-passive-events": "^2.0.3",
|
||||||
"dotenv": "^16.0.3",
|
"dotenv": "^16.0.3",
|
||||||
"emoji-mart": "npm:emoji-mart-lazyload@latest",
|
"emoji-mart": "npm:emoji-mart-lazyload@latest",
|
||||||
"es6-symbol": "^3.1.3",
|
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
|
@ -80,14 +80,11 @@
|
||||||
"mini-css-extract-plugin": "^1.6.2",
|
"mini-css-extract-plugin": "^1.6.2",
|
||||||
"mkdirp": "^2.1.6",
|
"mkdirp": "^2.1.6",
|
||||||
"npmlog": "^7.0.1",
|
"npmlog": "^7.0.1",
|
||||||
"object-assign": "^4.1.1",
|
|
||||||
"object.values": "^1.1.6",
|
|
||||||
"path-complete-extname": "^1.0.0",
|
"path-complete-extname": "^1.0.0",
|
||||||
"pg": "^8.5.0",
|
"pg": "^8.5.0",
|
||||||
"pg-connection-string": "^2.5.0",
|
"pg-connection-string": "^2.5.0",
|
||||||
"postcss": "^8.4.23",
|
"postcss": "^8.4.23",
|
||||||
"postcss-loader": "^4.3.0",
|
"postcss-loader": "^4.3.0",
|
||||||
"promise.prototype.finally": "^3.1.4",
|
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"punycode": "^2.3.0",
|
"punycode": "^2.3.0",
|
||||||
"react": "^16.14.0",
|
"react": "^16.14.0",
|
||||||
|
@ -126,7 +123,7 @@
|
||||||
"tesseract.js": "^2.1.5",
|
"tesseract.js": "^2.1.5",
|
||||||
"tiny-queue": "^0.2.1",
|
"tiny-queue": "^0.2.1",
|
||||||
"twitter-text": "3.1.0",
|
"twitter-text": "3.1.0",
|
||||||
"uuid": "^8.3.1",
|
"uuid": "^9.0.0",
|
||||||
"webpack": "^4.46.0",
|
"webpack": "^4.46.0",
|
||||||
"webpack-assets-manifest": "^4.0.6",
|
"webpack-assets-manifest": "^4.0.6",
|
||||||
"webpack-bundle-analyzer": "^4.8.0",
|
"webpack-bundle-analyzer": "^4.8.0",
|
||||||
|
@ -176,17 +173,19 @@
|
||||||
"@types/react-toggle": "^4.0.3",
|
"@types/react-toggle": "^4.0.3",
|
||||||
"@types/redux-immutable": "^4.0.3",
|
"@types/redux-immutable": "^4.0.3",
|
||||||
"@types/requestidlecallback": "^0.3.5",
|
"@types/requestidlecallback": "^0.3.5",
|
||||||
"@types/uuid": "^8.3.4",
|
"@types/uuid": "^9.0.0",
|
||||||
"@types/webpack": "^4.41.33",
|
"@types/webpack": "^4.41.33",
|
||||||
"@types/yargs": "^17.0.24",
|
"@types/yargs": "^17.0.24",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.59.2",
|
"@typescript-eslint/eslint-plugin": "^5.59.5",
|
||||||
"@typescript-eslint/parser": "^5.59.2",
|
"@typescript-eslint/parser": "^5.59.5",
|
||||||
"babel-jest": "^29.5.0",
|
"babel-jest": "^29.5.0",
|
||||||
"eslint": "^8.39.0",
|
"eslint": "^8.39.0",
|
||||||
|
"eslint-config-prettier": "^8.8.0",
|
||||||
"eslint-plugin-formatjs": "^4.10.1",
|
"eslint-plugin-formatjs": "^4.10.1",
|
||||||
"eslint-plugin-import": "~2.27.5",
|
"eslint-plugin-import": "~2.27.5",
|
||||||
"eslint-plugin-jsdoc": "^43.1.1",
|
"eslint-plugin-jsdoc": "^43.1.1",
|
||||||
"eslint-plugin-jsx-a11y": "~6.7.1",
|
"eslint-plugin-jsx-a11y": "~6.7.1",
|
||||||
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"eslint-plugin-promise": "~6.1.1",
|
"eslint-plugin-promise": "~6.1.1",
|
||||||
"eslint-plugin-react": "~7.32.2",
|
"eslint-plugin-react": "~7.32.2",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
|
"module": "CommonJS",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
|
|
206
yarn.lock
206
yarn.lock
|
@ -2425,10 +2425,10 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
source-map "^0.6.1"
|
source-map "^0.6.1"
|
||||||
|
|
||||||
"@types/uuid@^8.3.4":
|
"@types/uuid@^9.0.0":
|
||||||
version "8.3.4"
|
version "9.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc"
|
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.1.tgz#98586dc36aee8dacc98cc396dbca8d0429647aa6"
|
||||||
integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==
|
integrity sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==
|
||||||
|
|
||||||
"@types/warning@^3.0.0":
|
"@types/warning@^3.0.0":
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
|
@ -2475,15 +2475,15 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/yargs-parser" "*"
|
"@types/yargs-parser" "*"
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@^5.59.2":
|
"@typescript-eslint/eslint-plugin@^5.59.5":
|
||||||
version "5.59.2"
|
version "5.59.5"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.2.tgz#684a2ce7182f3b4dac342eef7caa1c2bae476abd"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.5.tgz#f156827610a3f8cefc56baeaa93cd4a5f32966b4"
|
||||||
integrity sha512-yVrXupeHjRxLDcPKL10sGQ/QlVrA8J5IYOEWVqk0lJaSZP7X5DfnP7Ns3cc74/blmbipQ1htFNVGsHX6wsYm0A==
|
integrity sha512-feA9xbVRWJZor+AnLNAr7A8JRWeZqHUf4T9tlP+TN04b05pFVhO5eN7/O93Y/1OUlLMHKbnJisgDURs/qvtqdg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/regexpp" "^4.4.0"
|
"@eslint-community/regexpp" "^4.4.0"
|
||||||
"@typescript-eslint/scope-manager" "5.59.2"
|
"@typescript-eslint/scope-manager" "5.59.5"
|
||||||
"@typescript-eslint/type-utils" "5.59.2"
|
"@typescript-eslint/type-utils" "5.59.5"
|
||||||
"@typescript-eslint/utils" "5.59.2"
|
"@typescript-eslint/utils" "5.59.5"
|
||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
grapheme-splitter "^1.0.4"
|
grapheme-splitter "^1.0.4"
|
||||||
ignore "^5.2.0"
|
ignore "^5.2.0"
|
||||||
|
@ -2491,31 +2491,31 @@
|
||||||
semver "^7.3.7"
|
semver "^7.3.7"
|
||||||
tsutils "^3.21.0"
|
tsutils "^3.21.0"
|
||||||
|
|
||||||
"@typescript-eslint/parser@^5.59.2":
|
"@typescript-eslint/parser@^5.59.5":
|
||||||
version "5.59.2"
|
version "5.59.5"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.2.tgz#c2c443247901d95865b9f77332d9eee7c55655e8"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.59.5.tgz#63064f5eafbdbfb5f9dfbf5c4503cdf949852981"
|
||||||
integrity sha512-uq0sKyw6ao1iFOZZGk9F8Nro/8+gfB5ezl1cA06SrqbgJAt0SRoFhb9pXaHvkrxUpZaoLxt8KlovHNk8Gp6/HQ==
|
integrity sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/scope-manager" "5.59.2"
|
"@typescript-eslint/scope-manager" "5.59.5"
|
||||||
"@typescript-eslint/types" "5.59.2"
|
"@typescript-eslint/types" "5.59.5"
|
||||||
"@typescript-eslint/typescript-estree" "5.59.2"
|
"@typescript-eslint/typescript-estree" "5.59.5"
|
||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
|
|
||||||
"@typescript-eslint/scope-manager@5.59.2":
|
"@typescript-eslint/scope-manager@5.59.5":
|
||||||
version "5.59.2"
|
version "5.59.5"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.2.tgz#f699fe936ee4e2c996d14f0fdd3a7da5ba7b9a4c"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz#33ffc7e8663f42cfaac873de65ebf65d2bce674d"
|
||||||
integrity sha512-dB1v7ROySwQWKqQ8rEWcdbTsFjh2G0vn8KUyvTXdPoyzSL6lLGkiXEV5CvpJsEe9xIdKV+8Zqb7wif2issoOFA==
|
integrity sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types" "5.59.2"
|
"@typescript-eslint/types" "5.59.5"
|
||||||
"@typescript-eslint/visitor-keys" "5.59.2"
|
"@typescript-eslint/visitor-keys" "5.59.5"
|
||||||
|
|
||||||
"@typescript-eslint/type-utils@5.59.2":
|
"@typescript-eslint/type-utils@5.59.5":
|
||||||
version "5.59.2"
|
version "5.59.5"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz#0729c237503604cd9a7084b5af04c496c9a4cdcf"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.59.5.tgz#485b0e2c5b923460bc2ea6b338c595343f06fc9b"
|
||||||
integrity sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ==
|
integrity sha512-4eyhS7oGym67/pSxA2mmNq7X164oqDYNnZCUayBwJZIRVvKpBCMBzFnFxjeoDeShjtO6RQBHBuwybuX3POnDqg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/typescript-estree" "5.59.2"
|
"@typescript-eslint/typescript-estree" "5.59.5"
|
||||||
"@typescript-eslint/utils" "5.59.2"
|
"@typescript-eslint/utils" "5.59.5"
|
||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
tsutils "^3.21.0"
|
tsutils "^3.21.0"
|
||||||
|
|
||||||
|
@ -2524,10 +2524,10 @@
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.0.tgz#3fcdac7dbf923ec5251545acdd9f1d42d7c4fe32"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.0.tgz#3fcdac7dbf923ec5251545acdd9f1d42d7c4fe32"
|
||||||
integrity sha512-yR2h1NotF23xFFYKHZs17QJnB51J/s+ud4PYU4MqdZbzeNxpgUr05+dNeCN/bb6raslHvGdd6BFCkVhpPk/ZeA==
|
integrity sha512-yR2h1NotF23xFFYKHZs17QJnB51J/s+ud4PYU4MqdZbzeNxpgUr05+dNeCN/bb6raslHvGdd6BFCkVhpPk/ZeA==
|
||||||
|
|
||||||
"@typescript-eslint/types@5.59.2":
|
"@typescript-eslint/types@5.59.5":
|
||||||
version "5.59.2"
|
version "5.59.5"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.2.tgz#b511d2b9847fe277c5cb002a2318bd329ef4f655"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.59.5.tgz#e63c5952532306d97c6ea432cee0981f6d2258c7"
|
||||||
integrity sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w==
|
integrity sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w==
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@5.59.0":
|
"@typescript-eslint/typescript-estree@5.59.0":
|
||||||
version "5.59.0"
|
version "5.59.0"
|
||||||
|
@ -2542,30 +2542,30 @@
|
||||||
semver "^7.3.7"
|
semver "^7.3.7"
|
||||||
tsutils "^3.21.0"
|
tsutils "^3.21.0"
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@5.59.2":
|
"@typescript-eslint/typescript-estree@5.59.5":
|
||||||
version "5.59.2"
|
version "5.59.5"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz#6e2fabd3ba01db5d69df44e0b654c0b051fe9936"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz#9b252ce55dd765e972a7a2f99233c439c5101e42"
|
||||||
integrity sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q==
|
integrity sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types" "5.59.2"
|
"@typescript-eslint/types" "5.59.5"
|
||||||
"@typescript-eslint/visitor-keys" "5.59.2"
|
"@typescript-eslint/visitor-keys" "5.59.5"
|
||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
globby "^11.1.0"
|
globby "^11.1.0"
|
||||||
is-glob "^4.0.3"
|
is-glob "^4.0.3"
|
||||||
semver "^7.3.7"
|
semver "^7.3.7"
|
||||||
tsutils "^3.21.0"
|
tsutils "^3.21.0"
|
||||||
|
|
||||||
"@typescript-eslint/utils@5.59.2":
|
"@typescript-eslint/utils@5.59.5":
|
||||||
version "5.59.2"
|
version "5.59.5"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.2.tgz#0c45178124d10cc986115885688db6abc37939f4"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.59.5.tgz#15b3eb619bb223302e60413adb0accd29c32bcae"
|
||||||
integrity sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ==
|
integrity sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/eslint-utils" "^4.2.0"
|
"@eslint-community/eslint-utils" "^4.2.0"
|
||||||
"@types/json-schema" "^7.0.9"
|
"@types/json-schema" "^7.0.9"
|
||||||
"@types/semver" "^7.3.12"
|
"@types/semver" "^7.3.12"
|
||||||
"@typescript-eslint/scope-manager" "5.59.2"
|
"@typescript-eslint/scope-manager" "5.59.5"
|
||||||
"@typescript-eslint/types" "5.59.2"
|
"@typescript-eslint/types" "5.59.5"
|
||||||
"@typescript-eslint/typescript-estree" "5.59.2"
|
"@typescript-eslint/typescript-estree" "5.59.5"
|
||||||
eslint-scope "^5.1.1"
|
eslint-scope "^5.1.1"
|
||||||
semver "^7.3.7"
|
semver "^7.3.7"
|
||||||
|
|
||||||
|
@ -2577,12 +2577,12 @@
|
||||||
"@typescript-eslint/types" "5.59.0"
|
"@typescript-eslint/types" "5.59.0"
|
||||||
eslint-visitor-keys "^3.3.0"
|
eslint-visitor-keys "^3.3.0"
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys@5.59.2":
|
"@typescript-eslint/visitor-keys@5.59.5":
|
||||||
version "5.59.2"
|
version "5.59.5"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz#37a419dc2723a3eacbf722512b86d6caf7d3b750"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz#ba5b8d6791a13cf9fea6716af1e7626434b29b9b"
|
||||||
integrity sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig==
|
integrity sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types" "5.59.2"
|
"@typescript-eslint/types" "5.59.5"
|
||||||
eslint-visitor-keys "^3.3.0"
|
eslint-visitor-keys "^3.3.0"
|
||||||
|
|
||||||
"@webassemblyjs/ast@1.9.0":
|
"@webassemblyjs/ast@1.9.0":
|
||||||
|
@ -4135,6 +4135,11 @@ core-js@^2.5.0:
|
||||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
|
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
|
||||||
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
|
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
|
||||||
|
|
||||||
|
core-js@^3.30.2:
|
||||||
|
version "3.30.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.30.2.tgz#6528abfda65e5ad728143ea23f7a14f0dcf503fc"
|
||||||
|
integrity sha512-uBJiDmwqsbJCWHAwjrx3cvjbMXP7xD72Dmsn5LOJpiRmE3WbBbN5rCqQ2Qh6Ek6/eOrjlWngEynBWo4VxerQhg==
|
||||||
|
|
||||||
core-util-is@~1.0.0:
|
core-util-is@~1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||||
|
@ -4409,14 +4414,6 @@ csstype@^3.0.2:
|
||||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.6.tgz#865d0b5833d7d8d40f4e5b8a6d76aea3de4725ef"
|
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.6.tgz#865d0b5833d7d8d40f4e5b8a6d76aea3de4725ef"
|
||||||
integrity sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw==
|
integrity sha512-+ZAmfyWMT7TiIlzdqJgjMb7S4f1beorDbWbsocyK4RaiqA5RTX3K14bnBWmmA9QEM0gRdsjyyrEmcyga8Zsxmw==
|
||||||
|
|
||||||
d@1, d@^1.0.1:
|
|
||||||
version "1.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
|
|
||||||
integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==
|
|
||||||
dependencies:
|
|
||||||
es5-ext "^0.10.50"
|
|
||||||
type "^1.0.1"
|
|
||||||
|
|
||||||
damerau-levenshtein@^1.0.8:
|
damerau-levenshtein@^1.0.8:
|
||||||
version "1.0.8"
|
version "1.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
|
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
|
||||||
|
@ -4967,32 +4964,6 @@ es-to-primitive@^1.2.1:
|
||||||
is-date-object "^1.0.1"
|
is-date-object "^1.0.1"
|
||||||
is-symbol "^1.0.2"
|
is-symbol "^1.0.2"
|
||||||
|
|
||||||
es5-ext@^0.10.35, es5-ext@^0.10.50:
|
|
||||||
version "0.10.53"
|
|
||||||
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1"
|
|
||||||
integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==
|
|
||||||
dependencies:
|
|
||||||
es6-iterator "~2.0.3"
|
|
||||||
es6-symbol "~3.1.3"
|
|
||||||
next-tick "~1.0.0"
|
|
||||||
|
|
||||||
es6-iterator@~2.0.3:
|
|
||||||
version "2.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
|
|
||||||
integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
|
|
||||||
dependencies:
|
|
||||||
d "1"
|
|
||||||
es5-ext "^0.10.35"
|
|
||||||
es6-symbol "^3.1.1"
|
|
||||||
|
|
||||||
es6-symbol@^3.1.1, es6-symbol@^3.1.3, es6-symbol@~3.1.3:
|
|
||||||
version "3.1.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
|
|
||||||
integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
|
|
||||||
dependencies:
|
|
||||||
d "^1.0.1"
|
|
||||||
ext "^1.1.2"
|
|
||||||
|
|
||||||
escalade@^3.1.1:
|
escalade@^3.1.1:
|
||||||
version "3.1.1"
|
version "3.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
||||||
|
@ -5030,6 +5001,11 @@ escodegen@^2.0.0:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
source-map "~0.6.1"
|
source-map "~0.6.1"
|
||||||
|
|
||||||
|
eslint-config-prettier@^8.8.0:
|
||||||
|
version "8.8.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz#bfda738d412adc917fd7b038857110efe98c9348"
|
||||||
|
integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==
|
||||||
|
|
||||||
eslint-import-resolver-node@^0.3.7:
|
eslint-import-resolver-node@^0.3.7:
|
||||||
version "0.3.7"
|
version "0.3.7"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7"
|
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7"
|
||||||
|
@ -5120,6 +5096,13 @@ eslint-plugin-jsx-a11y@~6.7.1:
|
||||||
object.fromentries "^2.0.6"
|
object.fromentries "^2.0.6"
|
||||||
semver "^6.3.0"
|
semver "^6.3.0"
|
||||||
|
|
||||||
|
eslint-plugin-prettier@^4.2.1:
|
||||||
|
version "4.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b"
|
||||||
|
integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==
|
||||||
|
dependencies:
|
||||||
|
prettier-linter-helpers "^1.0.0"
|
||||||
|
|
||||||
eslint-plugin-promise@~6.1.1:
|
eslint-plugin-promise@~6.1.1:
|
||||||
version "6.1.1"
|
version "6.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz#269a3e2772f62875661220631bd4dafcb4083816"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz#269a3e2772f62875661220631bd4dafcb4083816"
|
||||||
|
@ -5425,13 +5408,6 @@ express@^4.17.1, express@^4.18.2:
|
||||||
utils-merge "1.0.1"
|
utils-merge "1.0.1"
|
||||||
vary "~1.1.2"
|
vary "~1.1.2"
|
||||||
|
|
||||||
ext@^1.1.2:
|
|
||||||
version "1.4.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244"
|
|
||||||
integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==
|
|
||||||
dependencies:
|
|
||||||
type "^2.0.0"
|
|
||||||
|
|
||||||
extend-shallow@^2.0.1:
|
extend-shallow@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
|
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
|
||||||
|
@ -5466,6 +5442,11 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
||||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||||
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
||||||
|
|
||||||
|
fast-diff@^1.1.2:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
|
||||||
|
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
|
||||||
|
|
||||||
fast-glob@^3.2.12, fast-glob@^3.2.9:
|
fast-glob@^3.2.12, fast-glob@^3.2.9:
|
||||||
version "3.2.12"
|
version "3.2.12"
|
||||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
|
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
|
||||||
|
@ -8234,11 +8215,6 @@ neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2:
|
||||||
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
|
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
|
||||||
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
|
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
|
||||||
|
|
||||||
next-tick@~1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
|
|
||||||
integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
|
|
||||||
|
|
||||||
nice-try@^1.0.4:
|
nice-try@^1.0.4:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
|
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
|
||||||
|
@ -9240,6 +9216,13 @@ prelude-ls@~1.1.2:
|
||||||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
|
||||||
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
|
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
|
||||||
|
|
||||||
|
prettier-linter-helpers@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
|
||||||
|
integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==
|
||||||
|
dependencies:
|
||||||
|
fast-diff "^1.1.2"
|
||||||
|
|
||||||
prettier@^2.8.8:
|
prettier@^2.8.8:
|
||||||
version "2.8.8"
|
version "2.8.8"
|
||||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
|
||||||
|
@ -9284,15 +9267,6 @@ promise-inflight@^1.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
|
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
|
||||||
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
|
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
|
||||||
|
|
||||||
promise.prototype.finally@^3.1.4:
|
|
||||||
version "3.1.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.4.tgz#4e756a154e4db27fae24c6b18703495c31da3927"
|
|
||||||
integrity sha512-nNc3YbgMfLzqtqvO/q5DP6RR0SiHI9pUPGzyDf1q+usTwCN2kjvAnJkBb7bHe3o+fFSBPpsGMoYtaSi+LTNqng==
|
|
||||||
dependencies:
|
|
||||||
call-bind "^1.0.2"
|
|
||||||
define-properties "^1.1.4"
|
|
||||||
es-abstract "^1.20.4"
|
|
||||||
|
|
||||||
prompts@^2.0.1:
|
prompts@^2.0.1:
|
||||||
version "2.3.2"
|
version "2.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068"
|
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068"
|
||||||
|
@ -11426,16 +11400,6 @@ type-is@~1.6.18:
|
||||||
media-typer "0.3.0"
|
media-typer "0.3.0"
|
||||||
mime-types "~2.1.24"
|
mime-types "~2.1.24"
|
||||||
|
|
||||||
type@^1.0.1:
|
|
||||||
version "1.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0"
|
|
||||||
integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==
|
|
||||||
|
|
||||||
type@^2.0.0:
|
|
||||||
version "2.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3"
|
|
||||||
integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==
|
|
||||||
|
|
||||||
"typescript@^4.7 || 5", typescript@^5.0.4:
|
"typescript@^4.7 || 5", typescript@^5.0.4:
|
||||||
version "5.0.4"
|
version "5.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b"
|
||||||
|
@ -11654,10 +11618,10 @@ uuid@^3.3.2, uuid@^3.4.0:
|
||||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||||
|
|
||||||
uuid@^8.3.1:
|
uuid@^9.0.0:
|
||||||
version "8.3.2"
|
version "9.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5"
|
||||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==
|
||||||
|
|
||||||
v8-compile-cache@^2.1.1, v8-compile-cache@^2.3.0:
|
v8-compile-cache@^2.1.1, v8-compile-cache@^2.3.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue