~cytrogen/masto-fe

e6a7cfd12e8a44a3f2193c174f9b4d51492e711a — Renaud Chaput 2 years ago e8fc445
[Glitch] Add stricter ESLint rules for Typescript files

Port 5eeb40bdbe4d5e7c5c60788c0e10311f4d125853 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
33 files changed, 168 insertions(+), 120 deletions(-)

M .eslintrc.js
M app/javascript/flavours/glitch/actions/app.ts
M app/javascript/flavours/glitch/actions/pin_statuses.js
M app/javascript/flavours/glitch/components/animated_number.tsx
M app/javascript/flavours/glitch/components/avatar.tsx
M app/javascript/flavours/glitch/components/blurhash.tsx
M app/javascript/flavours/glitch/components/domain.tsx
M app/javascript/flavours/glitch/components/gifv.tsx
M app/javascript/flavours/glitch/components/icon.tsx
M app/javascript/flavours/glitch/components/icon_button.tsx
M app/javascript/flavours/glitch/components/icon_with_badge.tsx
M app/javascript/flavours/glitch/components/not_signed_in_indicator.tsx
M app/javascript/flavours/glitch/components/radio_button.tsx
M app/javascript/flavours/glitch/components/relative_timestamp.tsx
M app/javascript/flavours/glitch/components/server_hero_image.tsx
M app/javascript/flavours/glitch/features/account_timeline/index.jsx
M app/javascript/flavours/glitch/features/ui/components/columns_area.jsx
M app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx
M app/javascript/flavours/glitch/features/ui/components/upload_area.jsx
M app/javascript/flavours/glitch/features/ui/index.jsx
M app/javascript/flavours/glitch/is_mobile.ts
M app/javascript/flavours/glitch/packs/common.js
M app/javascript/flavours/glitch/polyfills/base_polyfills.ts
M app/javascript/flavours/glitch/reducers/index.ts
M app/javascript/flavours/glitch/reducers/markers.js
M app/javascript/flavours/glitch/store/index.ts
M app/javascript/flavours/glitch/store/middlewares/errors.ts
M app/javascript/flavours/glitch/store/middlewares/loading_bar.ts
M app/javascript/flavours/glitch/store/middlewares/sounds.ts
M app/javascript/flavours/glitch/types/resources.ts
M app/javascript/flavours/glitch/utils/resize_image.js
M app/javascript/flavours/glitch/uuid.ts
M tsconfig.json
M .eslintrc.js => .eslintrc.js +1 -1
@@ 319,7 319,7 @@ module.exports = {
              },
              // Internal packages
              {
                pattern: '{mastodon/**}',
                pattern: '{mastodon/**,flavours/glitch-soc/**}',
                group: 'internal',
                position: 'after',
              },

M app/javascript/flavours/glitch/actions/app.ts => app/javascript/flavours/glitch/actions/app.ts +3 -2
@@ 1,8 1,9 @@
import { createAction } from '@reduxjs/toolkit';

import type { LayoutType } from '../is_mobile';

type ChangeLayoutPayload = {
interface ChangeLayoutPayload {
  layout: LayoutType;
};
}
export const changeLayout =
  createAction<ChangeLayoutPayload>('APP_LAYOUT_CHANGE');

M app/javascript/flavours/glitch/actions/pin_statuses.js => app/javascript/flavours/glitch/actions/pin_statuses.js +2 -2
@@ 1,12 1,12 @@
import api from '../api';
import { importFetchedStatuses } from './importer';

import { me } from 'flavours/glitch/initial_state';

export const PINNED_STATUSES_FETCH_REQUEST = 'PINNED_STATUSES_FETCH_REQUEST';
export const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS';
export const PINNED_STATUSES_FETCH_FAIL = 'PINNED_STATUSES_FETCH_FAIL';

import { me } from 'flavours/glitch/initial_state';

