Merge remote-tracking branch 'glitch/main'
commit
2408f1046f
54
.eslintrc.js
54
.eslintrc.js
|
@ -4,10 +4,12 @@ module.exports = {
|
||||||
extends: [
|
extends: [
|
||||||
'eslint:recommended',
|
'eslint:recommended',
|
||||||
'plugin:react/recommended',
|
'plugin:react/recommended',
|
||||||
|
'plugin:react-hooks/recommended',
|
||||||
'plugin:jsx-a11y/recommended',
|
'plugin:jsx-a11y/recommended',
|
||||||
'plugin:import/recommended',
|
'plugin:import/recommended',
|
||||||
'plugin:promise/recommended',
|
'plugin:promise/recommended',
|
||||||
'plugin:jsdoc/recommended',
|
'plugin:jsdoc/recommended',
|
||||||
|
'plugin:prettier/recommended',
|
||||||
],
|
],
|
||||||
|
|
||||||
env: {
|
env: {
|
||||||
|
@ -61,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',
|
||||||
|
@ -94,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': [
|
||||||
|
@ -102,32 +92,18 @@ module.exports = {
|
||||||
{
|
{
|
||||||
vars: 'all',
|
vars: 'all',
|
||||||
args: 'after-used',
|
args: 'after-used',
|
||||||
|
destructuredArrayIgnorePattern: '^_',
|
||||||
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',
|
||||||
|
@ -208,6 +184,9 @@ module.exports = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
'import/no-amd': 'error',
|
||||||
|
'import/no-commonjs': 'error',
|
||||||
|
'import/no-import-module-exports': 'error',
|
||||||
'import/no-webpack-loader-syntax': 'error',
|
'import/no-webpack-loader-syntax': 'error',
|
||||||
|
|
||||||
'promise/always-return': 'off',
|
'promise/always-return': 'off',
|
||||||
|
@ -255,6 +234,7 @@ module.exports = {
|
||||||
'*.config.js',
|
'*.config.js',
|
||||||
'.*rc.js',
|
'.*rc.js',
|
||||||
'ide-helper.js',
|
'ide-helper.js',
|
||||||
|
'config/webpack/**/*',
|
||||||
],
|
],
|
||||||
|
|
||||||
env: {
|
env: {
|
||||||
|
@ -264,6 +244,10 @@ module.exports = {
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
sourceType: 'script',
|
sourceType: 'script',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
rules: {
|
||||||
|
'import/no-commonjs': 'off',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: [
|
files: [
|
||||||
|
@ -275,17 +259,25 @@ module.exports = {
|
||||||
'eslint:recommended',
|
'eslint:recommended',
|
||||||
'plugin:@typescript-eslint/recommended',
|
'plugin:@typescript-eslint/recommended',
|
||||||
'plugin:react/recommended',
|
'plugin:react/recommended',
|
||||||
|
'plugin:react-hooks/recommended',
|
||||||
'plugin:jsx-a11y/recommended',
|
'plugin:jsx-a11y/recommended',
|
||||||
'plugin:import/recommended',
|
'plugin:import/recommended',
|
||||||
'plugin:import/typescript',
|
'plugin:import/typescript',
|
||||||
'plugin:promise/recommended',
|
'plugin:promise/recommended',
|
||||||
'plugin:jsdoc/recommended',
|
'plugin:jsdoc/recommended',
|
||||||
|
'plugin:prettier/recommended',
|
||||||
],
|
],
|
||||||
|
|
||||||
rules: {
|
rules: {
|
||||||
'@typescript-eslint/no-explicit-any': 'off',
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
|
||||||
'jsdoc/require-jsdoc': 'off',
|
'jsdoc/require-jsdoc': 'off',
|
||||||
|
|
||||||
|
// Those rules set stricter rules for TS files
|
||||||
|
// to enforce better practices when converting from JS
|
||||||
|
'import/no-default-export': 'warn',
|
||||||
|
'react/prefer-stateless-function': 'warn',
|
||||||
|
'react/function-component-definition': ['error', { namedComponents: 'arrow-function' }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -298,5 +290,13 @@ module.exports = {
|
||||||
jest: true,
|
jest: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
'streaming/**/*',
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
'import/no-commonjs': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,7 +157,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]
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
require('../styles/mailer.scss');
|
import '../styles/mailer.scss';
|
||||||
|
|
||||||
require.context('../icons');
|
require.context('../icons');
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import 'packs/public-path';
|
import 'packs/public-path';
|
||||||
|
|
||||||
const { delegate } = require('@rails/ujs');
|
import { delegate } from '@rails/ujs';
|
||||||
|
|
||||||
const getProfileAvatarAnimationHandler = (swapTo) => {
|
const getProfileAvatarAnimationHandler = (swapTo) => {
|
||||||
//animate avatar gifs on the profile page when moused over
|
//animate avatar gifs on the profile page when moused over
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import 'packs/public-path';
|
import 'packs/public-path';
|
||||||
import escapeTextContentForBrowser from 'escape-html';
|
import escapeTextContentForBrowser from 'escape-html';
|
||||||
|
|
||||||
const { delegate } = require('@rails/ujs');
|
import { delegate } from '@rails/ujs';
|
||||||
|
|
||||||
import emojify from '../mastodon/features/emoji/emoji';
|
import emojify from '../mastodon/features/emoji/emoji';
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
|
import type { LayoutType } from '../is_mobile';
|
||||||
|
|
||||||
type ChangeLayoutPayload = {
|
type ChangeLayoutPayload = {
|
||||||
layout: 'mobile' | 'single-column' | 'multi-column';
|
layout: LayoutType;
|
||||||
};
|
};
|
||||||
export const changeLayout =
|
export const changeLayout =
|
||||||
createAction<ChangeLayoutPayload>('APP_LAYOUT_CHANGE');
|
createAction<ChangeLayoutPayload>('APP_LAYOUT_CHANGE');
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import api from '../api';
|
import api from '../api';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import compareId from '../compare_id';
|
import { compareId } from '../compare_id';
|
||||||
import { List as ImmutableList } from 'immutable';
|
import { List as ImmutableList } from 'immutable';
|
||||||
|
|
||||||
export const MARKERS_FETCH_REQUEST = 'MARKERS_FETCH_REQUEST';
|
export const MARKERS_FETCH_REQUEST = 'MARKERS_FETCH_REQUEST';
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { defineMessages } from 'react-intl';
|
||||||
import { List as ImmutableList } from 'immutable';
|
import { List as ImmutableList } from 'immutable';
|
||||||
import { unescapeHTML } from 'flavours/glitch/utils/html';
|
import { unescapeHTML } from 'flavours/glitch/utils/html';
|
||||||
import { usePendingItems as preferPendingItems } from 'flavours/glitch/initial_state';
|
import { usePendingItems as preferPendingItems } from 'flavours/glitch/initial_state';
|
||||||
import compareId from 'flavours/glitch/compare_id';
|
import { compareId } from 'flavours/glitch/compare_id';
|
||||||
import { requestNotificationPermission } from 'flavours/glitch/utils/notifications';
|
import { requestNotificationPermission } from 'flavours/glitch/utils/notifications';
|
||||||
|
|
||||||
export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE';
|
export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE';
|
||||||
|
|
|
@ -52,8 +52,10 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti
|
||||||
/**
|
/**
|
||||||
* @param {function(Function, Function): void} fallback
|
* @param {function(Function, Function): void} fallback
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const useFallback = fallback => {
|
const useFallback = fallback => {
|
||||||
fallback(dispatch, () => {
|
fallback(dispatch, () => {
|
||||||
|
// eslint-disable-next-line react-hooks/rules-of-hooks -- this is not a react hook
|
||||||
pollingId = setTimeout(() => useFallback(fallback), 20000 + randomUpTo(20000));
|
pollingId = setTimeout(() => useFallback(fallback), 20000 + randomUpTo(20000));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { importFetchedStatus, importFetchedStatuses } from './importer';
|
||||||
import { submitMarkers } from './markers';
|
import { submitMarkers } from './markers';
|
||||||
import api, { getLinks } from 'flavours/glitch/api';
|
import api, { getLinks } from 'flavours/glitch/api';
|
||||||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||||
import compareId from 'flavours/glitch/compare_id';
|
import { compareId } from 'flavours/glitch/compare_id';
|
||||||
import { usePendingItems as preferPendingItems } from 'flavours/glitch/initial_state';
|
import { usePendingItems as preferPendingItems } from 'flavours/glitch/initial_state';
|
||||||
import { toServerSideType } from 'flavours/glitch/utils/filters';
|
import { toServerSideType } from 'flavours/glitch/utils/filters';
|
||||||
|
|
||||||
|
|
|
@ -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 default function compareId (id1: string, id2: string) {
|
export function compareId(id1: string, id2: string) {
|
||||||
if (id1 === id2) {
|
if (id1 === id2) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } 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 Permalink from './permalink';
|
import Permalink from './permalink';
|
||||||
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';
|
||||||
import { me } from 'flavours/glitch/initial_state';
|
import { me } from 'flavours/glitch/initial_state';
|
||||||
import RelativeTimestamp from './relative_timestamp';
|
import { RelativeTimestamp } from './relative_timestamp';
|
||||||
import Skeleton from 'flavours/glitch/components/skeleton';
|
import Skeleton from 'flavours/glitch/components/skeleton';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
|
|
@ -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,29 +27,48 @@ 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>
|
||||||
)}
|
)}
|
||||||
</TransitionMotion>
|
</TransitionMotion>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AnimatedNumber;
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
|
||||||
const filename = url => url.split('/').pop().split('#')[0].split('?')[0];
|
const filename = url => url.split('/').pop().split('#')[0].split('?')[0];
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { autoPlayGif } from 'flavours/glitch/initial_state';
|
import { autoPlayGif } from 'flavours/glitch/initial_state';
|
||||||
import { useHovering } from 'hooks/useHovering';
|
import { useHovering } from 'flavours/glitch/hooks/useHovering';
|
||||||
import type { Account } from 'flavours/glitch/types/resources';
|
import type { Account } from 'flavours/glitch/types/resources';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -10,7 +10,7 @@ type Props = {
|
||||||
size: number;
|
size: number;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
inline?: boolean;
|
inline?: boolean;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const Avatar: React.FC<Props> = ({
|
export const Avatar: React.FC<Props> = ({
|
||||||
account,
|
account,
|
||||||
|
@ -19,7 +19,8 @@ export const Avatar: React.FC<Props> = ({
|
||||||
inline = false,
|
inline = false,
|
||||||
style: styleFromParent,
|
style: styleFromParent,
|
||||||
}) => {
|
}) => {
|
||||||
const { hovering, handleMouseEnter, handleMouseLeave } = useHovering(autoPlayGif);
|
const { hovering, handleMouseEnter, handleMouseLeave } =
|
||||||
|
useHovering(autoPlayGif);
|
||||||
|
|
||||||
const style = {
|
const style = {
|
||||||
...styleFromParent,
|
...styleFromParent,
|
||||||
|
@ -29,12 +30,18 @@ export const Avatar: React.FC<Props> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
if (account) {
|
if (account) {
|
||||||
style.backgroundImage = `url(${account.get(hovering ? 'avatar' : 'avatar_static')})`;
|
style.backgroundImage = `url(${account.get(
|
||||||
|
hovering ? 'avatar' : 'avatar_static'
|
||||||
|
)})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames('account__avatar', { 'account__avatar-inline': inline }, className)}
|
className={classNames(
|
||||||
|
'account__avatar',
|
||||||
|
{ 'account__avatar-inline': inline },
|
||||||
|
className
|
||||||
|
)}
|
||||||
onMouseEnter={handleMouseEnter}
|
onMouseEnter={handleMouseEnter}
|
||||||
onMouseLeave={handleMouseLeave}
|
onMouseLeave={handleMouseLeave}
|
||||||
style={style}
|
style={style}
|
||||||
|
@ -44,5 +51,3 @@ export const Avatar: React.FC<Props> = ({
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Avatar;
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ export default class AvatarComposite extends React.PureComponent {
|
||||||
accounts: ImmutablePropTypes.list.isRequired,
|
accounts: ImmutablePropTypes.list.isRequired,
|
||||||
animate: PropTypes.bool,
|
animate: PropTypes.bool,
|
||||||
size: PropTypes.number.isRequired,
|
size: PropTypes.number.isRequired,
|
||||||
onAccountClick: PropTypes.func.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
|
@ -80,15 +79,7 @@ export default class AvatarComposite extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a
|
<div key={account.get('id')} style={style} data-avatar-of={`@${account.get('acct')}`} />
|
||||||
href={account.get('url')}
|
|
||||||
target='_blank'
|
|
||||||
onClick={(e) => this.props.onAccountClick(account.get('acct'), e)}
|
|
||||||
title={`@${account.get('acct')}`}
|
|
||||||
key={account.get('id')}
|
|
||||||
>
|
|
||||||
<div style={style} data-avatar-of={`@${account.get('acct')}`} />
|
|
||||||
</a>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,14 +8,14 @@ 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;
|
||||||
}
|
};
|
||||||
function Blurhash({
|
const Blurhash: React.FC<Props> = ({
|
||||||
hash,
|
hash,
|
||||||
width = 32,
|
width = 32,
|
||||||
height = width,
|
height = width,
|
||||||
dummy = false,
|
dummy = false,
|
||||||
...canvasProps
|
...canvasProps
|
||||||
}: Props) {
|
}) => {
|
||||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -40,6 +40,8 @@ function Blurhash({
|
||||||
return (
|
return (
|
||||||
<canvas {...canvasProps} ref={canvasRef} width={width} height={height} />
|
<canvas {...canvasProps} ref={canvasRef} width={width} height={height} />
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default React.memo(Blurhash);
|
const MemoizedBlurhash = React.memo(Blurhash);
|
||||||
|
|
||||||
|
export { MemoizedBlurhash as Blurhash };
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
|
|
||||||
export default class ColumnBackButton extends React.PureComponent {
|
export default class ColumnBackButton extends React.PureComponent {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
|
||||||
export default class ColumnBackButtonSlim extends React.PureComponent {
|
export default class ColumnBackButtonSlim extends React.PureComponent {
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
|
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
|
show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import IconButton from './icon_button';
|
import { IconButton } from './icon_button';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { injectIntl, defineMessages } from 'react-intl';
|
import { injectIntl, defineMessages } from 'react-intl';
|
||||||
import { bannerSettings } from 'flavours/glitch/settings';
|
import { bannerSettings } from 'flavours/glitch/settings';
|
||||||
|
|
|
@ -9,12 +9,9 @@ export default class DisplayName extends React.PureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
account: ImmutablePropTypes.map,
|
account: ImmutablePropTypes.map,
|
||||||
className: PropTypes.string,
|
|
||||||
inline: PropTypes.bool,
|
|
||||||
localDomain: PropTypes.string,
|
|
||||||
others: ImmutablePropTypes.list,
|
others: ImmutablePropTypes.list,
|
||||||
handleClick: PropTypes.func,
|
localDomain: PropTypes.string,
|
||||||
onAccountClick: PropTypes.func,
|
inline: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMouseEnter = ({ currentTarget }) => {
|
handleMouseEnter = ({ currentTarget }) => {
|
||||||
|
@ -43,48 +40,30 @@ export default class DisplayName extends React.PureComponent {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render () {
|
||||||
const { account, className, inline, localDomain, others, onAccountClick } = this.props;
|
const { others, localDomain, inline } = this.props;
|
||||||
|
|
||||||
const computedClass = classNames('display-name', { inline }, className);
|
let displayName, suffix, account;
|
||||||
|
|
||||||
let displayName, suffix;
|
if (others && others.size > 1) {
|
||||||
let acct;
|
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 (account) {
|
if (others.size - 2 > 0) {
|
||||||
acct = account.get('acct');
|
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) {
|
if (acct.indexOf('@') === -1 && localDomain) {
|
||||||
acct = `${acct}@${localDomain}`;
|
acct = `${acct}@${localDomain}`;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (others && others.size > 0) {
|
|
||||||
displayName = others.take(2).map(a => (
|
|
||||||
<a
|
|
||||||
key={a.get('id')}
|
|
||||||
href={a.get('url')}
|
|
||||||
target='_blank'
|
|
||||||
onClick={(e) => onAccountClick(a.get('acct'), e)}
|
|
||||||
title={`@${a.get('acct')}`}
|
|
||||||
rel='noopener noreferrer'
|
|
||||||
>
|
|
||||||
<bdi key={a.get('id')}>
|
|
||||||
<strong className='display-name__html' dangerouslySetInnerHTML={{ __html: a.get('display_name_html') }} />
|
|
||||||
</bdi>
|
|
||||||
</a>
|
|
||||||
)).reduce((prev, cur) => [prev, ', ', cur]);
|
|
||||||
|
|
||||||
if (others.size - 2 > 0) {
|
|
||||||
displayName.push(` +${others.size - 2}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
suffix = (
|
|
||||||
<a href={account.get('url')} target='_blank' onClick={(e) => onAccountClick(account.get('acct'), e)} rel='noopener noreferrer'>
|
|
||||||
<span className='display-name__account'>@{acct}</span>
|
|
||||||
</a>
|
|
||||||
);
|
|
||||||
} else if (account) {
|
|
||||||
displayName = <bdi><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} /></bdi>;
|
displayName = <bdi><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} /></bdi>;
|
||||||
suffix = <span className='display-name__account'>@{acct}</span>;
|
suffix = <span className='display-name__account'>@{acct}</span>;
|
||||||
} else {
|
} else {
|
||||||
|
@ -93,7 +72,7 @@ export default class DisplayName extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className={computedClass} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
<span className={classNames('display-name', { inline })} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
||||||
{displayName}
|
{displayName}
|
||||||
{inline ? ' ' : null}
|
{inline ? ' ' : null}
|
||||||
{suffix}
|
{suffix}
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import IconButton from './icon_button';
|
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
|
|
||||||
});
|
|
||||||
|
|
||||||
class Account extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
domain: PropTypes.string,
|
|
||||||
onUnblockDomain: PropTypes.func.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
handleDomainUnblock = () => {
|
|
||||||
this.props.onUnblockDomain(this.props.domain);
|
|
||||||
};
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { domain, intl } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='domain'>
|
|
||||||
<div className='domain__wrapper'>
|
|
||||||
<span className='domain__domain-name'>
|
|
||||||
<strong>{domain}</strong>
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div className='domain__buttons'>
|
|
||||||
<IconButton active icon='unlock' title={intl.formatMessage(messages.unblockDomain, { domain })} onClick={this.handleDomainUnblock} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default injectIntl(Account);
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import React, { useCallback } from 'react';
|
||||||
|
import { IconButton } from './icon_button';
|
||||||
|
import { InjectedIntl, defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
unblockDomain: {
|
||||||
|
id: 'account.unblock_domain',
|
||||||
|
defaultMessage: 'Unblock domain {domain}',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
domain: string;
|
||||||
|
onUnblockDomain: (domain: string) => void;
|
||||||
|
intl: InjectedIntl;
|
||||||
|
};
|
||||||
|
const _Domain: React.FC<Props> = ({ domain, onUnblockDomain, intl }) => {
|
||||||
|
const handleDomainUnblock = useCallback(() => {
|
||||||
|
onUnblockDomain(domain);
|
||||||
|
}, [domain, onUnblockDomain]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='domain'>
|
||||||
|
<div className='domain__wrapper'>
|
||||||
|
<span className='domain__domain-name'>
|
||||||
|
<strong>{domain}</strong>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div className='domain__buttons'>
|
||||||
|
<IconButton
|
||||||
|
active
|
||||||
|
icon='unlock'
|
||||||
|
title={intl.formatMessage(messages.unblockDomain, { domain })}
|
||||||
|
onClick={handleDomainUnblock}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Domain = injectIntl(_Domain);
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
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 IconButton from './icon_button';
|
import { IconButton } from './icon_button';
|
||||||
import Overlay from 'react-overlays/Overlay';
|
import Overlay from 'react-overlays/Overlay';
|
||||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { FormattedMessage, injectIntl } from 'react-intl';
|
import { FormattedMessage, injectIntl } from 'react-intl';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import DropdownMenu from './containers/dropdown_menu_container';
|
import DropdownMenu from './containers/dropdown_menu_container';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { openModal } from 'flavours/glitch/actions/modal';
|
import { openModal } from 'flavours/glitch/actions/modal';
|
||||||
import RelativeTimestamp from 'flavours/glitch/components/relative_timestamp';
|
import { RelativeTimestamp } from 'flavours/glitch/components/relative_timestamp';
|
||||||
import InlineAccount from 'flavours/glitch/components/inline_account';
|
import InlineAccount from 'flavours/glitch/components/inline_account';
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch, { statusId }) => ({
|
const mapDispatchToProps = (dispatch, { statusId }) => ({
|
||||||
|
|
|
@ -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' }}>
|
||||||
|
@ -64,5 +68,3 @@ export const GIFV: React.FC<Props> = ({
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default GIFV;
|
|
||||||
|
|
|
@ -7,8 +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,
|
||||||
export default Icon;
|
fixedWidth,
|
||||||
|
...other
|
||||||
|
}) => (
|
||||||
|
<i
|
||||||
|
className={classNames('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })}
|
||||||
|
{...other}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
|
@ -21,18 +21,17 @@ type Props = {
|
||||||
animate: boolean;
|
animate: boolean;
|
||||||
overlay: boolean;
|
overlay: boolean;
|
||||||
tabIndex: number;
|
tabIndex: number;
|
||||||
label: string;
|
label?: string;
|
||||||
counter?: number;
|
counter?: number;
|
||||||
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 default 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,
|
||||||
|
@ -48,7 +47,7 @@ export default 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) {
|
||||||
|
@ -58,7 +57,7 @@ export default 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) {
|
||||||
|
@ -84,7 +83,7 @@ export default class IconButton extends React.PureComponent<Props, States> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render() {
|
||||||
// Hack required for some icons which have an overriden size
|
// Hack required for some icons which have an overriden size
|
||||||
let containerSize = '1.28571429em';
|
let containerSize = '1.28571429em';
|
||||||
if (this.props.style?.fontSize) {
|
if (this.props.style?.fontSize) {
|
||||||
|
@ -120,10 +119,7 @@ export default 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,
|
||||||
|
@ -141,7 +137,12 @@ export default 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>
|
||||||
|
)}
|
||||||
{this.props.label}
|
{this.props.label}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
@ -174,5 +175,4 @@ export default class IconButton extends React.PureComponent<Props, States> {
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +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;
|
||||||
}
|
};
|
||||||
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>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default IconWithBadge;
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Blurhash from './blurhash';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
export default class Image extends React.PureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
src: PropTypes.string,
|
|
||||||
srcSet: PropTypes.string,
|
|
||||||
blurhash: PropTypes.string,
|
|
||||||
className: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
state = {
|
|
||||||
loaded: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
handleLoad = () => this.setState({ loaded: true });
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { src, srcSet, blurhash, className } = this.props;
|
|
||||||
const { loaded } = this.state;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classNames('image', { loaded }, className)} role='presentation'>
|
|
||||||
{blurhash && <Blurhash hash={blurhash} className='image__preview' />}
|
|
||||||
<img src={src} srcSet={srcSet} alt='' onLoad={this.handleLoad} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import React, { useCallback, useState } from 'react';
|
||||||
|
import { Blurhash } from './blurhash';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
src: string;
|
||||||
|
srcSet?: string;
|
||||||
|
blurhash?: string;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Image: React.FC<Props> = ({
|
||||||
|
src,
|
||||||
|
srcSet,
|
||||||
|
blurhash,
|
||||||
|
className,
|
||||||
|
}) => {
|
||||||
|
const [loaded, setLoaded] = useState(false);
|
||||||
|
|
||||||
|
const handleLoad = useCallback(() => {
|
||||||
|
setLoaded(true);
|
||||||
|
}, [setLoaded]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames('image', { loaded }, className)}
|
||||||
|
role='presentation'
|
||||||
|
>
|
||||||
|
{blurhash && <Blurhash hash={blurhash} className='image__preview' />}
|
||||||
|
<img src={src} srcSet={srcSet} alt='' onLoad={handleLoad} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { makeGetAccount } from 'flavours/glitch/selectors';
|
import { makeGetAccount } from 'flavours/glitch/selectors';
|
||||||
import Avatar from 'flavours/glitch/components/avatar';
|
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
const makeMapStateToProps = () => {
|
||||||
const getAccount = makeGetAccount();
|
const getAccount = makeGetAccount();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { injectIntl, defineMessages } from 'react-intl';
|
import { injectIntl, defineMessages } from 'react-intl';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
load_more: { id: 'status.load_more', defaultMessage: 'Load more' },
|
load_more: { id: 'status.load_more', defaultMessage: 'Load more' },
|
||||||
|
|
|
@ -2,12 +2,12 @@ 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 { is } from 'immutable';
|
import { is } from 'immutable';
|
||||||
import IconButton from './icon_button';
|
import { IconButton } from './icon_button';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { autoPlayGif, displayMedia, useBlurhash } from 'flavours/glitch/initial_state';
|
import { autoPlayGif, displayMedia, useBlurhash } from 'flavours/glitch/initial_state';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import Blurhash from 'flavours/glitch/components/blurhash';
|
import { Blurhash } from 'flavours/glitch/components/blurhash';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
hidden: {
|
hidden: {
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
|
|
||||||
const NotSignedInIndicator = () => (
|
|
||||||
<div className='scrollable scrollable--flex'>
|
|
||||||
<div className='empty-column-indicator'>
|
|
||||||
<FormattedMessage id='not_signed_in_indicator.not_signed_in' defaultMessage='You need to sign in to access this resource.' />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default NotSignedInIndicator;
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
export const NotSignedInIndicator: React.FC = () => (
|
||||||
|
<div className='scrollable scrollable--flex'>
|
||||||
|
<div className='empty-column-indicator'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='not_signed_in_indicator.not_signed_in'
|
||||||
|
defaultMessage='You need to sign in to access this resource.'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
|
@ -10,7 +10,7 @@ import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
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 Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import { removePictureInPicture } from 'flavours/glitch/actions/picture_in_picture';
|
import { removePictureInPicture } from 'flavours/glitch/actions/picture_in_picture';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
|
@ -8,8 +8,8 @@ import Motion from 'flavours/glitch/features/ui/util/optional_motion';
|
||||||
import spring from 'react-motion/lib/spring';
|
import spring from 'react-motion/lib/spring';
|
||||||
import escapeTextContentForBrowser from 'escape-html';
|
import escapeTextContentForBrowser from 'escape-html';
|
||||||
import emojify from 'flavours/glitch/features/emoji/emoji';
|
import emojify from 'flavours/glitch/features/emoji/emoji';
|
||||||
import RelativeTimestamp from './relative_timestamp';
|
import { RelativeTimestamp } from './relative_timestamp';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
closed: {
|
closed: {
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
export default class RadioButton extends React.PureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
value: PropTypes.string.isRequired,
|
|
||||||
checked: PropTypes.bool,
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
label: PropTypes.node.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { name, value, checked, onChange, label } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<label className='radio-button'>
|
|
||||||
<input
|
|
||||||
name={name}
|
|
||||||
type='radio'
|
|
||||||
value={value}
|
|
||||||
checked={checked}
|
|
||||||
onChange={onChange}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<span className={classNames('radio-button__input', { checked })} />
|
|
||||||
|
|
||||||
<span>{label}</span>
|
|
||||||
</label>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
import React from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
value: string;
|
||||||
|
checked: boolean;
|
||||||
|
name: string;
|
||||||
|
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
label: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const RadioButton: React.FC<Props> = ({
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
checked,
|
||||||
|
onChange,
|
||||||
|
label,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<label className='radio-button'>
|
||||||
|
<input
|
||||||
|
name={name}
|
||||||
|
type='radio'
|
||||||
|
value={value}
|
||||||
|
checked={checked}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span className={classNames('radio-button__input', { checked })} />
|
||||||
|
|
||||||
|
<span>{label}</span>
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
};
|
|
@ -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,88 @@ 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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default injectIntl(RelativeTimestamp);
|
const RelativeTimestampWithIntl = injectIntl(RelativeTimestamp);
|
||||||
|
|
||||||
|
export { RelativeTimestampWithIntl as RelativeTimestamp };
|
||||||
|
|
|
@ -8,6 +8,7 @@ import IntersectionObserverWrapper from 'flavours/glitch/features/ui/util/inters
|
||||||
import { throttle } from 'lodash';
|
import { throttle } from 'lodash';
|
||||||
import { List as ImmutableList } from 'immutable';
|
import { List as ImmutableList } from 'immutable';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||||
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../features/ui/util/fullscreen';
|
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../features/ui/util/fullscreen';
|
||||||
import LoadingIndicator from './loading_indicator';
|
import LoadingIndicator from './loading_indicator';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
@ -236,10 +237,10 @@ class ScrollableList extends PureComponent {
|
||||||
attachScrollListener () {
|
attachScrollListener () {
|
||||||
if (this.props.bindToDocument) {
|
if (this.props.bindToDocument) {
|
||||||
document.addEventListener('scroll', this.handleScroll);
|
document.addEventListener('scroll', this.handleScroll);
|
||||||
document.addEventListener('wheel', this.handleWheel);
|
document.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : undefined);
|
||||||
} else {
|
} else {
|
||||||
this.node.addEventListener('scroll', this.handleScroll);
|
this.node.addEventListener('scroll', this.handleScroll);
|
||||||
this.node.addEventListener('wheel', this.handleWheel);
|
this.node.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import ShortNumber from 'flavours/glitch/components/short_number';
|
||||||
import Skeleton from 'flavours/glitch/components/skeleton';
|
import Skeleton from 'flavours/glitch/components/skeleton';
|
||||||
import Account from 'flavours/glitch/containers/account_container';
|
import Account from 'flavours/glitch/containers/account_container';
|
||||||
import { domain } from 'flavours/glitch/initial_state';
|
import { domain } from 'flavours/glitch/initial_state';
|
||||||
import Image from 'flavours/glitch/components/image';
|
import { Image } from 'flavours/glitch/components/image';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import React from 'react';
|
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 IconButton from './icon_button';
|
import { IconButton } from './icon_button';
|
||||||
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
|
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
|
||||||
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 { me } from 'flavours/glitch/initial_state';
|
import { me } from 'flavours/glitch/initial_state';
|
||||||
import RelativeTimestamp from './relative_timestamp';
|
import { RelativeTimestamp } from './relative_timestamp';
|
||||||
import { accountAdminLink, statusAdminLink } from 'flavours/glitch/utils/backend_links';
|
import { accountAdminLink, statusAdminLink } from 'flavours/glitch/utils/backend_links';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions';
|
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions';
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { FormattedMessage, injectIntl } from 'react-intl';
|
||||||
import Permalink from './permalink';
|
import Permalink from './permalink';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import { autoPlayGif, languages as preloadedLanguages } from 'flavours/glitch/initial_state';
|
import { autoPlayGif, languages as preloadedLanguages } from 'flavours/glitch/initial_state';
|
||||||
import { decode as decodeIDNA } from 'flavours/glitch/utils/idna';
|
import { decode as decodeIDNA } from 'flavours/glitch/utils/idna';
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
|
||||||
// Mastodon imports.
|
// Mastodon imports.
|
||||||
import Avatar from './avatar';
|
import { Avatar } from './avatar';
|
||||||
import AvatarOverlay from './avatar_overlay';
|
import AvatarOverlay from './avatar_overlay';
|
||||||
import DisplayName from './display_name';
|
import DisplayName from './display_name';
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,9 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
// Mastodon imports.
|
// Mastodon imports.
|
||||||
import IconButton from './icon_button';
|
import { IconButton } from './icon_button';
|
||||||
import VisibilityIcon from './status_visibility_icon';
|
import VisibilityIcon from './status_visibility_icon';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import { languages } from 'flavours/glitch/initial_state';
|
import { languages } from 'flavours/glitch/initial_state';
|
||||||
|
|
||||||
// Messages for use with internationalization stuff.
|
// Messages for use with internationalization stuff.
|
||||||
|
|
|
@ -3,7 +3,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 { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import { me } from 'flavours/glitch/initial_state';
|
import { me } from 'flavours/glitch/initial_state';
|
||||||
|
|
||||||
export default class StatusPrepend extends React.PureComponent {
|
export default class StatusPrepend extends React.PureComponent {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
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 Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
public: { id: 'privacy.public.short', defaultMessage: 'Public' },
|
public: { id: 'privacy.public.short', defaultMessage: 'Public' },
|
||||||
|
|
|
@ -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 'flavours/glitch/store/configureStore';
|
import { store } from 'flavours/glitch/store';
|
||||||
import { hydrateStore } from 'flavours/glitch/actions/store';
|
import { hydrateStore } from 'flavours/glitch/actions/store';
|
||||||
import { IntlProvider, addLocaleData } from 'react-intl';
|
import { IntlProvider, addLocaleData } from 'react-intl';
|
||||||
import { getLocale } from 'mastodon/locales';
|
import { getLocale } from 'mastodon/locales';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { blockDomain, unblockDomain } from '../actions/domain_blocks';
|
import { blockDomain, unblockDomain } from '../actions/domain_blocks';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import Domain from '../components/domain';
|
import { Domain } from '../components/domain';
|
||||||
import { openModal } from '../actions/modal';
|
import { openModal } from '../actions/modal';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
|
|
@ -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 'flavours/glitch/store/configureStore';
|
import { store } from 'flavours/glitch/store';
|
||||||
import UI from 'flavours/glitch/features/ui';
|
import UI from 'flavours/glitch/features/ui';
|
||||||
import { fetchCustomEmojis } from 'flavours/glitch/actions/custom_emojis';
|
import { fetchCustomEmojis } from 'flavours/glitch/actions/custom_emojis';
|
||||||
import { hydrateStore } from 'flavours/glitch/actions/store';
|
import { hydrateStore } from 'flavours/glitch/actions/store';
|
||||||
|
|
|
@ -9,9 +9,9 @@ import { Helmet } from 'react-helmet';
|
||||||
import { fetchServer, fetchExtendedDescription, fetchDomainBlocks } from 'flavours/glitch/actions/server';
|
import { fetchServer, fetchExtendedDescription, fetchDomainBlocks } from 'flavours/glitch/actions/server';
|
||||||
import Account from 'flavours/glitch/containers/account_container';
|
import Account from 'flavours/glitch/containers/account_container';
|
||||||
import Skeleton from 'flavours/glitch/components/skeleton';
|
import Skeleton from 'flavours/glitch/components/skeleton';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Image from 'flavours/glitch/components/image';
|
import { Image } from 'flavours/glitch/components/image';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
title: { id: 'column.about', defaultMessage: 'About' },
|
title: { id: 'column.about', defaultMessage: 'About' },
|
||||||
|
|
|
@ -3,7 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import Textarea from 'react-textarea-autosize';
|
import Textarea from 'react-textarea-autosize';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { NavLink } from 'react-router-dom';
|
import { NavLink } from 'react-router-dom';
|
||||||
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
|
||||||
class ActionBar extends React.PureComponent {
|
class ActionBar extends React.PureComponent {
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
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 Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
|
||||||
export default class FollowRequestNote extends ImmutablePureComponent {
|
export default class FollowRequestNote extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,9 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { autoPlayGif, me, domain } from 'flavours/glitch/initial_state';
|
import { autoPlayGif, me, domain } from 'flavours/glitch/initial_state';
|
||||||
import { preferencesLink, profileLink, accountAdminLink } from 'flavours/glitch/utils/backend_links';
|
import { preferencesLink, profileLink, accountAdminLink } from 'flavours/glitch/utils/backend_links';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import IconButton from 'flavours/glitch/components/icon_button';
|
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||||
import Avatar from 'flavours/glitch/components/avatar';
|
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||||
import Button from 'flavours/glitch/components/button';
|
import Button from 'flavours/glitch/components/button';
|
||||||
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
|
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
|
||||||
import AccountNoteContainer from '../containers/account_note_container';
|
import AccountNoteContainer from '../containers/account_note_container';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Blurhash from 'flavours/glitch/components/blurhash';
|
import { Blurhash } from 'flavours/glitch/components/blurhash';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import { autoPlayGif, displayMedia, useBlurhash } from 'flavours/glitch/initial_state';
|
import { autoPlayGif, displayMedia, useBlurhash } from 'flavours/glitch/initial_state';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
|
@ -5,7 +5,7 @@ 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 Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
|
||||||
export default class MovedNote extends ImmutablePureComponent {
|
export default class MovedNote extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,12 @@ import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
|
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
|
||||||
import { formatTime, getPointerPosition, fileNameFromURL } from 'flavours/glitch/features/video';
|
import { formatTime, getPointerPosition, fileNameFromURL } from 'flavours/glitch/features/video';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { throttle, debounce } from 'lodash';
|
import { throttle, debounce } from 'lodash';
|
||||||
import Visualizer from './visualizer';
|
import Visualizer from './visualizer';
|
||||||
import { displayMedia, useBlurhash } from 'flavours/glitch/initial_state';
|
import { displayMedia, useBlurhash } from 'flavours/glitch/initial_state';
|
||||||
import Blurhash from 'flavours/glitch/components/blurhash';
|
import { Blurhash } from 'flavours/glitch/components/blurhash';
|
||||||
import { is } from 'immutable';
|
import { is } from 'immutable';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Avatar from 'flavours/glitch/components/avatar';
|
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||||
import DisplayName from 'flavours/glitch/components/display_name';
|
import DisplayName from 'flavours/glitch/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';
|
||||||
|
|
|
@ -5,7 +5,7 @@ import React from 'react';
|
||||||
import Overlay from 'react-overlays/Overlay';
|
import Overlay from 'react-overlays/Overlay';
|
||||||
|
|
||||||
// Components.
|
// Components.
|
||||||
import IconButton from 'flavours/glitch/components/icon_button';
|
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||||
import DropdownMenu from './dropdown_menu';
|
import DropdownMenu from './dropdown_menu';
|
||||||
|
|
||||||
// The component.
|
// The component.
|
||||||
|
|
|
@ -4,7 +4,7 @@ import React from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
// Components.
|
// Components.
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
|
||||||
// Utils.
|
// Utils.
|
||||||
import { withPassive } from 'flavours/glitch/utils/dom_helpers';
|
import { withPassive } from 'flavours/glitch/utils/dom_helpers';
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { Link } from 'react-router-dom';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
// Components.
|
// Components.
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
|
||||||
// Utils.
|
// Utils.
|
||||||
import { conditionalRender } from 'flavours/glitch/utils/react_helpers';
|
import { conditionalRender } from 'flavours/glitch/utils/react_helpers';
|
||||||
|
|
|
@ -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 ActionBar from './action_bar';
|
import ActionBar from './action_bar';
|
||||||
import Avatar from 'flavours/glitch/components/avatar';
|
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||||
import Permalink from 'flavours/glitch/components/permalink';
|
import Permalink from 'flavours/glitch/components/permalink';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
|
@ -7,7 +7,7 @@ import Toggle from 'react-toggle';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
// Components.
|
// Components.
|
||||||
import IconButton from 'flavours/glitch/components/icon_button';
|
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||||
import TextIconButton from './text_icon_button';
|
import TextIconButton from './text_icon_button';
|
||||||
import DropdownContainer from '../containers/dropdown_container';
|
import DropdownContainer from '../containers/dropdown_container';
|
||||||
import PrivacyDropdownContainer from '../containers/privacy_dropdown_container';
|
import PrivacyDropdownContainer from '../containers/privacy_dropdown_container';
|
||||||
|
|
|
@ -3,8 +3,8 @@ import PropTypes from 'prop-types';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import IconButton from 'flavours/glitch/components/icon_button';
|
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import AutosuggestInput from 'flavours/glitch/components/autosuggest_input';
|
import AutosuggestInput from 'flavours/glitch/components/autosuggest_input';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { pollLimits } from 'flavours/glitch/initial_state';
|
import { pollLimits } from 'flavours/glitch/initial_state';
|
||||||
|
|
|
@ -8,7 +8,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
// Components.
|
// Components.
|
||||||
import Button from 'flavours/glitch/components/button';
|
import Button from 'flavours/glitch/components/button';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
|
||||||
// Utils.
|
// Utils.
|
||||||
import { maxChars } from 'flavours/glitch/initial_state';
|
import { maxChars } from 'flavours/glitch/initial_state';
|
||||||
|
|
|
@ -7,8 +7,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
// Components.
|
// Components.
|
||||||
import AccountContainer from 'flavours/glitch/containers/account_container';
|
import AccountContainer from 'flavours/glitch/containers/account_container';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import IconButton from 'flavours/glitch/components/icon_button';
|
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||||
import AttachmentList from 'flavours/glitch/components/attachment_list';
|
import AttachmentList from 'flavours/glitch/components/attachment_list';
|
||||||
|
|
||||||
// Messages.
|
// Messages.
|
||||||
|
|
|
@ -7,8 +7,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
// Components.
|
// Components.
|
||||||
import AccountContainer from 'flavours/glitch/containers/account_container';
|
import AccountContainer from 'flavours/glitch/containers/account_container';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import IconButton from 'flavours/glitch/components/icon_button';
|
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||||
import AttachmentList from 'flavours/glitch/components/attachment_list';
|
import AttachmentList from 'flavours/glitch/components/attachment_list';
|
||||||
|
|
||||||
// Messages.
|
// Messages.
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
import Overlay from 'react-overlays/Overlay';
|
import Overlay from 'react-overlays/Overlay';
|
||||||
|
|
||||||
// Components.
|
// Components.
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
|
||||||
// Utils.
|
// Utils.
|
||||||
import { focusRoot } from 'flavours/glitch/utils/dom_helpers';
|
import { focusRoot } from 'flavours/glitch/utils/dom_helpers';
|
||||||
|
|
|
@ -6,7 +6,7 @@ import AccountContainer from 'flavours/glitch/containers/account_container';
|
||||||
import StatusContainer from 'flavours/glitch/containers/status_container';
|
import StatusContainer from 'flavours/glitch/containers/status_container';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { ImmutableHashtag as Hashtag } from 'flavours/glitch/components/hashtag';
|
import { ImmutableHashtag as Hashtag } from 'flavours/glitch/components/hashtag';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import { searchEnabled } from 'flavours/glitch/initial_state';
|
import { searchEnabled } from 'flavours/glitch/initial_state';
|
||||||
import LoadMore from 'flavours/glitch/components/load_more';
|
import LoadMore from 'flavours/glitch/components/load_more';
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { defineMessages, injectIntl } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
// Components.
|
// Components.
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
|
||||||
// Messages.
|
// Messages.
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
|
|
@ -5,7 +5,7 @@ import Motion from '../../ui/util/optional_motion';
|
||||||
import spring from 'react-motion/lib/spring';
|
import spring from 'react-motion/lib/spring';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
|
||||||
export default class Upload extends ImmutablePureComponent {
|
export default class Upload extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Motion from '../../ui/util/optional_motion';
|
import Motion from '../../ui/util/optional_motion';
|
||||||
import spring from 'react-motion/lib/spring';
|
import spring from 'react-motion/lib/spring';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
export default class UploadProgress extends React.PureComponent {
|
export default class UploadProgress extends React.PureComponent {
|
||||||
|
|
|
@ -72,6 +72,7 @@ const mapDispatchToProps = (dispatch, { onPickEmoji }) => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
onPickEmoji: emoji => {
|
onPickEmoji: emoji => {
|
||||||
|
// eslint-disable-next-line react-hooks/rules-of-hooks -- this is not a react hook
|
||||||
dispatch(useEmoji(emoji));
|
dispatch(useEmoji(emoji));
|
||||||
|
|
||||||
if (onPickEmoji) {
|
if (onPickEmoji) {
|
||||||
|
|
|
@ -26,6 +26,7 @@ const mapDispatchToProps = dispatch => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
onClose (value) {
|
onClose (value) {
|
||||||
|
// eslint-disable-next-line react-hooks/rules-of-hooks -- this is not a react hook
|
||||||
dispatch(useLanguage(value));
|
dispatch(useLanguage(value));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
|
import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
|
||||||
import AvatarComposite from 'flavours/glitch/components/avatar_composite';
|
import AvatarComposite from 'flavours/glitch/components/avatar_composite';
|
||||||
import Permalink from 'flavours/glitch/components/permalink';
|
import Permalink from 'flavours/glitch/components/permalink';
|
||||||
import IconButton from 'flavours/glitch/components/icon_button';
|
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||||
import RelativeTimestamp from 'flavours/glitch/components/relative_timestamp';
|
import { RelativeTimestamp } from 'flavours/glitch/components/relative_timestamp';
|
||||||
import { HotKeys } from 'react-hotkeys';
|
import { HotKeys } from 'react-hotkeys';
|
||||||
import { autoPlayGif } from 'flavours/glitch/initial_state';
|
import { autoPlayGif } from 'flavours/glitch/initial_state';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
|
@ -4,10 +4,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { makeGetAccount } from 'flavours/glitch/selectors';
|
import { makeGetAccount } from 'flavours/glitch/selectors';
|
||||||
import Avatar from 'flavours/glitch/components/avatar';
|
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||||
import DisplayName from 'flavours/glitch/components/display_name';
|
import DisplayName from 'flavours/glitch/components/display_name';
|
||||||
import Permalink from 'flavours/glitch/components/permalink';
|
import Permalink from 'flavours/glitch/components/permalink';
|
||||||
import IconButton from 'flavours/glitch/components/icon_button';
|
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||||
import Button from 'flavours/glitch/components/button';
|
import Button from 'flavours/glitch/components/button';
|
||||||
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
|
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
|
||||||
import { autoPlayGif, me, unfollowModal } from 'flavours/glitch/initial_state';
|
import { autoPlayGif, me, unfollowModal } from 'flavours/glitch/initial_state';
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { addColumn, removeColumn, moveColumn, changeColumnParams } from 'flavour
|
||||||
import { fetchDirectory, expandDirectory } from 'flavours/glitch/actions/directory';
|
import { fetchDirectory, expandDirectory } from 'flavours/glitch/actions/directory';
|
||||||
import { List as ImmutableList } from 'immutable';
|
import { List as ImmutableList } from 'immutable';
|
||||||
import AccountCard from './components/account_card';
|
import AccountCard from './components/account_card';
|
||||||
import RadioButton from 'flavours/glitch/components/radio_button';
|
import { RadioButton } from 'flavours/glitch/components/radio_button';
|
||||||
import LoadMore from 'flavours/glitch/components/load_more';
|
import LoadMore from 'flavours/glitch/components/load_more';
|
||||||
import ScrollContainer from 'flavours/glitch/containers/scroll_container';
|
import ScrollContainer from 'flavours/glitch/containers/scroll_container';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* eslint-disable import/no-commonjs --
|
||||||
|
We need to use CommonJS here due to preval */
|
||||||
// @preval
|
// @preval
|
||||||
// http://www.unicode.org/Public/emoji/5.0/emoji-test.txt
|
// http://www.unicode.org/Public/emoji/5.0/emoji-test.txt
|
||||||
// This file contains the compressed version of the emoji data from
|
// This file contains the compressed version of the emoji data from
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
// The output of this module is designed to mimic emoji-mart's
|
// The output of this module is designed to mimic emoji-mart's
|
||||||
// "data" object, such that we can use it for a light version of emoji-mart's
|
// "data" object, such that we can use it for a light version of emoji-mart's
|
||||||
// emojiIndex.search functionality.
|
// emojiIndex.search functionality.
|
||||||
const { unicodeToUnifiedName } = require('./unicode_to_unified_name');
|
import { unicodeToUnifiedName } from './unicode_to_unified_name';
|
||||||
const [ shortCodesToEmojiData, skins, categories, short_names ] = require('./emoji_compressed');
|
import emojiCompressed from './emoji_compressed';
|
||||||
|
|
||||||
|
const [ shortCodesToEmojiData, skins, categories, short_names ] = emojiCompressed;
|
||||||
|
|
||||||
const emojis = {};
|
const emojis = {};
|
||||||
|
|
||||||
|
@ -33,7 +35,7 @@ Object.keys(shortCodesToEmojiData).forEach((shortCode) => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = {
|
export {
|
||||||
emojis,
|
emojis,
|
||||||
skins,
|
skins,
|
||||||
categories,
|
categories,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// This code is largely borrowed from:
|
// This code is largely borrowed from:
|
||||||
// https://github.com/missive/emoji-mart/blob/5f2ffcc/src/utils/emoji-index.js
|
// https://github.com/missive/emoji-mart/blob/5f2ffcc/src/utils/emoji-index.js
|
||||||
|
|
||||||
import data from './emoji_mart_data_light';
|
import * as data from './emoji_mart_data_light';
|
||||||
import { getData, getSanitizedData, uniq, intersect } from './emoji_utils';
|
import { getData, getSanitizedData, uniq, intersect } from './emoji_utils';
|
||||||
|
|
||||||
let originalPool = {};
|
let originalPool = {};
|
||||||
|
|
|
@ -2,14 +2,17 @@
|
||||||
// (i.e. the svg filename) and a shortCode intended to be shown
|
// (i.e. the svg filename) and a shortCode intended to be shown
|
||||||
// as a "title" attribute in an HTML element (aka tooltip).
|
// as a "title" attribute in an HTML element (aka tooltip).
|
||||||
|
|
||||||
|
import emojiCompressed from './emoji_compressed';
|
||||||
|
|
||||||
|
import { unicodeToFilename } from './unicode_to_filename';
|
||||||
|
|
||||||
const [
|
const [
|
||||||
shortCodesToEmojiData,
|
shortCodesToEmojiData,
|
||||||
skins, // eslint-disable-line @typescript-eslint/no-unused-vars
|
_skins,
|
||||||
categories, // eslint-disable-line @typescript-eslint/no-unused-vars
|
_categories,
|
||||||
short_names, // eslint-disable-line @typescript-eslint/no-unused-vars
|
_short_names,
|
||||||
emojisWithoutShortCodes,
|
emojisWithoutShortCodes,
|
||||||
] = require('./emoji_compressed');
|
] = emojiCompressed;
|
||||||
const { unicodeToFilename } = require('./unicode_to_filename');
|
|
||||||
|
|
||||||
// decompress
|
// decompress
|
||||||
const unicodeMapping = {};
|
const unicodeMapping = {};
|
||||||
|
@ -32,4 +35,4 @@ Object.keys(shortCodesToEmojiData).forEach((shortCode) => {
|
||||||
});
|
});
|
||||||
emojisWithoutShortCodes.forEach(emojiMapData => processEmojiMapData(emojiMapData));
|
emojisWithoutShortCodes.forEach(emojiMapData => processEmojiMapData(emojiMapData));
|
||||||
|
|
||||||
module.exports = unicodeMapping;
|
export default unicodeMapping;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// This code is largely borrowed from:
|
// This code is largely borrowed from:
|
||||||
// https://github.com/missive/emoji-mart/blob/5f2ffcc/src/utils/index.js
|
// https://github.com/missive/emoji-mart/blob/5f2ffcc/src/utils/index.js
|
||||||
|
|
||||||
import data from './emoji_mart_data_light';
|
import * as data from './emoji_mart_data_light';
|
||||||
|
|
||||||
const buildSearch = (data) => {
|
const buildSearch = (data) => {
|
||||||
const search = [];
|
const search = [];
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
/* eslint-disable import/no-commonjs --
|
||||||
|
We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */
|
||||||
|
|
||||||
// taken from:
|
// taken from:
|
||||||
// https://github.com/twitter/twemoji/blob/47732c7/twemoji-generator.js#L848-L866
|
// https://github.com/twitter/twemoji/blob/47732c7/twemoji-generator.js#L848-L866
|
||||||
exports.unicodeToFilename = (str) => {
|
exports.unicodeToFilename = (str) => {
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
/* eslint-disable import/no-commonjs --
|
||||||
|
We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */
|
||||||
|
|
||||||
function padLeft(str, num) {
|
function padLeft(str, num) {
|
||||||
while (str.length < num) {
|
while (str.length < num) {
|
||||||
str = '0' + str;
|
str = '0' + str;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Blurhash from 'flavours/glitch/components/blurhash';
|
import { Blurhash } from 'flavours/glitch/components/blurhash';
|
||||||
import { accountsCountRenderer } from 'flavours/glitch/components/hashtag';
|
import { accountsCountRenderer } from 'flavours/glitch/components/hashtag';
|
||||||
import ShortNumber from 'flavours/glitch/components/short_number';
|
import ShortNumber from 'flavours/glitch/components/short_number';
|
||||||
import Skeleton from 'flavours/glitch/components/skeleton';
|
import Skeleton from 'flavours/glitch/components/skeleton';
|
||||||
|
|
|
@ -5,7 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import ColumnHeader from 'flavours/glitch/components/column_header';
|
import ColumnHeader from 'flavours/glitch/components/column_header';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import { fetchFavourites } from 'flavours/glitch/actions/interactions';
|
import { fetchFavourites } from 'flavours/glitch/actions/interactions';
|
||||||
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
|
||||||
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
import ScrollableList from 'flavours/glitch/components/scrollable_list';
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { connect } from 'react-redux';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import { toServerSideType } from 'flavours/glitch/utils/filters';
|
import { toServerSideType } from 'flavours/glitch/utils/filters';
|
||||||
import { loupeIcon, deleteIcon } from 'flavours/glitch/utils/icons';
|
import { loupeIcon, deleteIcon } from 'flavours/glitch/utils/icons';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import fuzzysort from 'fuzzysort';
|
import fuzzysort from 'fuzzysort';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
|
|
@ -4,10 +4,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { makeGetAccount } from 'flavours/glitch/selectors';
|
import { makeGetAccount } from 'flavours/glitch/selectors';
|
||||||
import Avatar from 'flavours/glitch/components/avatar';
|
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||||
import DisplayName from 'flavours/glitch/components/display_name';
|
import DisplayName from 'flavours/glitch/components/display_name';
|
||||||
import Permalink from 'flavours/glitch/components/permalink';
|
import Permalink from 'flavours/glitch/components/permalink';
|
||||||
import IconButton from 'flavours/glitch/components/icon_button';
|
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||||
import { injectIntl, defineMessages } from 'react-intl';
|
import { injectIntl, defineMessages } from 'react-intl';
|
||||||
import { followAccount, unfollowAccount } from 'flavours/glitch/actions/accounts';
|
import { followAccount, unfollowAccount } from 'flavours/glitch/actions/accounts';
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,9 @@ 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 Permalink from 'flavours/glitch/components/permalink';
|
import Permalink from 'flavours/glitch/components/permalink';
|
||||||
import Avatar from 'flavours/glitch/components/avatar';
|
import { Avatar } from 'flavours/glitch/components/avatar';
|
||||||
import DisplayName from 'flavours/glitch/components/display_name';
|
import DisplayName from 'flavours/glitch/components/display_name';
|
||||||
import IconButton from 'flavours/glitch/components/icon_button';
|
import { IconButton } from 'flavours/glitch/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';
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,15 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import ReactSwipeableViews from 'react-swipeable-views';
|
import ReactSwipeableViews from 'react-swipeable-views';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import IconButton from 'flavours/glitch/components/icon_button';
|
import { IconButton } from 'flavours/glitch/components/icon_button';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import { defineMessages, injectIntl, FormattedMessage, FormattedDate } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage, FormattedDate } from 'react-intl';
|
||||||
import { autoPlayGif, reduceMotion, disableSwiping, mascot } from 'flavours/glitch/initial_state';
|
import { autoPlayGif, reduceMotion, disableSwiping, mascot } from 'flavours/glitch/initial_state';
|
||||||
import elephantUIPlane from 'mastodon/../images/elephant_ui_plane.svg';
|
import elephantUIPlane from 'mastodon/../images/elephant_ui_plane.svg';
|
||||||
import unicodeMapping from 'flavours/glitch/features/emoji/emoji_unicode_mapping_light';
|
import unicodeMapping from 'flavours/glitch/features/emoji/emoji_unicode_mapping_light';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import EmojiPickerDropdown from 'flavours/glitch/features/compose/containers/emoji_picker_dropdown_container';
|
import EmojiPickerDropdown from 'flavours/glitch/features/compose/containers/emoji_picker_dropdown_container';
|
||||||
import AnimatedNumber from 'flavours/glitch/components/animated_number';
|
import { AnimatedNumber } from 'flavours/glitch/components/animated_number';
|
||||||
import TransitionMotion from 'react-motion/lib/TransitionMotion';
|
import TransitionMotion from 'react-motion/lib/TransitionMotion';
|
||||||
import spring from 'react-motion/lib/spring';
|
import spring from 'react-motion/lib/spring';
|
||||||
import { assetHost } from 'flavours/glitch/utils/config';
|
import { assetHost } from 'flavours/glitch/utils/config';
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { connectHashtagStream } from 'flavours/glitch/actions/streaming';
|
||||||
import { injectIntl, FormattedMessage, defineMessages } from 'react-intl';
|
import { injectIntl, FormattedMessage, defineMessages } from 'react-intl';
|
||||||
import { isEqual } from 'lodash';
|
import { isEqual } from 'lodash';
|
||||||
import { fetchHashtag, followHashtag, unfollowHashtag } from 'flavours/glitch/actions/tags';
|
import { fetchHashtag, followHashtag, unfollowHashtag } from 'flavours/glitch/actions/tags';
|
||||||
import Icon from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@ import { Link } from 'react-router-dom';
|
||||||
import { fetchAnnouncements, toggleShowAnnouncements } from 'flavours/glitch/actions/announcements';
|
import { fetchAnnouncements, toggleShowAnnouncements } from 'flavours/glitch/actions/announcements';
|
||||||
import AnnouncementsContainer from 'flavours/glitch/features/getting_started/containers/announcements_container';
|
import AnnouncementsContainer from 'flavours/glitch/features/getting_started/containers/announcements_container';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import IconWithBadge from 'flavours/glitch/components/icon_with_badge';
|
import { IconWithBadge } from 'flavours/glitch/components/icon_with_badge';
|
||||||
import NotSignedInIndicator from 'flavours/glitch/components/not_signed_in_indicator';
|
import { NotSignedInIndicator } from 'flavours/glitch/components/not_signed_in_indicator';
|
||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue