diff --git a/.eslintrc.js b/.eslintrc.js index 1800daa55d..badcb1dcb9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -319,7 +319,7 @@ module.exports = { }, // Internal packages { - pattern: '{mastodon/**}', + pattern: '{mastodon/**,flavours/glitch-soc/**}', group: 'internal', position: 'after', }, diff --git a/app/javascript/flavours/glitch/actions/app.ts b/app/javascript/flavours/glitch/actions/app.ts index 46b2cdf93c..6fbfc07f68 100644 --- a/app/javascript/flavours/glitch/actions/app.ts +++ b/app/javascript/flavours/glitch/actions/app.ts @@ -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('APP_LAYOUT_CHANGE'); diff --git a/app/javascript/flavours/glitch/actions/pin_statuses.js b/app/javascript/flavours/glitch/actions/pin_statuses.js index d8c0a13737..a0d5933b1c 100644 --- a/app/javascript/flavours/glitch/actions/pin_statuses.js +++ b/app/javascript/flavours/glitch/actions/pin_statuses.js @@ -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()); diff --git a/app/javascript/flavours/glitch/components/animated_number.tsx b/app/javascript/flavours/glitch/components/animated_number.tsx index f6c77d35ff..b6b073161b 100644 --- a/app/javascript/flavours/glitch/components/animated_number.tsx +++ b/app/javascript/flavours/glitch/components/animated_number.tsx @@ -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 = ({ value, obfuscate }) => { const [previousValue, setPreviousValue] = useState(value); const [direction, setDirection] = useState<1 | -1>(1); @@ -64,7 +67,11 @@ export const AnimatedNumber: React.FC = ({ value, obfuscate }) => { transform: `translateY(${style.y * 100}%)`, }} > - {obfuscate ? obfuscatedCount(data) : } + {obfuscate ? ( + obfuscatedCount(data as number) + ) : ( + + )} ))} diff --git a/app/javascript/flavours/glitch/components/avatar.tsx b/app/javascript/flavours/glitch/components/avatar.tsx index 1bd7739f5f..11253a8e94 100644 --- a/app/javascript/flavours/glitch/components/avatar.tsx +++ b/app/javascript/flavours/glitch/components/avatar.tsx @@ -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 = ({ account, diff --git a/app/javascript/flavours/glitch/components/blurhash.tsx b/app/javascript/flavours/glitch/components/blurhash.tsx index 7005136765..1550d0b7a5 100644 --- a/app/javascript/flavours/glitch/components/blurhash.tsx +++ b/app/javascript/flavours/glitch/components/blurhash.tsx @@ -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 { 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 = ({ hash, width = 32, @@ -21,6 +21,7 @@ const Blurhash: React.FC = ({ 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 diff --git a/app/javascript/flavours/glitch/components/domain.tsx b/app/javascript/flavours/glitch/components/domain.tsx index af0fec35af..9e8e04b65c 100644 --- a/app/javascript/flavours/glitch/components/domain.tsx +++ b/app/javascript/flavours/glitch/components/domain.tsx @@ -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 = ({ domain, onUnblockDomain, intl }) => { const handleDomainUnblock = useCallback(() => { onUnblockDomain(domain); diff --git a/app/javascript/flavours/glitch/components/gifv.tsx b/app/javascript/flavours/glitch/components/gifv.tsx index 72914ba741..c606a29048 100644 --- a/app/javascript/flavours/glitch/components/gifv.tsx +++ b/app/javascript/flavours/glitch/components/gifv.tsx @@ -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 = ({ src, diff --git a/app/javascript/flavours/glitch/components/icon.tsx b/app/javascript/flavours/glitch/components/icon.tsx index 4eb948dc76..6bd15da6ac 100644 --- a/app/javascript/flavours/glitch/components/icon.tsx +++ b/app/javascript/flavours/glitch/components/icon.tsx @@ -1,13 +1,14 @@ import React from 'react'; + import classNames from 'classnames'; -type Props = { +interface Props extends React.HTMLAttributes { id: string; className?: string; fixedWidth?: boolean; children?: never; - [key: string]: any; -}; +} + export const Icon: React.FC = ({ id, className, diff --git a/app/javascript/flavours/glitch/components/icon_button.tsx b/app/javascript/flavours/glitch/components/icon_button.tsx index 80b20ae1b0..0b81288241 100644 --- a/app/javascript/flavours/glitch/components/icon_button.tsx +++ b/app/javascript/flavours/glitch/components/icon_button.tsx @@ -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 { static defaultProps = { size: 18, diff --git a/app/javascript/flavours/glitch/components/icon_with_badge.tsx b/app/javascript/flavours/glitch/components/icon_with_badge.tsx index bf86814c03..e427b7172b 100644 --- a/app/javascript/flavours/glitch/components/icon_with_badge.tsx +++ b/app/javascript/flavours/glitch/components/icon_with_badge.tsx @@ -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 = ({ id, count, diff --git a/app/javascript/flavours/glitch/components/not_signed_in_indicator.tsx b/app/javascript/flavours/glitch/components/not_signed_in_indicator.tsx index 53945d6a7a..7a71f6539d 100644 --- a/app/javascript/flavours/glitch/components/not_signed_in_indicator.tsx +++ b/app/javascript/flavours/glitch/components/not_signed_in_indicator.tsx @@ -1,4 +1,5 @@ import React from 'react'; + import { FormattedMessage } from 'react-intl'; export const NotSignedInIndicator: React.FC = () => ( diff --git a/app/javascript/flavours/glitch/components/radio_button.tsx b/app/javascript/flavours/glitch/components/radio_button.tsx index 829f471747..67acb09f42 100644 --- a/app/javascript/flavours/glitch/components/radio_button.tsx +++ b/app/javascript/flavours/glitch/components/radio_button.tsx @@ -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) => void; label: React.ReactNode; -}; +} export const RadioButton: React.FC = ({ name, diff --git a/app/javascript/flavours/glitch/components/relative_timestamp.tsx b/app/javascript/flavours/glitch/components/relative_timestamp.tsx index 65d9d27cb2..e0e0d4bb53 100644 --- a/app/javascript/flavours/glitch/components/relative_timestamp.tsx +++ b/app/javascript/flavours/glitch/components/relative_timestamp.tsx @@ -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 { state = { now: this.props.intl.now(), diff --git a/app/javascript/flavours/glitch/components/server_hero_image.tsx b/app/javascript/flavours/glitch/components/server_hero_image.tsx index d10b8a620b..973d1d1b37 100644 --- a/app/javascript/flavours/glitch/components/server_hero_image.tsx +++ b/app/javascript/flavours/glitch/components/server_hero_image.tsx @@ -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 = ({ src, diff --git a/app/javascript/flavours/glitch/features/account_timeline/index.jsx b/app/javascript/flavours/glitch/features/account_timeline/index.jsx index 0a4bb94888..3739ce23ca 100644 --- a/app/javascript/flavours/glitch/features/account_timeline/index.jsx +++ b/app/javascript/flavours/glitch/features/account_timeline/index.jsx @@ -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'; diff --git a/app/javascript/flavours/glitch/features/ui/components/columns_area.jsx b/app/javascript/flavours/glitch/features/ui/components/columns_area.jsx index 458f48cde0..a466a3eb61 100644 --- a/app/javascript/flavours/glitch/features/ui/components/columns_area.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/columns_area.jsx @@ -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'; diff --git a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx index 2b61bad70e..250e781cf2 100644 --- a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx @@ -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'; diff --git a/app/javascript/flavours/glitch/features/ui/components/upload_area.jsx b/app/javascript/flavours/glitch/features/ui/components/upload_area.jsx index 0e07b67f87..5b4d0ce60f 100644 --- a/app/javascript/flavours/glitch/features/ui/components/upload_area.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/upload_area.jsx @@ -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'; diff --git a/app/javascript/flavours/glitch/features/ui/index.jsx b/app/javascript/flavours/glitch/features/ui/index.jsx index 4fc2372b37..15b94273db 100644 --- a/app/javascript/flavours/glitch/features/ui/index.jsx +++ b/app/javascript/flavours/glitch/features/ui/index.jsx @@ -64,7 +64,7 @@ import Header from './components/header'; // Dummy import, to make sure that 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.' }, diff --git a/app/javascript/flavours/glitch/is_mobile.ts b/app/javascript/flavours/glitch/is_mobile.ts index c91ba4d53d..d69beb2402 100644 --- a/app/javascript/flavours/glitch/is_mobile.ts +++ b/app/javascript/flavours/glitch/is_mobile.ts @@ -1,4 +1,5 @@ import { supportsPassiveEvents } from 'detect-passive-events'; + import { forceSingleColumn } from 'flavours/glitch/initial_state'; const LAYOUT_BREAKPOINT = 630; diff --git a/app/javascript/flavours/glitch/packs/common.js b/app/javascript/flavours/glitch/packs/common.js index 7dc34eba93..a750c3668d 100644 --- a/app/javascript/flavours/glitch/packs/common.js +++ b/app/javascript/flavours/glitch/packs/common.js @@ -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); diff --git a/app/javascript/flavours/glitch/polyfills/base_polyfills.ts b/app/javascript/flavours/glitch/polyfills/base_polyfills.ts index 64211c11e9..e008d8f025 100644 --- a/app/javascript/flavours/glitch/polyfills/base_polyfills.ts +++ b/app/javascript/flavours/glitch/polyfills/base_polyfills.ts @@ -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) { diff --git a/app/javascript/flavours/glitch/reducers/index.ts b/app/javascript/flavours/glitch/reducers/index.ts index da2174fc2c..eaef569f09 100644 --- a/app/javascript/flavours/glitch/reducers/index.ts +++ b/app/javascript/flavours/glitch/reducers/index.ts @@ -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, diff --git a/app/javascript/flavours/glitch/reducers/markers.js b/app/javascript/flavours/glitch/reducers/markers.js index e3d1b1936b..3e8b1780a7 100644 --- a/app/javascript/flavours/glitch/reducers/markers.js +++ b/app/javascript/flavours/glitch/reducers/markers.js @@ -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: diff --git a/app/javascript/flavours/glitch/store/index.ts b/app/javascript/flavours/glitch/store/index.ts index f7e1be6b7b..1ef9cb8184 100644 --- a/app/javascript/flavours/glitch/store/index.ts +++ b/app/javascript/flavours/glitch/store/index.ts @@ -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, diff --git a/app/javascript/flavours/glitch/store/middlewares/errors.ts b/app/javascript/flavours/glitch/store/middlewares/errors.ts index 5dec423af7..2697f80f18 100644 --- a/app/javascript/flavours/glitch/store/middlewares/errors.ts +++ b/app/javascript/flavours/glitch/store/middlewares/errors.ts @@ -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, 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)); } } diff --git a/app/javascript/flavours/glitch/store/middlewares/loading_bar.ts b/app/javascript/flavours/glitch/store/middlewares/loading_bar.ts index 183c0cf9d6..0f997fd349 100644 --- a/app/javascript/flavours/glitch/store/middlewares/loading_bar.ts +++ b/app/javascript/flavours/glitch/store/middlewares/loading_bar.ts @@ -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()); + } } } diff --git a/app/javascript/flavours/glitch/store/middlewares/sounds.ts b/app/javascript/flavours/glitch/store/middlewares/sounds.ts index e7c87df7ec..6005d3649e 100644 --- a/app/javascript/flavours/glitch/store/middlewares/sounds.ts +++ b/app/javascript/flavours/glitch/store/middlewares/sounds.ts @@ -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); + }; }; diff --git a/app/javascript/flavours/glitch/types/resources.ts b/app/javascript/flavours/glitch/types/resources.ts index 0906504150..63ec2993bb 100644 --- a/app/javascript/flavours/glitch/types/resources.ts +++ b/app/javascript/flavours/glitch/types/resources.ts @@ -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 diff --git a/app/javascript/flavours/glitch/utils/resize_image.js b/app/javascript/flavours/glitch/utils/resize_image.js index fb8c3c11e6..e3d4e6a354 100644 --- a/app/javascript/flavours/glitch/utils/resize_image.js +++ b/app/javascript/flavours/glitch/utils/resize_image.js @@ -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; diff --git a/app/javascript/flavours/glitch/uuid.ts b/app/javascript/flavours/glitch/uuid.ts index 6cadbd6bb0..0b4d55beb6 100644 --- a/app/javascript/flavours/glitch/uuid.ts +++ b/app/javascript/flavours/glitch/uuid.ts @@ -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); } diff --git a/tsconfig.json b/tsconfig.json index 022ab1f71e..d8f425f168 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -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"],