export function fetchPinnedStatuses() {
  return (dispatch, getState) => {
    dispatch(fetchPinnedStatusesRequest());

M app/javascript/flavours/glitch/components/animated_number.tsx => app/javascript/flavours/glitch/components/animated_number.tsx +11 -4
@@ 1,8 1,11 @@
import React, { useCallback, useState } from 'react';
import ShortNumber from './short_number';

import { TransitionMotion, spring } from 'react-motion';

import { reduceMotion } from '../initial_state';

import ShortNumber from './short_number';

const obfuscatedCount = (count: number) => {
  if (count < 0) {
    return 0;


@@ 13,10 16,10 @@ const obfuscatedCount = (count: number) => {
  }
};

type Props = {
interface Props {
  value: number;
  obfuscate?: boolean;
};
}
export const AnimatedNumber: React.FC<Props> = ({ value, obfuscate }) => {
  const [previousValue, setPreviousValue] = useState(value);
  const [direction, setDirection] = useState<1 | -1>(1);


@@ 64,7 67,11 @@ export const AnimatedNumber: React.FC<Props> = ({ value, obfuscate }) => {
                transform: `translateY(${style.y * 100}%)`,
              }}
            >
              {obfuscate ? obfuscatedCount(data) : <ShortNumber value={data} />}
              {obfuscate ? (
                obfuscatedCount(data as number)
              ) : (
                <ShortNumber value={data as number} />
              )}
            </span>
          ))}
        </span>

M app/javascript/flavours/glitch/components/avatar.tsx => app/javascript/flavours/glitch/components/avatar.tsx +5 -3
@@ 1,16 1,18 @@
import * as React from 'react';

import classNames from 'classnames';
import { autoPlayGif } from 'flavours/glitch/initial_state';

import { useHovering } from 'flavours/glitch/hooks/useHovering';
import { autoPlayGif } from 'flavours/glitch/initial_state';
import type { Account } from 'flavours/glitch/types/resources';

type Props = {
interface Props {
  account: Account | undefined;
  className?: string;
  size: number;
  style?: React.CSSProperties;
  inline?: boolean;
};
}

export const Avatar: React.FC<Props> = ({
  account,

M app/javascript/flavours/glitch/components/blurhash.tsx => app/javascript/flavours/glitch/components/blurhash.tsx +5 -4
@@ 1,14 1,14 @@
import { decode } from 'blurhash';
import React, { useRef, useEffect } from 'react';

type Props = {
import { decode } from 'blurhash';

interface Props extends React.HTMLAttributes<HTMLCanvasElement> {
  hash: string;
  width?: number;
  height?: number;
  dummy?: boolean; // Whether dummy mode is enabled. If enabled, nothing is rendered and canvas left untouched
  children?: never;
  [key: string]: any;
};
}
const Blurhash: React.FC<Props> = ({
  hash,
  width = 32,


@@ 21,6 21,7 @@ const Blurhash: React.FC<Props> = ({
  useEffect(() => {
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    const canvas = canvasRef.current!;

    // eslint-disable-next-line no-self-assign
    canvas.width = canvas.width; // resets canvas


M app/javascript/flavours/glitch/components/domain.tsx => app/javascript/flavours/glitch/components/domain.tsx +6 -3
@@ 1,6 1,9 @@
import React, { useCallback } from 'react';

import type { InjectedIntl } from 'react-intl';
import { defineMessages, injectIntl } from 'react-intl';

import { IconButton } from './icon_button';
import { InjectedIntl, defineMessages, injectIntl } from 'react-intl';

const messages = defineMessages({
  unblockDomain: {


@@ 9,11 12,11 @@ const messages = defineMessages({
  },
});

type Props = {
interface Props {
  domain: string;
  onUnblockDomain: (domain: string) => void;
  intl: InjectedIntl;
};
}
const _Domain: React.FC<Props> = ({ domain, onUnblockDomain, intl }) => {
  const handleDomainUnblock = useCallback(() => {
    onUnblockDomain(domain);

M app/javascript/flavours/glitch/components/gifv.tsx => app/javascript/flavours/glitch/components/gifv.tsx +2 -2
@@ 1,6 1,6 @@
import React, { useCallback, useState } from 'react';

type Props = {
interface Props {
  src: string;
  key: string;
  alt?: string;


@@ 8,7 8,7 @@ type Props = {
  width: number;
  height: number;
  onClick?: () => void;
};
}

export const GIFV: React.FC<Props> = ({
  src,

M app/javascript/flavours/glitch/components/icon.tsx => app/javascript/flavours/glitch/components/icon.tsx +4 -3
@@ 1,13 1,14 @@
import React from 'react';

import classNames from 'classnames';

type Props = {
interface Props extends React.HTMLAttributes<HTMLImageElement> {
  id: string;
  className?: string;
  fixedWidth?: boolean;
  children?: never;
  [key: string]: any;
};
}

export const Icon: React.FC<Props> = ({
  id,
  className,

M app/javascript/flavours/glitch/components/icon_button.tsx => app/javascript/flavours/glitch/components/icon_button.tsx +7 -5
@@ 1,9 1,11 @@
import React from 'react';

import classNames from 'classnames';
import { Icon } from './icon';

import { AnimatedNumber } from './animated_number';
import { Icon } from './icon';

type Props = {
interface Props {
  className?: string;
  title: string;
  icon: string;


@@ 26,11 28,11 @@ type Props = {
  obfuscateCount?: boolean;
  href?: string;
  ariaHidden: boolean;
};
type States = {
}
interface States {
  activate: boolean;
  deactivate: boolean;
};
}
export class IconButton extends React.PureComponent<Props, States> {
  static defaultProps = {
    size: 18,

M app/javascript/flavours/glitch/components/icon_with_badge.tsx => app/javascript/flavours/glitch/components/icon_with_badge.tsx +3 -2
@@ 1,14 1,15 @@
import React from 'react';

import { Icon } from './icon';

const formatNumber = (num: number): number | string => (num > 40 ? '40+' : num);

type Props = {
interface Props {
  id: string;
  count: number;
  issueBadge: boolean;
  className: string;
};
}
export const IconWithBadge: React.FC<Props> = ({
  id,
  count,

M app/javascript/flavours/glitch/components/not_signed_in_indicator.tsx => app/javascript/flavours/glitch/components/not_signed_in_indicator.tsx +1 -0
@@ 1,4 1,5 @@
import React from 'react';

import { FormattedMessage } from 'react-intl';

export const NotSignedInIndicator: React.FC = () => (

M app/javascript/flavours/glitch/components/radio_button.tsx => app/javascript/flavours/glitch/components/radio_button.tsx +3 -2
@@ 1,13 1,14 @@
import React from 'react';

import classNames from 'classnames';

type Props = {
interface Props {
  value: string;
  checked: boolean;
  name: string;
  onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
  label: React.ReactNode;
};
}

export const RadioButton: React.FC<Props> = ({
  name,

M app/javascript/flavours/glitch/components/relative_timestamp.tsx => app/javascript/flavours/glitch/components/relative_timestamp.tsx +7 -5
@@ 1,5 1,7 @@
import React from 'react';
import { injectIntl, defineMessages, InjectedIntl } from 'react-intl';

import type { InjectedIntl } from 'react-intl';
import { injectIntl, defineMessages } from 'react-intl';

const messages = defineMessages({
  today: { id: 'relative_time.today', defaultMessage: 'today' },


@@ 187,16 189,16 @@ const timeRemainingString = (
  return relativeTime;
};

type Props = {
interface Props {
  intl: InjectedIntl;
  timestamp: string;
  year: number;
  futureDate?: boolean;
  short?: boolean;
};
type States = {
}
interface States {
  now: number;
};
}
class RelativeTimestamp extends React.Component<Props, States> {
  state = {
    now: this.props.intl.now(),

M app/javascript/flavours/glitch/components/server_hero_image.tsx => app/javascript/flavours/glitch/components/server_hero_image.tsx +5 -3
@@ 1,13 1,15 @@
import React, { useCallback, useState } from 'react';
import { Blurhash } from './blurhash';

import classNames from 'classnames';

type Props = {
import { Blurhash } from './blurhash';

interface Props {
  src: string;
  srcSet?: string;
  blurhash?: string;
  className?: string;
};
}

export const ServerHeroImage: React.FC<Props> = ({
  src,

M app/javascript/flavours/glitch/features/account_timeline/index.jsx => app/javascript/flavours/glitch/features/account_timeline/index.jsx +1 -1
@@ 3,7 3,7 @@ import { connect } from 'react-redux';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import { lookupAccount, fetchAccount } from 'flavours/glitch/actions/accounts';
import { expandAccountFeaturedTimeline, expandAccountTimeline } from 'flavours/glitch/actions/timelines';
import { expandAccountFeaturedTimeline, expandAccountTimeline } from '../../actions/timelines';
import StatusList from '../../components/status_list';
import LoadingIndicator from '../../components/loading_indicator';
import Column from '../ui/components/column';

M app/javascript/flavours/glitch/features/ui/components/columns_area.jsx => app/javascript/flavours/glitch/features/ui/components/columns_area.jsx +1 -1
@@ 18,7 18,7 @@ import {
  BookmarkedStatuses,
  ListTimeline,
  Directory,
} from '../../ui/util/async-components';
} from '../util/async-components';
import ComposePanel from './compose_panel';
import NavigationPanel from './navigation_panel';


M app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx => app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx +1 -1
@@ 4,7 4,7 @@ import PropTypes from 'prop-types';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import classNames from 'classnames';
import { changeUploadCompose, uploadThumbnail, onChangeMediaDescription, onChangeMediaFocus } from 'flavours/glitch/actions/compose';
import { changeUploadCompose, uploadThumbnail, onChangeMediaDescription, onChangeMediaFocus } from '../../../actions/compose';
import Video, { getPointerPosition } from 'flavours/glitch/features/video';
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
import { IconButton } from 'flavours/glitch/components/icon_button';

M app/javascript/flavours/glitch/features/ui/components/upload_area.jsx => app/javascript/flavours/glitch/features/ui/components/upload_area.jsx +1 -1
@@ 1,6 1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import Motion from '../../ui/util/optional_motion';
import Motion from '../util/optional_motion';
import spring from 'react-motion/lib/spring';
import { FormattedMessage } from 'react-intl';


M app/javascript/flavours/glitch/features/ui/index.jsx => app/javascript/flavours/glitch/features/ui/index.jsx +1 -1
@@ 64,7 64,7 @@ import Header from './components/header';

// Dummy import, to make sure that <Status /> ends up in the application bundle.
// Without this it ends up in ~8 very commonly used bundles.
import '../../../glitch/components/status';
import "../../components/status";

const messages = defineMessages({
  beforeUnload: { id: 'ui.beforeunload', defaultMessage: 'Your draft will be lost if you leave Mastodon.' },

M app/javascript/flavours/glitch/is_mobile.ts => app/javascript/flavours/glitch/is_mobile.ts +1 -0
@@ 1,4 1,5 @@
import { supportsPassiveEvents } from 'detect-passive-events';

import { forceSingleColumn } from 'flavours/glitch/initial_state';

const LAYOUT_BREAKPOINT = 630;

M app/javascript/flavours/glitch/packs/common.js => app/javascript/flavours/glitch/packs/common.js +2 -2
@@ 1,9 1,9 @@
import 'packs/public-path';
import { start } from '@rails/ujs';

start();

import 'flavours/glitch/styles/index.scss';

start();

//  This ensures that webpack compiles our images.
require.context('../images', true);

M app/javascript/flavours/glitch/polyfills/base_polyfills.ts => app/javascript/flavours/glitch/polyfills/base_polyfills.ts +7 -2
@@ 10,8 10,13 @@ if (!HTMLCanvasElement.prototype.toBlob) {
  const BASE64_MARKER = ';base64,';

  Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
    value(callback: BlobCallback, type = 'image/png', quality: any) {
      const dataURL = this.toDataURL(type, quality);
    value: function (
      this: HTMLCanvasElement,
      callback: BlobCallback,
      type = 'image/png',
      quality: unknown
    ) {
      const dataURL: string = this.toDataURL(type, quality);
      let data;

      if (dataURL.indexOf(BASE64_MARKER) >= 0) {

M app/javascript/flavours/glitch/reducers/index.ts => app/javascript/flavours/glitch/reducers/index.ts +35 -34
@@ 1,48 1,49 @@
import { combineReducers } from 'redux-immutable';
import dropdown_menu from './dropdown_menu';
import timelines from './timelines';
import meta from './meta';
import alerts from './alerts';
import { loadingBarReducer } from 'react-redux-loading-bar';
import modal from './modal';
import user_lists from './user_lists';
import domain_lists from './domain_lists';
import { combineReducers } from 'redux-immutable';

import account_notes from './account_notes';
import accounts from './accounts';
import accounts_counters from './accounts_counters';
import statuses from './statuses';
import relationships from './relationships';
import settings from './settings';
import local_settings from './local_settings';
import push_notifications from './push_notifications';
import status_lists from './status_lists';
import mutes from './mutes';
import accounts_map from './accounts_map';
import alerts from './alerts';
import announcements from './announcements';
import blocks from './blocks';
import server from './server';
import boosts from './boosts';
import contexts from './contexts';
import compose from './compose';
import search from './search';
import media_attachments from './media_attachments';
import notifications from './notifications';
import height_cache from './height_cache';
import contexts from './contexts';
import conversations from './conversations';
import custom_emojis from './custom_emojis';
import lists from './lists';
import listEditor from './list_editor';
import listAdder from './list_adder';
import domain_lists from './domain_lists';
import dropdown_menu from './dropdown_menu';
import filters from './filters';
import conversations from './conversations';
import suggestions from './suggestions';
import pinnedAccountsEditor from './pinned_accounts_editor';
import polls from './polls';
import trends from './trends';
import announcements from './announcements';
import followed_tags from './followed_tags';
import height_cache from './height_cache';
import history from './history';
import listAdder from './list_adder';
import listEditor from './list_editor';
import lists from './lists';
import local_settings from './local_settings';
import markers from './markers';
import account_notes from './account_notes';
import media_attachments from './media_attachments';
import meta from './meta';
import modal from './modal';
import mutes from './mutes';
import notifications from './notifications';
import picture_in_picture from './picture_in_picture';
import accounts_map from './accounts_map';
import history from './history';
import pinnedAccountsEditor from './pinned_accounts_editor';
import polls from './polls';
import push_notifications from './push_notifications';
import relationships from './relationships';
import search from './search';
import server from './server';
import settings from './settings';
import status_lists from './status_lists';
import statuses from './statuses';
import suggestions from './suggestions';
import tags from './tags';
import followed_tags from './followed_tags';
import timelines from './timelines';
import trends from './trends';
import user_lists from './user_lists';

const reducers = {
  announcements,

M app/javascript/flavours/glitch/reducers/markers.js => app/javascript/flavours/glitch/reducers/markers.js +2 -2
@@ 2,13 2,13 @@ import {
  MARKERS_SUBMIT_SUCCESS,
} from '../actions/markers';

import { Map as ImmutableMap } from 'immutable';

const initialState = ImmutableMap({
  home: '0',
  notifications: '0',
});

import { Map as ImmutableMap } from 'immutable';

export default function markers(state = initialState, action) {
  switch(action.type) {
  case MARKERS_SUBMIT_SUCCESS:

M app/javascript/flavours/glitch/store/index.ts => app/javascript/flavours/glitch/store/index.ts +6 -2
@@ 1,9 1,13 @@
import type { TypedUseSelectorHook } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';

import { configureStore } from '@reduxjs/toolkit';

import { rootReducer } from '../reducers';
import { loadingBarMiddleware } from './middlewares/loading_bar';

import { errorsMiddleware } from './middlewares/errors';
import { loadingBarMiddleware } from './middlewares/loading_bar';
import { soundsMiddleware } from './middlewares/sounds';
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';

export const store = configureStore({
  reducer: rootReducer,

M app/javascript/flavours/glitch/store/middlewares/errors.ts => app/javascript/flavours/glitch/store/middlewares/errors.ts +6 -4
@@ 1,17 1,19 @@
import { Middleware } from 'redux';
import type { AnyAction, Middleware } from 'redux';

import { showAlertForError } from 'flavours/glitch/actions/alerts';
import { RootState } from '..';

import type { RootState } from '..';

const defaultFailSuffix = 'FAIL';

export const errorsMiddleware: Middleware<Record<string, never>, RootState> =
  ({ dispatch }) =>
  (next) =>
  (action) => {
  (action: AnyAction & { skipAlert?: boolean; skipNotFound?: boolean }) => {
    if (action.type && !action.skipAlert) {
      const isFail = new RegExp(`${defaultFailSuffix}$`, 'g');

      if (action.type.match(isFail)) {
      if (typeof action.type === 'string' && action.type.match(isFail)) {
        dispatch(showAlertForError(action.error, action.skipNotFound));
      }
    }

M app/javascript/flavours/glitch/store/middlewares/loading_bar.ts => app/javascript/flavours/glitch/store/middlewares/loading_bar.ts +13 -10
@@ 1,6 1,7 @@
import { showLoading, hideLoading } from 'react-redux-loading-bar';
import { Middleware } from 'redux';
import { RootState } from '..';
import type { AnyAction, Middleware } from 'redux';

import type { RootState } from '..';

interface Config {
  promiseTypeSuffixes?: string[];


@@ 19,7 20,7 @@ export const loadingBarMiddleware = (

  return ({ dispatch }) =>
    (next) =>
    (action) => {
    (action: AnyAction) => {
      if (action.type && !action.skipLoading) {
        const [PENDING, FULFILLED, REJECTED] = promiseTypeSuffixes;



@@ 27,13 28,15 @@ export const loadingBarMiddleware = (
        const isFulfilled = new RegExp(`${FULFILLED}$`, 'g');
        const isRejected = new RegExp(`${REJECTED}$`, 'g');

        if (action.type.match(isPending)) {
          dispatch(showLoading());
        } else if (
          action.type.match(isFulfilled) ||
          action.type.match(isRejected)
        ) {
          dispatch(hideLoading());
        if (typeof action.type === 'string') {
          if (action.type.match(isPending)) {
            dispatch(showLoading());
          } else if (
            action.type.match(isFulfilled) ||
            action.type.match(isRejected)
          ) {
            dispatch(hideLoading());
          }
        }
      }


M app/javascript/flavours/glitch/store/middlewares/sounds.ts => app/javascript/flavours/glitch/store/middlewares/sounds.ts +13 -10
@@ 1,5 1,6 @@
import { Middleware, AnyAction } from 'redux';
import { RootState } from '..';
import type { Middleware, AnyAction } from 'redux';

import type { RootState } from '..';

interface AudioSource {
  src: string;


@@ 27,7 28,7 @@ const play = (audio: HTMLAudioElement) => {
    }
  }

  audio.play();
  void audio.play();
};

export const soundsMiddleware = (): Middleware<


@@ 47,13 48,15 @@ export const soundsMiddleware = (): Middleware<
    ]),
  };

  return () => (next) => (action: AnyAction) => {
    const sound = action?.meta?.sound;
  return () =>
    (next) =>
    (action: AnyAction & { meta?: { sound?: string } }) => {
      const sound = action?.meta?.sound;

    if (sound && soundCache[sound]) {
      play(soundCache[sound]);
    }
      if (sound && soundCache[sound]) {
        play(soundCache[sound]);
      }

    return next(action);
  };
      return next(action);
    };
};

M app/javascript/flavours/glitch/types/resources.ts => app/javascript/flavours/glitch/types/resources.ts +4 -4
@@ 12,7 12,7 @@ type AccountField = Record<{
  verified_at: string | null;
}>;

type AccountApiResponseValues = {
interface AccountApiResponseValues {
  acct: string;
  avatar: string;
  avatar_static: string;


@@ 34,7 34,7 @@ type AccountApiResponseValues = {
  statuses_count: number;
  url: string;
  username: string;
};
}

type NormalizedAccountField = Record<{
  name_emojified: string;


@@ 42,12 42,12 @@ type NormalizedAccountField = Record<{
  value_plain: string;
}>;

type NormalizedAccountValues = {
interface NormalizedAccountValues {
  display_name_html: string;
  fields: NormalizedAccountField[];
  note_emojified: string;
  note_plain: string;
};
}

export type Account = Record<
  AccountApiResponseValues & NormalizedAccountValues

M app/javascript/flavours/glitch/utils/resize_image.js => app/javascript/flavours/glitch/utils/resize_image.js +3 -1
@@ 170,7 170,7 @@ const resizeImage = (img, type = 'image/png') => new Promise((resolve, reject) =
    .catch(reject);
});

export default inputFile => new Promise((resolve) => {
const resizeFile = (inputFile) => new Promise((resolve) => {
  if (!inputFile.type.match(/image.*/) || inputFile.type === 'image/gif') {
    resolve(inputFile);
    return;


@@ 187,3 187,5 @@ export default inputFile => new Promise((resolve) => {
      .catch(() => resolve(inputFile));
  }).catch(() => resolve(inputFile));
});

export default resizeFile;

M app/javascript/flavours/glitch/uuid.ts => app/javascript/flavours/glitch/uuid.ts +4 -3
@@ 1,8 1,9 @@
export function uuid(a?: string): string {
  return a
    ? (
        (a as any as number) ^
        ((Math.random() * 16) >> ((a as any as number) / 4))
        (a as unknown as number) ^
        ((Math.random() * 16) >> ((a as unknown as number) / 4))
      ).toString(16)
    : ('' + 1e7 + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid);
    : // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
      ('' + 1e7 + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid);
}

M tsconfig.json => tsconfig.json +2 -0
@@ 12,6 12,8 @@
    "baseUrl": "./",
    "paths": {
      "locales": ["app/javascript/locales"],
      "styles/*": ["app/javascript/styles/*"],
      "packs/public-path": ["app/javascript/packs/public-path"],
      "flavours/glitch": ["app/javascript/flavours/glitch"],
      "flavours/glitch/*": ["app/javascript/flavours/glitch/*"],
      "mastodon": ["app/javascript/mastodon"],