nicolium: do some linting but don't enable new rules for now
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@@ -132,7 +132,7 @@ const otpVerify =
|
||||
(code: string, mfa_token: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const state = getState();
|
||||
const app = state.auth.app;
|
||||
const baseUrl = parseBaseURL(state.me) || BuildConfig.BACKEND_URL;
|
||||
const baseUrl = parseBaseURL(state.me || undefined) || BuildConfig.BACKEND_URL;
|
||||
const client = new PlApiClient(baseUrl);
|
||||
return client.oauth
|
||||
.mfaChallenge({
|
||||
|
||||
@@ -11,7 +11,7 @@ import type { Me } from '@/types/pl-fe';
|
||||
// Taken from https://www.npmjs.com/package/web-push
|
||||
const urlBase64ToUint8Array = (base64String: string) => {
|
||||
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
|
||||
const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
|
||||
const base64 = (base64String + padding).replaceAll('-', '+').replaceAll('_', '/');
|
||||
|
||||
return decodeBase64(base64);
|
||||
};
|
||||
|
||||
@@ -106,7 +106,7 @@ const dequeueTimeline =
|
||||
|
||||
if (typeof expandFunc === 'function') {
|
||||
dispatch(clearTimeline(timelineId));
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
expandFunc();
|
||||
} else if (timelineId === 'home') {
|
||||
dispatch(clearTimeline(timelineId));
|
||||
@@ -166,7 +166,7 @@ const deduplicateStatuses = (statuses: Array<BaseStatus>) => {
|
||||
reblogged.accounts.push(status.account);
|
||||
reblogged.id += ':' + status.id;
|
||||
} else if (
|
||||
!deduplicatedStatuses.find(
|
||||
!deduplicatedStatuses.some(
|
||||
(deduplicatedStatus) => deduplicatedStatus.reblog?.id === status.id,
|
||||
)
|
||||
) {
|
||||
|
||||
@@ -15,7 +15,7 @@ const env = compileTime(() => {
|
||||
};
|
||||
|
||||
const sanitizeBasename = (path: string | undefined = ''): string =>
|
||||
`/${path.replace(/^\/+|\/+$/g, '')}`;
|
||||
`/${path.replaceAll(/^\/+|\/+$/g, '')}`;
|
||||
|
||||
return {
|
||||
NODE_ENV: NODE_ENV ?? 'development',
|
||||
|
||||
@@ -15,11 +15,10 @@ interface IEmoji {
|
||||
const Emoji: React.FC<IEmoji> = ({ emoji, emojiMap, hovered }) => {
|
||||
const { autoPlayGif, systemEmojiFont } = useSettings();
|
||||
|
||||
// @ts-ignore
|
||||
if (unicodeMapping[emoji]) {
|
||||
if (systemEmojiFont) return <>{emoji}</>;
|
||||
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
const { unified, shortCode } = unicodeMapping[emoji];
|
||||
const title = shortCode ? `:${shortCode}:` : '';
|
||||
|
||||
|
||||
@@ -40,9 +40,7 @@ const Reaction: React.FC<IReaction> = ({ announcementId, reaction, emojiMap, sty
|
||||
|
||||
let shortCode = reaction.name;
|
||||
|
||||
// @ts-ignore
|
||||
if (unicodeMapping[shortCode]) {
|
||||
// @ts-ignore
|
||||
shortCode = unicodeMapping[shortCode].shortcode;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ const ReactionsBar: React.FC<IReactionsBar> = ({ announcementId, reactions, emoj
|
||||
const { addReaction } = useAnnouncements();
|
||||
|
||||
const handleEmojiPick = (data: Emoji) => {
|
||||
addReaction({ announcementId, name: (data as NativeEmoji).native.replace(/:/g, '') });
|
||||
addReaction({ announcementId, name: (data as NativeEmoji).native.replaceAll(':', '') });
|
||||
};
|
||||
|
||||
const visibleReactions = reactions.filter((x) => x.count > 0);
|
||||
|
||||
@@ -116,7 +116,7 @@ const DropdownMenuItem = ({ index, item, onClick, autoFocus, onSetTab }: IDropdo
|
||||
if (itemRef.current && (autoFocus ? firstItem : item?.active)) {
|
||||
itemRef.current.focus({ preventScroll: true });
|
||||
}
|
||||
}, [itemRef.current, index]);
|
||||
}, [index]);
|
||||
|
||||
if (item === null) {
|
||||
return <hr />;
|
||||
|
||||
@@ -128,7 +128,7 @@ const DropdownMenuContent: React.FC<IDropdownMenuContent> = ({
|
||||
e.stopPropagation();
|
||||
}
|
||||
},
|
||||
[ref.current],
|
||||
[],
|
||||
);
|
||||
|
||||
const handleDocumentClick = useMemo(
|
||||
@@ -138,7 +138,7 @@ const DropdownMenuContent: React.FC<IDropdownMenuContent> = ({
|
||||
event.stopPropagation();
|
||||
}
|
||||
},
|
||||
[ref.current],
|
||||
[],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -153,7 +153,7 @@ const DropdownMenuContent: React.FC<IDropdownMenuContent> = ({
|
||||
document.removeEventListener('touchend', handleDocumentClick);
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}, [ref.current]);
|
||||
}, []);
|
||||
|
||||
const handleExitSubmenu: React.EventHandler<any> = (event) => {
|
||||
event.stopPropagation();
|
||||
|
||||
@@ -35,7 +35,7 @@ const ExtendedVideoPlayer: React.FC<IExtendedVideoPlayer> = ({
|
||||
return () => {
|
||||
video.current?.removeEventListener('loadeddata', handleLoadedData);
|
||||
};
|
||||
}, [video.current]);
|
||||
}, []);
|
||||
|
||||
const handleClick: React.MouseEventHandler<HTMLVideoElement> = (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
@@ -64,7 +64,7 @@ const ListItem: React.FC<IListItem> = ({
|
||||
: childDescribedBy;
|
||||
|
||||
return React.cloneElement(child, {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
id: domId,
|
||||
'aria-labelledby': ariaLabelledBy,
|
||||
'aria-describedby': ariaDescribedBy,
|
||||
|
||||
@@ -367,7 +367,7 @@ const MediaGallery: React.FC<IMediaGallery> = (props) => {
|
||||
|
||||
setWidth(offsetWidth);
|
||||
}
|
||||
}, [node.current]);
|
||||
}, []);
|
||||
|
||||
const handleClick = (index: number) => {
|
||||
onOpenMedia(media, index);
|
||||
@@ -655,7 +655,7 @@ const MediaGallery: React.FC<IMediaGallery> = (props) => {
|
||||
if (compact) {
|
||||
return {
|
||||
style: {},
|
||||
itemsDimensions: [...new Array(size)].map(() => ({
|
||||
itemsDimensions: new Array(size).fill('').map(() => ({
|
||||
w: 'auto',
|
||||
h: 'auto',
|
||||
top: 'auto',
|
||||
|
||||
@@ -29,7 +29,7 @@ const GREENTEXT_CLASS = 'dark:text-accent-green text-lime-600';
|
||||
const checkSuspiciousUrl = (url: string): boolean => {
|
||||
try {
|
||||
const { host } = new URL(url);
|
||||
return /^verify\.form/.test(host);
|
||||
return host.startsWith('verify.form');
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
@@ -213,16 +213,16 @@ function parseContent(
|
||||
const options: HTMLReactParserOptions = {
|
||||
replace(domNode) {
|
||||
if (!(domNode instanceof Element)) {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
domNode.preGreentext =
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
(!domNode.prev || domNode.prev.preGreentext) && !domNode.data.trim().length;
|
||||
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
const data = domNode.prev?.preGreentext ? domNode.data.trim() : domNode.data;
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
if (greentext && (data.startsWith('>') || domNode.prev?.greentext)) {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
domNode.greentext = true;
|
||||
return <span className={GREENTEXT_CLASS}>{transformText(domNode.data)}</span>;
|
||||
}
|
||||
@@ -239,24 +239,24 @@ function parseContent(
|
||||
}
|
||||
|
||||
if (domNode.attribs.class?.split(' ').includes('h-card')) {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
domNode.preGreentext = !domNode.prev || domNode.prev.preGreentext;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
if (domNode.name !== 'br' && domNode.prev?.greentext) {
|
||||
domNode.attribs.class = `${domNode.attribs.class || ''} ${GREENTEXT_CLASS}`;
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
domNode.greentext = true;
|
||||
}
|
||||
|
||||
if (domNode.name === 'a') {
|
||||
const classes = domNode.attribs.class?.split(' ');
|
||||
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
if (domNode.prev?.greentext) {
|
||||
classes.push(GREENTEXT_CLASS);
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
domNode.greentext = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,12 +26,12 @@ const safeParseFloat = (str: unknown): number | null => {
|
||||
const validTime = (t: string | boolean | null | undefined) => {
|
||||
if (t === null || t === undefined) return null;
|
||||
if (typeof t === 'boolean') return null;
|
||||
return t.match(/^-?[0-9.]+s$/) ? t : null;
|
||||
return /^-?[0-9.]+s$/.test(t) ? t : null;
|
||||
};
|
||||
|
||||
const validColor = (c: unknown): string | null => {
|
||||
if (typeof c !== 'string') return null;
|
||||
return c.match(/^[0-9a-f]{3,6}$/i) ? c : null;
|
||||
return /^[0-9a-f]{3,6}$/i.test(c) ? c : null;
|
||||
};
|
||||
|
||||
interface IParsedMfm {
|
||||
@@ -61,7 +61,7 @@ const ParsedMfm: React.FC<IParsedMfm> = React.memo(({ text, emojis, mentions, sp
|
||||
.map((token): React.JSX.Element | string | (React.JSX.Element | string)[] => {
|
||||
switch (token.type) {
|
||||
case 'text': {
|
||||
let text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n');
|
||||
let text = token.props.text.replaceAll(/(\r\n|\n|\r)/g, '\n');
|
||||
|
||||
if (speakAsCat) text = nyaize(text);
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ const PreviewCard: React.FC<IPreviewCard> = ({
|
||||
}}
|
||||
href={href}
|
||||
title={trimmedTitle}
|
||||
rel='noopener'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
dir={direction}
|
||||
>
|
||||
@@ -274,7 +274,7 @@ const PreviewCard: React.FC<IPreviewCard> = ({
|
||||
}}
|
||||
href={href}
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
rel='noopener noreferrer'
|
||||
className='text-gray-700 hover:text-gray-900 dark:text-gray-200 dark:hover:text-gray-100'
|
||||
title={intl.formatMessage(messages.externalLink)}
|
||||
>
|
||||
@@ -320,7 +320,7 @@ const PreviewCard: React.FC<IPreviewCard> = ({
|
||||
href={href}
|
||||
className={className}
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
rel='noopener noreferrer'
|
||||
ref={setRef}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
@@ -370,7 +370,7 @@ const PreviewCard: React.FC<IPreviewCard> = ({
|
||||
{linkBody}
|
||||
</Link>
|
||||
) : (
|
||||
<a href={author.url} target='_blank' rel='noopener'>
|
||||
<a href={author.url} target='_blank' rel='noopener noreferrer'>
|
||||
{linkBody}
|
||||
</a>
|
||||
)}
|
||||
@@ -396,7 +396,7 @@ const trim = (text: string, len: number): string => {
|
||||
return text;
|
||||
}
|
||||
|
||||
return text.substring(0, cut) + (text.length > len ? '…' : '');
|
||||
return text.slice(0, cut) + (text.length > len ? '…' : '');
|
||||
};
|
||||
|
||||
export { PreviewCard as default };
|
||||
|
||||
@@ -42,7 +42,7 @@ const SafeEmbed: React.FC<ISafeEmbed> = ({ className, sandbox, title, html }) =>
|
||||
return () => {
|
||||
iframe.current?.contentWindow?.removeEventListener('message', handleMessage);
|
||||
};
|
||||
}, [iframe.current, html]);
|
||||
}, [html]);
|
||||
|
||||
return (
|
||||
<iframe ref={iframe} className={className} sandbox={sandbox} height={height} title={title} />
|
||||
|
||||
@@ -15,7 +15,7 @@ interface IScrobble {
|
||||
const Scrobble: React.FC<IScrobble> = ({ scrobble }) => {
|
||||
const textRef = useRef<HTMLParagraphElement>(null);
|
||||
|
||||
const isRecent = new Date().getTime() - new Date(scrobble.created_at).getTime() <= 60 * 60 * 1000;
|
||||
const isRecent = Date.now() - new Date(scrobble.created_at).getTime() <= 60 * 60 * 1000;
|
||||
|
||||
const song = scrobble.artist ? (
|
||||
<FormattedMessage
|
||||
@@ -35,7 +35,7 @@ const Scrobble: React.FC<IScrobble> = ({ scrobble }) => {
|
||||
textRef.current &&
|
||||
textRef.current.parentElement &&
|
||||
textRef.current.clientWidth > textRef.current.parentElement.clientWidth,
|
||||
[textRef.current],
|
||||
[],
|
||||
);
|
||||
|
||||
if (!isRecent) return null;
|
||||
|
||||
@@ -77,9 +77,7 @@ const StatusReaction: React.FC<IStatusReaction> = ({
|
||||
|
||||
let shortCode = reaction.name;
|
||||
|
||||
// @ts-ignore
|
||||
if (unicodeMapping[shortCode]?.shortcode) {
|
||||
// @ts-ignore
|
||||
shortCode = unicodeMapping[shortCode].shortcode;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ const TrendingLink: React.FC<ITrendingLink> = ({ trendingLink }) => {
|
||||
className='flex cursor-pointer gap-4 overflow-hidden rounded-lg border border-solid border-gray-200 p-4 text-sm text-gray-800 no-underline hover:bg-gray-100 hover:no-underline dark:border-gray-800 dark:text-gray-200 dark:hover:bg-primary-800/30'
|
||||
href={trendingLink.url}
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
{media}
|
||||
<Stack space={2} className='flex-1 overflow-hidden'>
|
||||
|
||||
@@ -126,7 +126,7 @@ const Button = React.forwardRef<HTMLButtonElement | HTMLAnchorElement, IButton>(
|
||||
ref={ref as React.ForwardedRef<HTMLAnchorElement>}
|
||||
href={href}
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
{buttonChildren}
|
||||
</a>
|
||||
|
||||
@@ -28,12 +28,12 @@ const FormGroup: React.FC<IFormGroup> = (props) => {
|
||||
if (React.isValidElement(inputChildren[0])) {
|
||||
firstChild = React.cloneElement(
|
||||
inputChildren[0],
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
{ id: formFieldId },
|
||||
);
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
const isCheckboxFormGroup = firstChild?.type === Checkbox;
|
||||
|
||||
if (isCheckboxFormGroup) {
|
||||
|
||||
@@ -79,11 +79,11 @@ const HStack = forwardRef<HTMLDivElement, IHStack>((props, ref) => {
|
||||
className={clsx(
|
||||
'flex',
|
||||
{
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
[alignItemsOptions[alignItems]]: typeof alignItems !== 'undefined',
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
[justifyContentOptions[justifyContent]]: typeof justifyContent !== 'undefined',
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
[spaces[space]]: typeof space !== 'undefined',
|
||||
grow: grow,
|
||||
'flex-wrap': wrap,
|
||||
|
||||
@@ -64,11 +64,11 @@ const Stack = React.forwardRef<HTMLDivElement, IStack>(
|
||||
className={clsx(
|
||||
'flex flex-col',
|
||||
{
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
[spaces[space]]: typeof space !== 'undefined',
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
[alignItemsOptions[alignItems]]: typeof alignItems !== 'undefined',
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
[justifyContentOptions[justifyContent]]: typeof justifyContent !== 'undefined',
|
||||
grow: grow,
|
||||
},
|
||||
|
||||
@@ -32,21 +32,17 @@ const AnimatedTabs: React.FC<IAnimatedTabs> = ({ children, ...rest }) => {
|
||||
const ref = React.useRef<any>(null);
|
||||
const rect = useRect(ref);
|
||||
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
const top: number = (activeRect && activeRect.bottom) - (rect && rect.top);
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
const width: number = activeRect && activeRect.width - HORIZONTAL_PADDING * 2;
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
const left: number = (activeRect && activeRect.left) - (rect && rect.left) + HORIZONTAL_PADDING;
|
||||
|
||||
return (
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
<AnimatedContext.Provider value={setActiveRect}>
|
||||
<ReachTabs
|
||||
{...rest}
|
||||
// @ts-ignore
|
||||
ref={ref}
|
||||
>
|
||||
<ReachTabs {...rest} ref={ref}>
|
||||
<div className='absolute h-[3px] w-full bg-primary-200 dark:bg-gray-800' style={{ top }} />
|
||||
<div
|
||||
className={clsx('absolute h-[3px] bg-primary-500 transition-all duration-200', {
|
||||
@@ -89,15 +85,12 @@ const AnimatedTab: React.FC<IAnimatedTab> = ({ index, ...props }) => {
|
||||
// callup to set styles whenever we're active
|
||||
React.useLayoutEffect(() => {
|
||||
if (isSelected) {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
setActiveRect(rect);
|
||||
}
|
||||
}, [isSelected, rect, setActiveRect]);
|
||||
|
||||
return (
|
||||
// @ts-ignore
|
||||
<ReachTab ref={ref} {...props} />
|
||||
);
|
||||
return <ReachTab ref={ref} {...props} />;
|
||||
};
|
||||
|
||||
/** Structure to represent a tab. */
|
||||
@@ -147,7 +140,7 @@ const Tabs = ({ items, activeItem }: ITabs) => {
|
||||
key={name}
|
||||
as='button'
|
||||
role='button'
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
title={title}
|
||||
index={idx}
|
||||
>
|
||||
|
||||
@@ -53,7 +53,7 @@ const TagInput: React.FC<ITagInput> = ({ tags, onChange, placeholder }) => {
|
||||
wrap
|
||||
>
|
||||
{tags.map((tag, i) => (
|
||||
<div className='mb-2'>
|
||||
<div key={tag} className='mb-2'>
|
||||
<Tag tag={tag} onDelete={handleTagDelete} />
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -308,7 +308,7 @@ const Audio: React.FC<IAudio> = (props) => {
|
||||
|
||||
const _initAudioContext = () => {
|
||||
if (audio.current) {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
// eslint-disable-next-line compat/compat
|
||||
const AudioContext = window.AudioContext || window.webkitAudioContext;
|
||||
const context = new AudioContext();
|
||||
@@ -420,20 +420,20 @@ const Audio: React.FC<IAudio> = (props) => {
|
||||
if (player.current) {
|
||||
_setDimensions();
|
||||
}
|
||||
}, [player.current]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (audio.current) {
|
||||
setVolume(audio.current.volume);
|
||||
setMuted(audio.current.muted);
|
||||
}
|
||||
}, [audio.current]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (canvas.current && visualizer.current) {
|
||||
visualizer.current.setCanvas(canvas.current);
|
||||
}
|
||||
}, [canvas.current, visualizer.current]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
|
||||
@@ -114,7 +114,7 @@ class Visualizer {
|
||||
|
||||
if (i < 20) {
|
||||
let scale = delta / (200 * scaleCoefficient);
|
||||
scale = scale < 1 ? 1 : scale;
|
||||
scale = Math.max(1, scale);
|
||||
allScales.push(scale);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -29,7 +29,8 @@ const messages = defineMessages({
|
||||
|
||||
const BIG_EMOJI_LIMIT = 3;
|
||||
|
||||
const parsePendingContent = (content: string) => escape(content).replace(/(?:\r\n|\r|\n)/g, '<br>');
|
||||
const parsePendingContent = (content: string) =>
|
||||
escape(content).replaceAll(/(?:\r\n|\r|\n)/g, '<br>');
|
||||
|
||||
const parseContent = (chatMessage: ChatMessageEntity) => {
|
||||
const content = chatMessage.content || '';
|
||||
|
||||
@@ -35,7 +35,7 @@ const ChatsPage: React.FC = () => {
|
||||
|
||||
useLayoutEffect(() => {
|
||||
calculateHeight();
|
||||
}, [containerRef.current]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('resize', calculateHeight);
|
||||
|
||||
@@ -126,7 +126,7 @@ const getLanguageDropdown =
|
||||
|
||||
const search = (value: string) => {
|
||||
if (value === '') {
|
||||
return [...languages].sort((a, b) => {
|
||||
return languages.toSorted((a, b) => {
|
||||
// Push current selection to the top of the list
|
||||
|
||||
if (a[0] in textMap) {
|
||||
@@ -168,13 +168,13 @@ const getLanguageDropdown =
|
||||
|
||||
useEffect(() => {
|
||||
if (!language) input.current?.focus();
|
||||
}, [input.current]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (node.current) {
|
||||
(node.current?.querySelector('button[aria-selected=true]') as HTMLButtonElement)?.focus();
|
||||
}
|
||||
}, [node.current]);
|
||||
}, []);
|
||||
|
||||
const isSearching = searchValue !== '';
|
||||
|
||||
|
||||
@@ -201,13 +201,7 @@ const PrivacyDropdown: React.FC<IPrivacyDropdown> = ({ composeId, compact }) =>
|
||||
|
||||
const valueOption = useMemo(
|
||||
() =>
|
||||
[
|
||||
options,
|
||||
options
|
||||
.filter((option) => option.items)
|
||||
.map((option) => option.items)
|
||||
.flat(),
|
||||
]
|
||||
[options, options.filter((option) => option.items).flatMap((option) => option.items)]
|
||||
.flat()
|
||||
.find((item) => item!.value === value),
|
||||
[value, lists, circles],
|
||||
|
||||
@@ -12,7 +12,7 @@ const isCurrentOrFutureDate = (date: Date) =>
|
||||
date && new Date().setHours(0, 0, 0, 0) <= new Date(date).setHours(0, 0, 0, 0);
|
||||
|
||||
const isFiveMinutesFromNow = (selectedDate: Date) => {
|
||||
const fiveMinutesFromNow = new Date(new Date().getTime() + 1000 * 60 * 5);
|
||||
const fiveMinutesFromNow = new Date(Date.now() + 1000 * 60 * 5);
|
||||
|
||||
return fiveMinutesFromNow.getTime() < selectedDate.getTime();
|
||||
};
|
||||
@@ -50,7 +50,7 @@ const ScheduleForm: React.FC<IScheduleForm> = ({ composeId }) => {
|
||||
const isValidTime = useCallback(
|
||||
(date: Date) =>
|
||||
isFiveMinutesFromNow(date) ||
|
||||
(features.scheduledStatusesBackwards && new Date().getTime() > date.getTime()),
|
||||
(features.scheduledStatusesBackwards && Date.now() > date.getTime()),
|
||||
[features.scheduledStatusesBackwards],
|
||||
);
|
||||
|
||||
|
||||
@@ -57,7 +57,6 @@ const UploadButton: React.FC<IUploadButton> = ({ onSelectFile }) => {
|
||||
if (e.target.files?.length) {
|
||||
setDisabled(true);
|
||||
|
||||
// @ts-ignore
|
||||
dispatch(
|
||||
uploadFile(
|
||||
e.target.files.item(0) as File,
|
||||
|
||||
@@ -105,7 +105,7 @@ const StatePlugin: React.FC<IStatePlugin> = ({ composeId, isWysiwyg }) => {
|
||||
for (const tag of hashtagNodes) {
|
||||
const text = tag.getTextContent();
|
||||
|
||||
if (text.length > 10 && text.toLowerCase() === text && !text.match(/[0-9]/)) {
|
||||
if (text.length > 10 && text.toLowerCase() === text && !/[0-9]/.test(text)) {
|
||||
actions.updateCompose(composeId, (draft) => {
|
||||
draft.hashtagCasingSuggestion = text;
|
||||
});
|
||||
|
||||
@@ -24,7 +24,7 @@ const IMAGE_TRANSFORMER: TextMatchTransformer = {
|
||||
if ($isImageNode(node)) {
|
||||
const src = node.getSrc();
|
||||
const alt = node.getAltText();
|
||||
return `![${alt.replace(/([[\]])/g, '\\$1')}](${src})`;
|
||||
return `![${alt.replaceAll(/([[\]])/g, '\\$1')}](${src})`;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
@@ -5,6 +5,6 @@ const urlPlaceholder = 'xxxxxxxxxxxxxxxxxxxxxxx';
|
||||
const countableText = (inputText: string) =>
|
||||
inputText
|
||||
.replace(urlRegex, urlPlaceholder)
|
||||
.replace(/(^|[^/\w])@(([a-z0-9_]+)@[a-z0-9.-]+[a-z0-9]+)/gi, '$1@$3');
|
||||
.replaceAll(/(^|[^/\w])@(([a-z0-9_]+)@[a-z0-9.-]+[a-z0-9]+)/gi, '$1@$3');
|
||||
|
||||
export { countableText };
|
||||
|
||||
@@ -15,7 +15,7 @@ const regexSupplant = (regex: string | RegExp, flags = '') => {
|
||||
regex = regex.source;
|
||||
}
|
||||
return new RegExp(
|
||||
regex.replace(/#\{(\w+)\}/g, (match, name) => {
|
||||
regex.replaceAll(/#\{(\w+)\}/g, (match, name) => {
|
||||
let newRegex = regexen[name] || '';
|
||||
if (typeof newRegex !== 'string') {
|
||||
newRegex = newRegex.source;
|
||||
@@ -27,11 +27,11 @@ const regexSupplant = (regex: string | RegExp, flags = '') => {
|
||||
};
|
||||
|
||||
const stringSupplant = (str: string, values: { [x: string]: any }) =>
|
||||
str.replace(/#\{(\w+)\}/g, (match, name) => values[name] ?? '');
|
||||
str.replaceAll(/#\{(\w+)\}/g, (match, name) => values[name] ?? '');
|
||||
|
||||
const urlRegex = (() => {
|
||||
regexen.spaces_group =
|
||||
/\x09-\x0D\x20\x85\xA0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000/; // eslint-disable-line no-control-regex
|
||||
/\u0009-\u000D\u0020\u0085\u00A0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000/; // eslint-disable-line no-control-regex
|
||||
regexen.invalid_chars_group = /\uFFFE\uFEFF\uFFFF\u202A-\u202E/;
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
regexen.punct = /!'#%&@,:;<=>_~{}\$\?\^\*\+\-\.\(\)\[\]\|\/\\/;
|
||||
@@ -165,7 +165,7 @@ const urlRegex = (() => {
|
||||
);
|
||||
regexen.validPortNumber = /[0-9]+/;
|
||||
regexen.pd =
|
||||
/\u002d\u058a\u05be\u1400\u1806\u2010-\u2015\u2e17\u2e1a\u2e3a\u2e40\u301c\u3030\u30a0\ufe31\ufe58\ufe63\uff0d/;
|
||||
/\u002D\u058A\u05BE\u1400\u1806\u2010-\u2015\u2E17\u2E1A\u2E3A\u2E40\u301C\u3030\u30A0\uFE31\uFE58\uFE63\uFF0D/;
|
||||
regexen.validGeneralUrlPathChars = regexSupplant(/[^#{spaces_group}()?]/i);
|
||||
// Allow URL paths to contain up to two nested levels of balanced parens
|
||||
// 1. Used in Wikipedia URLs like /Primer_(film)
|
||||
|
||||
@@ -21,7 +21,7 @@ const buildStatus = (account: Account, draftStatus: DraftStatus) => {
|
||||
const status = v.parse(statusSchema, {
|
||||
id: 'draft',
|
||||
account,
|
||||
content: draftStatus.text.replace(
|
||||
content: draftStatus.text.replaceAll(
|
||||
new RegExp('\n', 'g'),
|
||||
'<br>',
|
||||
) /* eslint-disable-line no-control-regex */,
|
||||
|
||||
@@ -10,7 +10,7 @@ import('./data')
|
||||
.then((data) => {
|
||||
emojis = data.emojis;
|
||||
|
||||
const sortedEmojis = Object.entries(emojis).sort((a, b) => a[0].localeCompare(b[0]));
|
||||
const sortedEmojis = Object.entries(emojis).toSorted((a, b) => a[0].localeCompare(b[0]));
|
||||
for (const [key, emoji] of sortedEmojis) {
|
||||
index.add('n' + key, `${emoji.id} ${emoji.name} ${emoji.keywords.join(' ')}`);
|
||||
}
|
||||
@@ -29,7 +29,7 @@ interface searchOptions {
|
||||
}
|
||||
|
||||
const addCustomToPool = (customEmojis: any[]) => {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
for (const key in index.register) {
|
||||
if (key[0] === 'c') {
|
||||
index.remove(key); // remove old custom emojis
|
||||
|
||||
@@ -279,7 +279,7 @@ const getNotificationStatus = (
|
||||
'quoted_update',
|
||||
].includes(n.type)
|
||||
)
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
return n.status;
|
||||
return null;
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ const IconPickerMenu: React.FC<IIconPickerMenu> = ({ icons, onPick }) => {
|
||||
useEffect(() => {
|
||||
const firstButton = containerNode.current?.querySelector('button') as HTMLButtonElement;
|
||||
firstButton?.focus();
|
||||
}, [containerNode.current]);
|
||||
}, []);
|
||||
|
||||
const handleClick = (icon: string) => {
|
||||
onPick(icon);
|
||||
|
||||
@@ -413,7 +413,7 @@ const Preferences = () => {
|
||||
<a
|
||||
className='underline'
|
||||
href='https://hosted.weblate.org/projects/pl-fe/pl-fe/'
|
||||
rel='noopener'
|
||||
rel='noopener noreferrer'
|
||||
target='_blank'
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -15,7 +15,7 @@ const buildStatus = (account: Account, scheduledStatus: ScheduledStatus) => {
|
||||
|
||||
const status = v.parse(statusSchema, {
|
||||
account,
|
||||
content: scheduledStatus.params.text?.replace(
|
||||
content: scheduledStatus.params.text?.replaceAll(
|
||||
new RegExp('\n', 'g'),
|
||||
'<br>',
|
||||
) /* eslint-disable-line no-control-regex */,
|
||||
|
||||
@@ -137,7 +137,7 @@ const DetailedStatus: React.FC<IDetailedStatus> = ({
|
||||
<a
|
||||
href={actualStatus.url}
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
rel='noopener noreferrer'
|
||||
className='hover:underline'
|
||||
>
|
||||
<FormattedDate
|
||||
@@ -157,7 +157,7 @@ const DetailedStatus: React.FC<IDetailedStatus> = ({
|
||||
<a
|
||||
href={actualStatus.application.website ?? '#'}
|
||||
target='_blank'
|
||||
rel='noopener'
|
||||
rel='noopener noreferrer'
|
||||
className='hover:underline'
|
||||
title={intl.formatMessage(messages.applicationName, {
|
||||
name: actualStatus.application.name,
|
||||
@@ -171,11 +171,9 @@ const DetailedStatus: React.FC<IDetailedStatus> = ({
|
||||
{actualStatus.edited_at && (
|
||||
<>
|
||||
<span className='⁂-separator' />
|
||||
<div
|
||||
<button
|
||||
className='inline hover:underline'
|
||||
onClick={handleOpenCompareHistoryModal}
|
||||
role='button'
|
||||
tabIndex={0}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='status.edited'
|
||||
@@ -190,7 +188,7 @@ const DetailedStatus: React.FC<IDetailedStatus> = ({
|
||||
}),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</HStack>
|
||||
|
||||
@@ -60,7 +60,6 @@ const ThreadStatus: React.FC<IThreadStatus> = (props): React.JSX.Element => {
|
||||
>
|
||||
{renderConnector()}
|
||||
{isLoaded ? (
|
||||
// @ts-ignore FIXME
|
||||
<StatusContainer {...props} showGroup={false} />
|
||||
) : (
|
||||
<PlaceholderStatus variant='default' />
|
||||
|
||||
@@ -29,7 +29,7 @@ const Palette: React.FC<IPalette> = ({
|
||||
resetKey,
|
||||
allowTintChange = true,
|
||||
}) => {
|
||||
const tints = Object.keys(palette).sort(compareId);
|
||||
const tints = Object.keys(palette).toSorted(compareId);
|
||||
|
||||
const [hue, setHue] = useState(0);
|
||||
const lastHue = usePrevious(hue);
|
||||
|
||||
@@ -217,7 +217,7 @@ function useHotkeys<T extends HTMLElement>(handlers: HandlerMap) {
|
||||
});
|
||||
|
||||
// Sort all matches by priority
|
||||
matchCandidates.sort((a, b) => b.priority - a.priority);
|
||||
matchCandidates.toSorted((a, b) => b.priority - a.priority);
|
||||
|
||||
const bestMatchingHandler = matchCandidates.at(0)?.handler;
|
||||
if (bestMatchingHandler) {
|
||||
|
||||
@@ -25,7 +25,7 @@ const LinkFooter: React.FC = (): React.JSX.Element => {
|
||||
values={{
|
||||
code_name: sourceCode.displayName,
|
||||
code_link: (
|
||||
<a href={sourceCode.url} rel='noopener' target='_blank'>
|
||||
<a href={sourceCode.url} rel='noopener noreferrer' target='_blank'>
|
||||
{sourceCode.repository}
|
||||
</a>
|
||||
),
|
||||
|
||||
@@ -25,10 +25,10 @@ const ProfileMediaPanel: React.FC<IProfileMediaPanel> = ({ account }) => {
|
||||
const children = useMemo(() => {
|
||||
if (isLoading || !account) return <Spinner />;
|
||||
|
||||
const publicVisibilities = ['public', 'unlisted'];
|
||||
const publicVisibilities = new Set(['public', 'unlisted']);
|
||||
|
||||
const publicAttachments = attachments
|
||||
.filter((attachment) => publicVisibilities.includes(attachment.visibility))
|
||||
.filter((attachment) => publicVisibilities.has(attachment.visibility))
|
||||
.slice(0, 9);
|
||||
|
||||
if (publicAttachments.length) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import PollPreview from './poll-preview';
|
||||
import type { Status as StatusEntity } from '@/normalizers/status';
|
||||
|
||||
const shouldHaveCard = (pendingStatus: StatusEntity) =>
|
||||
Boolean(pendingStatus.content.match(/https?:\/\/\S*/));
|
||||
Boolean(/https?:\/\/\S*/.test(pendingStatus.content));
|
||||
|
||||
interface IPendingStatus {
|
||||
className?: string;
|
||||
|
||||
@@ -44,8 +44,8 @@ const ProfileDropdown: React.FC<IProfileDropdown> = ({ account, children }) => {
|
||||
dispatch(logOut());
|
||||
};
|
||||
|
||||
const handleSwitchAccount = (account: AccountEntity) => () => {
|
||||
dispatch(switchAccount(account.id));
|
||||
const handleSwitchAccount = (otherAccount: AccountEntity) => () => {
|
||||
dispatch(switchAccount(otherAccount.id));
|
||||
};
|
||||
|
||||
const renderAccount = (account: AccountEntity) => (
|
||||
|
||||
@@ -5,7 +5,7 @@ const isFullscreen = (): boolean =>
|
||||
Boolean(
|
||||
// eslint-disable-next-line compat/compat
|
||||
document.fullscreenElement ??
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
document.webkitFullscreenElement,
|
||||
);
|
||||
|
||||
@@ -13,7 +13,7 @@ const exitFullscreen = (): void => {
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen();
|
||||
} else if ('webkitExitFullscreen' in document) {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
document.webkitExitFullscreen();
|
||||
}
|
||||
};
|
||||
@@ -22,7 +22,7 @@ const requestFullscreen = (el: Element): void => {
|
||||
if (el.requestFullscreen) {
|
||||
el.requestFullscreen();
|
||||
} else if ('webkitRequestFullscreen' in el) {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
el.webkitRequestFullscreen();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -18,7 +18,7 @@ const buildMentions = (pendingStatus: PendingStatus) => {
|
||||
const buildPoll = (pendingStatus: PendingStatus) => {
|
||||
if (pendingStatus.poll?.options) {
|
||||
return create(pendingStatus.poll, (draft) => {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
draft.options = draft.options.map((title) => ({ title }));
|
||||
});
|
||||
} else {
|
||||
@@ -36,10 +36,7 @@ const buildStatus = (
|
||||
|
||||
const status = {
|
||||
account,
|
||||
content: pendingStatus.status.replace(
|
||||
new RegExp('\n', 'g'),
|
||||
'<br>',
|
||||
) /* eslint-disable-line no-control-regex */,
|
||||
content: pendingStatus.status.replaceAll('\n', '<br>'),
|
||||
id: `末pending-${idempotencyKey}`,
|
||||
in_reply_to_account_id: state.statuses[inReplyToId ?? '']?.account_id || null,
|
||||
in_reply_to_id: inReplyToId,
|
||||
|
||||
@@ -166,14 +166,14 @@ const Video: React.FC<IVideo> = ({
|
||||
|
||||
useLayoutEffect(() => {
|
||||
setDimensions();
|
||||
}, [player.current]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (video.current) {
|
||||
setVolume(video.current.volume);
|
||||
setMuted(video.current.muted);
|
||||
}
|
||||
}, [video.current]);
|
||||
}, []);
|
||||
|
||||
const handleClickRoot: React.MouseEventHandler = (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
@@ -2,7 +2,7 @@ import messages from '@/messages';
|
||||
import { useSettings } from '@/stores/settings';
|
||||
|
||||
/** Locales which should be presented in right-to-left. */
|
||||
const RTL_LOCALES = ['ar', 'ckb', 'fa', 'he'];
|
||||
const RTL_LOCALES = new Set(['ar', 'ckb', 'fa', 'he']);
|
||||
|
||||
/** Get valid locale from settings. */
|
||||
const useLocale = (fallback = 'en') => {
|
||||
@@ -15,6 +15,6 @@ const useLocale = (fallback = 'en') => {
|
||||
: fallback;
|
||||
};
|
||||
|
||||
const useLocaleDirection = (locale = 'en') => (RTL_LOCALES.includes(locale) ? 'rtl' : 'ltr');
|
||||
const useLocaleDirection = (locale = 'en') => (RTL_LOCALES.has(locale) ? 'rtl' : 'ltr');
|
||||
|
||||
export { useLocale, useLocaleDirection };
|
||||
|
||||
@@ -56,14 +56,14 @@ const normalizeColors = (
|
||||
const normalizedColors = toTailwind({
|
||||
brandColor,
|
||||
accentColor,
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
colors,
|
||||
});
|
||||
|
||||
return {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
'gradient-start': normalizedColors.primary?.['500'],
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
'gradient-end': normalizedColors.accent?.['500'],
|
||||
...normalizedColors,
|
||||
} as typeof normalizedColors;
|
||||
|
||||
@@ -19,7 +19,7 @@ import { useCompose, useComposeActions } from '@/stores/compose';
|
||||
import type { BaseModalProps } from '@/features/ui/components/modal-root';
|
||||
import type { CreateStatusParams, InteractionPolicy } from 'pl-api';
|
||||
|
||||
const MANAGABLE_VISIBILITIES = ['public', 'unlisted', 'private'];
|
||||
const MANAGABLE_VISIBILITIES = new Set(['public', 'unlisted', 'private']);
|
||||
|
||||
interface ComposeInteractionPolicyModalProps {
|
||||
composeId: string;
|
||||
@@ -35,7 +35,7 @@ const ComposeInteractionPolicyModal: React.FC<
|
||||
const { interactionPolicies: initial } = useInteractionPolicies();
|
||||
const compose = useCompose(composeId);
|
||||
|
||||
const canManageInteractionPolicies = MANAGABLE_VISIBILITIES.includes(compose.visibility);
|
||||
const canManageInteractionPolicies = MANAGABLE_VISIBILITIES.has(compose.visibility);
|
||||
|
||||
useEffect(() => {
|
||||
if (!canManageInteractionPolicies) {
|
||||
|
||||
@@ -85,15 +85,13 @@ const ReactionsModal: React.FC<BaseModalProps & ReactionsModalProps> = ({
|
||||
reactionUrl: reactionRecord.url ?? undefined,
|
||||
}));
|
||||
} else {
|
||||
return reactions
|
||||
.map(({ account_ids, name, url }) =>
|
||||
account_ids.map((account) => ({
|
||||
id: account,
|
||||
reaction: name,
|
||||
reactionUrl: url ?? undefined,
|
||||
})),
|
||||
)
|
||||
.flat();
|
||||
return reactions.flatMap(({ account_ids, name, url }) =>
|
||||
account_ids.map((account) => ({
|
||||
id: account,
|
||||
reaction: name,
|
||||
reactionUrl: url ?? undefined,
|
||||
})),
|
||||
);
|
||||
}
|
||||
}, [reactions, reaction]);
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ const ReasonStep: React.FC<IReasonStep> = ({ comment, setComment, ruleIds, setRu
|
||||
setNearBottom(true);
|
||||
}
|
||||
}
|
||||
}, [rules, rulesListRef.current]);
|
||||
}, [rules]);
|
||||
|
||||
return (
|
||||
<Stack space={4}>
|
||||
|
||||
@@ -11,9 +11,9 @@ const normalizeNotification = (notification: BaseNotification): NotificationGrou
|
||||
page_max_id: notification.id,
|
||||
latest_page_notification_at: notification.created_at,
|
||||
sample_account_ids: [notification.account.id],
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
status_id: notification.status?.id,
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
target_id: notification.target?.id,
|
||||
});
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ const getOrderedLists = (lists: Array<Pick<ListEntity, 'title'>>) => {
|
||||
|
||||
return Object.values(lists)
|
||||
.filter((item): item is ListEntity => !!item)
|
||||
.sort((a, b) => a.title.localeCompare(b.title));
|
||||
.toSorted((a, b) => a.title.localeCompare(b.title));
|
||||
};
|
||||
|
||||
const NewListForm: React.FC = () => {
|
||||
|
||||
@@ -43,10 +43,10 @@ const Dashboard: React.FC = () => {
|
||||
|
||||
const [today] = useState<string>(new Date().toISOString().slice(0, 10));
|
||||
const [monthAgo] = useState<string>(
|
||||
new Date(new Date().getTime() - 30 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10),
|
||||
new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10),
|
||||
);
|
||||
const [sixMonthsAgo] = useState<string>(
|
||||
new Date(new Date().getTime() - 30 * 6 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10),
|
||||
new Date(Date.now() - 30 * 6 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10),
|
||||
);
|
||||
|
||||
if (!account) return null;
|
||||
|
||||
@@ -177,7 +177,7 @@ const FrontendConfigEditor: React.FC = () => {
|
||||
if (path[0] === 'cryptoAddresses') {
|
||||
draft.cryptoAddresses = values;
|
||||
} else {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
draft[path[0]][path[1]] = values;
|
||||
}
|
||||
});
|
||||
@@ -191,7 +191,7 @@ const FrontendConfigEditor: React.FC = () => {
|
||||
if (path[0] === 'cryptoAddresses') {
|
||||
draft.cryptoAddresses.push(v.parse(cryptoAddressSchema, {}));
|
||||
} else {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
draft[path[0]][path[1]].push(v.parse(schema, {}));
|
||||
}
|
||||
});
|
||||
@@ -203,7 +203,7 @@ const FrontendConfigEditor: React.FC = () => {
|
||||
if (path[0] === 'cryptoAddresses') {
|
||||
draft.cryptoAddresses = draft.cryptoAddresses.filter((_, index) => index !== i);
|
||||
} else {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
draft[path[0]][path[1]] = draft[path[0]][path[1]].filter((_, index) => index !== i);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -79,8 +79,8 @@ const ReportStatuses: React.FC<IReportStatuses> = ({ statusIds }) => {
|
||||
)}
|
||||
<ReactSwipeableViews animateHeight index={index} onChangeIndex={handleChangeIndex}>
|
||||
{statusIds.map((statusId) => (
|
||||
<div className='w-full'>
|
||||
<StatusContainer key={statusId} id={statusId} />
|
||||
<div className='w-full' key={statusId}>
|
||||
<StatusContainer id={statusId} />
|
||||
</div>
|
||||
))}
|
||||
</ReactSwipeableViews>
|
||||
|
||||
@@ -67,6 +67,7 @@ const Reports: React.FC = () => {
|
||||
value={[
|
||||
account && (
|
||||
<FormattedMessage
|
||||
key='account'
|
||||
id='column.admin.reports.filter_message.account'
|
||||
defaultMessage='from @{acct}'
|
||||
values={{
|
||||
@@ -76,6 +77,7 @@ const Reports: React.FC = () => {
|
||||
),
|
||||
targetAccount && (
|
||||
<FormattedMessage
|
||||
key='targetAccount'
|
||||
id='column.admin.reports.filter_message.target_account'
|
||||
defaultMessage='targeting @{acct}'
|
||||
values={{
|
||||
|
||||
@@ -69,7 +69,7 @@ const AuthToken: React.FC<IAuthToken> = ({ token, isCurrent }) => {
|
||||
<HStack space={1} alignItems='center'>
|
||||
{token.app_name}
|
||||
{token.app_website && (
|
||||
<a href={token.app_website} target='_blank' rel='noopener'>
|
||||
<a href={token.app_website} target='_blank' rel='noopener noreferrer'>
|
||||
<Icon
|
||||
src={require('@phosphor-icons/core/regular/arrow-square-out.svg')}
|
||||
className='inline size-4 text-inherit'
|
||||
|
||||
@@ -296,15 +296,15 @@ const InteractionRequestsPage = () => {
|
||||
|
||||
const handleMoveUp = (id: string) => {
|
||||
const elementIndex = data.findIndex((item) => item !== null && item.id === id) - 1;
|
||||
_selectChild(elementIndex);
|
||||
selectChild(elementIndex);
|
||||
};
|
||||
|
||||
const handleMoveDown = (id: string) => {
|
||||
const elementIndex = data.findIndex((item) => item !== null && item.id === id) + 1;
|
||||
_selectChild(elementIndex);
|
||||
selectChild(elementIndex);
|
||||
};
|
||||
|
||||
const _selectChild = (index: number) => {
|
||||
const selectChild = (index: number) => {
|
||||
const selector = `[data-index="${index}"] .focusable`;
|
||||
const element = document.querySelector<HTMLDivElement>(selector);
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ const About: React.FC<IAbout> = ({ slug }) => {
|
||||
setLocale(defaultLocale);
|
||||
}}
|
||||
>
|
||||
{/* @ts-ignore */}
|
||||
{/* @ts-expect-error */}
|
||||
{languages[defaultLocale] ?? defaultLocale}
|
||||
</a>
|
||||
</li>
|
||||
@@ -51,7 +51,7 @@ const About: React.FC<IAbout> = ({ slug }) => {
|
||||
setLocale(locale);
|
||||
}}
|
||||
>
|
||||
{/* @ts-ignore */}
|
||||
{/* @ts-expect-error */}
|
||||
{languages[locale] ?? locale}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -21,7 +21,7 @@ const useFamiliarFollowers = (accountId: string) => {
|
||||
for (const account of accounts) {
|
||||
queryClient.setQueryData(['accounts', account.id], account);
|
||||
}
|
||||
accounts.map(({ id }) => id);
|
||||
return accounts.map(({ id }) => id);
|
||||
}),
|
||||
enabled: isLoggedIn && features.familiarFollowers,
|
||||
});
|
||||
|
||||
@@ -38,12 +38,10 @@ const makeUseFollowRequests = <T>(select: (data: InfiniteData<PaginatedResponse<
|
||||
'isLoggedIn',
|
||||
);
|
||||
|
||||
const useFollowRequests = makeUseFollowRequests((data) =>
|
||||
data.pages.map((page) => page.items).flat(),
|
||||
);
|
||||
const useFollowRequests = makeUseFollowRequests((data) => data.pages.flatMap((page) => page.items));
|
||||
|
||||
const useFollowRequestsCount = makeUseFollowRequests(
|
||||
(data) => data.pages.map((page) => page.items).flat().length,
|
||||
(data) => data.pages.flatMap((page) => page.items).length,
|
||||
);
|
||||
|
||||
const useOutgoingFollowRequests = makePaginatedResponseQuery(
|
||||
|
||||
@@ -70,7 +70,7 @@ const usePendingUsersCount = () => {
|
||||
return useInfiniteQuery({
|
||||
...pendingUsersQuery,
|
||||
select: (data) =>
|
||||
(data.pages.at(-1)?.total ?? data.pages.map((page) => page.items).flat().length) || 0,
|
||||
(data.pages.at(-1)?.total ?? data.pages.flatMap((page) => page.items).length) || 0,
|
||||
enabled: !!(account?.is_admin ?? account?.is_moderator),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ const usePendingReportsCount = () => {
|
||||
return useInfiniteQuery({
|
||||
...pendingReportsQuery,
|
||||
select: (data) =>
|
||||
(data.pages.at(-1)?.total ?? data.pages.map((page) => page.items).flat().length) || 0,
|
||||
(data.pages.at(-1)?.total ?? data.pages.flatMap((page) => page.items).length) || 0,
|
||||
enabled: !!instance.fetched && !!(account?.is_admin ?? account?.is_moderator),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -108,7 +108,7 @@ const useAnnouncements = () => {
|
||||
});
|
||||
|
||||
return {
|
||||
data: data ? [...data].sort(compareAnnouncements) : undefined,
|
||||
data: data?.toSorted(compareAnnouncements),
|
||||
...result,
|
||||
addReaction,
|
||||
removeReaction,
|
||||
|
||||
@@ -190,7 +190,7 @@ const useCreateChatMessage = (chatId: string) => {
|
||||
// Snapshot the previous value
|
||||
const prevContent = variables.content;
|
||||
const prevChatMessages = queryClient.getQueryData(['chats', 'messages', variables.chatId]);
|
||||
const pendingId = String(Number(new Date()));
|
||||
const pendingId = String(Date.now());
|
||||
|
||||
// Optimistically update to the new value
|
||||
queryClient.setQueryData(ChatKeys.chatMessages(variables.chatId), (prevResult: any) => {
|
||||
|
||||
@@ -14,7 +14,7 @@ const scheduledStatusesQueryOptions = makePaginatedResponseQueryOptions(
|
||||
|
||||
const scheduledStatusesCountQueryOptions = infiniteQueryOptions({
|
||||
...scheduledStatusesQueryOptions,
|
||||
select: (data) => data.pages.map((page) => page.items).flat().length,
|
||||
select: (data) => data.pages.flatMap((page) => page.items).length,
|
||||
});
|
||||
|
||||
const cancelScheduledStatusMutationOptions = (scheduledStatusId: string) =>
|
||||
|
||||
@@ -29,7 +29,7 @@ const minifyInteractionRequestsList = (
|
||||
): PaginatedResponse<MinifiedInteractionRequest> => {
|
||||
dispatch(
|
||||
importEntities({
|
||||
statuses: items.map((item) => [item.status, item.reply]).flat(),
|
||||
statuses: items.flatMap((item) => [item.status, item.reply]),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -74,11 +74,11 @@ const useInteractionRequests = <T>(
|
||||
|
||||
const useFlatInteractionRequests = () =>
|
||||
useInteractionRequests((data: InfiniteData<PaginatedResponse<MinifiedInteractionRequest>>) =>
|
||||
data.pages.map((page) => page.items).flat(),
|
||||
data.pages.flatMap((page) => page.items),
|
||||
);
|
||||
|
||||
const useInteractionRequestsCount = () =>
|
||||
useInteractionRequests((data) => data.pages.map(({ items }) => items).flat().length);
|
||||
useInteractionRequests((data) => data.pages.flatMap(({ items }) => items).length);
|
||||
|
||||
const useAuthorizeInteractionRequestMutation = (requestId: string) => {
|
||||
const client = useClient();
|
||||
|
||||
@@ -33,10 +33,10 @@ const getFilters = (state: Pick<RootState, 'filters'>, query: FilterContext) =>
|
||||
state.filters.filter(
|
||||
(filter) =>
|
||||
(!query?.contextType || filter.context.includes(toServerSideType(query.contextType))) &&
|
||||
(filter.expires_at === null || Date.parse(filter.expires_at) > new Date().getTime()),
|
||||
(filter.expires_at === null || Date.parse(filter.expires_at) > Date.now()),
|
||||
);
|
||||
|
||||
const escapeRegExp = (string: string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
||||
const escapeRegExp = (string: string) => string.replaceAll(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
||||
|
||||
const regexFromFilters = (filters: Array<Filter>) => {
|
||||
if (filters.length === 0) return null;
|
||||
|
||||
@@ -154,9 +154,9 @@ const formatMessage = (messageId: string, locale: string, values = {}): string =
|
||||
const htmlToPlainText = (html: string): string =>
|
||||
unescape(
|
||||
html
|
||||
.replace(/<br\s*\/?>/g, '\n')
|
||||
.replace(/<\/p><[^>]*>/g, '\n\n')
|
||||
.replace(/<[^>]*>/g, ''),
|
||||
.replaceAll(/<br\s*\/?>/g, '\n')
|
||||
.replaceAll(/<\/p><[^>]*>/g, '\n\n')
|
||||
.replaceAll(/<[^>]*>/g, ''),
|
||||
);
|
||||
|
||||
/** ServiceWorker `push` event callback. */
|
||||
@@ -218,7 +218,7 @@ const handlePush = (event: PushEvent) => {
|
||||
body,
|
||||
icon,
|
||||
tag: notification_id,
|
||||
timestamp: Number(new Date()),
|
||||
timestamp: Date.now(),
|
||||
data: { access_token, preferred_locale, url: '/notifications' },
|
||||
}),
|
||||
),
|
||||
|
||||
@@ -6,7 +6,7 @@ const filtered = compileTime(() => {
|
||||
const filenames = fs.readdirSync(path.resolve(__dirname, '../locales'));
|
||||
|
||||
filenames.forEach((filename) => {
|
||||
if (!filename.match(/\.json$/) || filename.match(/defaultMessages|whitelist/)) return;
|
||||
if (!filename.endsWith('.json') || filename.match(/defaultMessages|whitelist/)) return;
|
||||
|
||||
const content = fs.readFileSync(path.resolve(__dirname, `../locales/${filename}`), 'utf-8');
|
||||
const full = JSON.parse(content) as Record<string, string>;
|
||||
|
||||
@@ -723,10 +723,10 @@ const useSubmitCompose = (composeId: string) => {
|
||||
if (!preview) {
|
||||
const scheduledAt = compose.scheduledAt;
|
||||
if (scheduledAt) {
|
||||
const fiveMinutesFromNow = new Date(new Date().getTime() + 300000);
|
||||
const fiveMinutesFromNow = new Date(Date.now() + 300000);
|
||||
const valid =
|
||||
scheduledAt.getTime() > fiveMinutesFromNow.getTime() ||
|
||||
(features.scheduledStatusesBackwards && scheduledAt.getTime() < new Date().getTime());
|
||||
(features.scheduledStatusesBackwards && scheduledAt.getTime() < Date.now());
|
||||
if (!valid) {
|
||||
toast.error(messages.scheduleError);
|
||||
return;
|
||||
@@ -760,12 +760,7 @@ const useSubmitCompose = (composeId: string) => {
|
||||
to = [
|
||||
...new Set([
|
||||
...to,
|
||||
...mentionsMatch.map((mention) =>
|
||||
mention
|
||||
.replace(/ /g, '')
|
||||
.trim()
|
||||
.slice(1),
|
||||
),
|
||||
...mentionsMatch.map((mention) => mention.replaceAll(' ', '').trim().slice(1)),
|
||||
]),
|
||||
];
|
||||
}
|
||||
@@ -808,7 +803,7 @@ const useSubmitCompose = (composeId: string) => {
|
||||
};
|
||||
|
||||
if (compose.editedId) {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
params.media_attributes = media.map((item) => {
|
||||
const focalPoint = (item.type === 'image' || item.type === 'gifv') && item.meta?.focus;
|
||||
const focus = focalPoint
|
||||
@@ -860,7 +855,7 @@ const useSubmitCompose = (composeId: string) => {
|
||||
} catch {}
|
||||
} else {
|
||||
if (compose.redacting) {
|
||||
// @ts-ignore
|
||||
// @ts-expect-error
|
||||
params.overwrite = compose.redactingOverwrite;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ import { selectAccount, selectOwnAccount } from '@/queries/accounts/selectors';
|
||||
|
||||
import type { RootState } from '@/store';
|
||||
|
||||
const validId = (id: any) => typeof id === 'string' && id !== 'null' && id !== 'undefined';
|
||||
const validId = (id?: string | null | false) =>
|
||||
typeof id === 'string' && id !== 'null' && id !== 'undefined';
|
||||
|
||||
const isURL = (url?: string | null) => {
|
||||
if (typeof url !== 'string') return false;
|
||||
@@ -14,7 +15,8 @@ const isURL = (url?: string | null) => {
|
||||
}
|
||||
};
|
||||
|
||||
const parseBaseURL = (url: any) => {
|
||||
const parseBaseURL = (url?: string) => {
|
||||
if (typeof url !== 'string') return '';
|
||||
try {
|
||||
return new URL(url).origin;
|
||||
} catch {
|
||||
|
||||
@@ -5,8 +5,8 @@ import pkg from '../../package.json';
|
||||
const code = compileTime(() => {
|
||||
const { CI_COMMIT_TAG, CI_COMMIT_REF_NAME, CI_COMMIT_SHA } = process.env;
|
||||
|
||||
const shortRepoName = (url: string): string => new URL(url).pathname.substring(1);
|
||||
const trimHash = (hash: string): string => hash.substring(0, 7);
|
||||
const shortRepoName = (url: string): string => new URL(url).pathname.slice(1);
|
||||
const trimHash = (hash: string): string => hash.slice(0, 7);
|
||||
|
||||
const tryGit = (cmd: string): string | undefined => {
|
||||
try {
|
||||
|
||||
@@ -28,7 +28,7 @@ SOFTWARE.
|
||||
import type { Rgb, TailwindColorObject } from '@/types/colors';
|
||||
|
||||
const hexToRgb = (hex: string): Rgb | null => {
|
||||
const sanitizedHex = hex.replace(/##/g, '#');
|
||||
const sanitizedHex = hex.replaceAll('##', '#');
|
||||
const colorParts = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(sanitizedHex);
|
||||
|
||||
if (!colorParts) {
|
||||
@@ -79,7 +79,7 @@ const darken = (hex: string, intensity: number): string => {
|
||||
|
||||
const colors = (baseColor: string): TailwindColorObject => {
|
||||
const response: TailwindColorObject = {
|
||||
500: `#${baseColor}`.replace(/##/g, '#'),
|
||||
500: `#${baseColor}`.replaceAll('##', '#'),
|
||||
};
|
||||
|
||||
const intensityMap: {
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
const unescapeHTML = (html: string = ''): string => {
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.innerHTML = html
|
||||
.replace(/<br\s*\/?>/g, '\n')
|
||||
.replace(/<\/p><[^>]*>/g, '\n\n')
|
||||
.replace(/<[^>]*>/g, '');
|
||||
.replaceAll(/<br\s*\/?>/g, '\n')
|
||||
.replaceAll(/<\/p><[^>]*>/g, '\n\n')
|
||||
.replaceAll(/<[^>]*>/g, '');
|
||||
return wrapper.textContent || '';
|
||||
};
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ const truncateFilename = (url: string, maxLength: number) => {
|
||||
|
||||
if (filename.length <= maxLength) return filename;
|
||||
|
||||
return [filename.substr(0, maxLength / 2), filename.substr(filename.length - maxLength / 2)].join(
|
||||
return [filename.slice(0, maxLength / 2), filename.slice(filename.length - maxLength / 2)].join(
|
||||
'…',
|
||||
);
|
||||
};
|
||||
@@ -16,7 +16,7 @@ const formatBytes = (bytes: number, decimals: number = 2) => {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
|
||||
const k = 1024;
|
||||
const dm = decimals < 0 ? 0 : decimals;
|
||||
const dm = Math.max(0, decimals);
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
@@ -9,7 +9,7 @@ const ifAfter = (prefix: string, fn: (x: string) => string) => {
|
||||
const preLen = prefix.length;
|
||||
const regex = new RegExp(prefix, 'i');
|
||||
return (x: string, pos: number, string: string) => {
|
||||
return pos > 0 && string.substring(pos - preLen, pos).match(regex) ? fn(x) : x;
|
||||
return pos > 0 && string.slice(pos - preLen, pos).match(regex) ? fn(x) : x;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -20,26 +20,26 @@ const nyaize = (text: string) =>
|
||||
.replaceAll('ナ', 'ニャ')
|
||||
.replaceAll('ナ', 'ニャ')
|
||||
// en-US
|
||||
.replace(
|
||||
/a/gi,
|
||||
.replaceAll(
|
||||
'a',
|
||||
ifAfter('n', (x) => (x === 'A' ? 'YA' : 'ya')),
|
||||
)
|
||||
.replace(
|
||||
/ing/gi,
|
||||
.replaceAll(
|
||||
'ing',
|
||||
ifAfter('morn', (x) => (x === 'ING' ? 'YAN' : 'yan')),
|
||||
)
|
||||
.replace(
|
||||
/one/gi,
|
||||
.replaceAll(
|
||||
'one',
|
||||
ifAfter('every', (x) => (x === 'ONE' ? 'NYAN' : 'nyan')),
|
||||
)
|
||||
// pl-PL
|
||||
.replace(
|
||||
/ł/gi,
|
||||
.replaceAll(
|
||||
'ł',
|
||||
ifAfter('mia', (x) => (x === 'Ł' ? 'U' : 'u')),
|
||||
)
|
||||
// ru-RU
|
||||
.replace(
|
||||
/а/gi,
|
||||
.replaceAll(
|
||||
'а',
|
||||
ifAfter('н', (x) => (x === 'А' ? 'Я' : 'я')),
|
||||
)
|
||||
// ko-KR
|
||||
|
||||
@@ -95,7 +95,7 @@ const sortQueryData = <T>(queryKey: QueryKey, comparator: (a: T, b: T) => number
|
||||
if (prevResult) {
|
||||
const nextResult = { ...prevResult };
|
||||
const flattenedQueryData = flattenPages(nextResult);
|
||||
const sortedQueryData = flattenedQueryData?.sort(comparator);
|
||||
const sortedQueryData = flattenedQueryData?.toSorted(comparator);
|
||||
const paginatedPages = paginateQueryData(sortedQueryData);
|
||||
const newPages = paginatedPages.map((page: T, idx: number) => ({
|
||||
...prevResult.pages[idx],
|
||||
|
||||
@@ -51,7 +51,7 @@ const dropOrientationIfNeeded = (orientation: number) =>
|
||||
/** Convert the file into a local blob URL. */
|
||||
const getImageUrl = (inputFile: File) =>
|
||||
new Promise<string>((resolve, reject) => {
|
||||
// @ts-ignore: This is a browser capabilities check.
|
||||
// @ts-expect-error: This is a browser capabilities check.
|
||||
if (window.URL?.createObjectURL) {
|
||||
try {
|
||||
resolve(URL.createObjectURL(inputFile));
|
||||
@@ -177,7 +177,7 @@ const processImage = (
|
||||
reject(blob);
|
||||
return;
|
||||
}
|
||||
resolve(new File([blob], name, { type, lastModified: new Date().getTime() }));
|
||||
resolve(new File([blob], name, { type, lastModified: Date.now() }));
|
||||
}, type);
|
||||
});
|
||||
|
||||
@@ -214,7 +214,7 @@ const resize = async (
|
||||
): Promise<File> => {
|
||||
if (!hasCanvasExtractPermission) return inputFile;
|
||||
|
||||
if (!inputFile.type.match(/image.*/) || inputFile.type === 'image/gif') {
|
||||
if (!/image.*/.test(inputFile.type) || inputFile.type === 'image/gif') {
|
||||
return inputFile;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ const onlyEmoji = (node: HTMLElement, limit = 1, ignoreMentions = true): boolean
|
||||
node.querySelectorAll('a.mention').forEach((m) => m.parentNode?.removeChild(m));
|
||||
}
|
||||
|
||||
if (node.textContent?.replace(new RegExp(' ', 'g'), '') !== '') return false;
|
||||
if (node.textContent?.replaceAll(new RegExp(' ', 'g'), '') !== '') return false;
|
||||
const emojis = Array.from(node.querySelectorAll('img.emojione'));
|
||||
if (emojis.length === 0) return false;
|
||||
if (emojis.length > limit) return false;
|
||||
|
||||
@@ -22,17 +22,17 @@ const isRtl = (text: string, confidence = 0.3): boolean => {
|
||||
}
|
||||
|
||||
// Remove http(s), (s)ftp, ws(s), blob and smtp(s) links
|
||||
text = text.replace(/(?:https?|ftp|sftp|ws|wss|blob|smtp|smtps):\/\/[\S]+/g, '');
|
||||
text = text.replaceAll(/(?:https?|ftp|sftp|ws|wss|blob|smtp|smtps):\/\/[\S]+/g, '');
|
||||
// Remove email address links
|
||||
text = text.replace(/(mailto:)([^\s@]+@[^\s@]+\.[^\s@]+)/g, '');
|
||||
text = text.replaceAll(/(mailto:)([^\s@]+@[^\s@]+\.[^\s@]+)/g, '');
|
||||
// Remove phone number links
|
||||
text = text.replace(/(tel:)([+\d\s()-]+)/g, '');
|
||||
text = text.replaceAll(/(tel:)([+\d\s()-]+)/g, '');
|
||||
// Remove mentions
|
||||
text = text.replace(/(?:^|[^/\w])@([a-z0-9_]+(@[a-z0-9.-]+)?)/gi, '');
|
||||
text = text.replaceAll(/(?:^|[^/\w])@([a-z0-9_]+(@[a-z0-9.-]+)?)/gi, '');
|
||||
// Remove hashtags
|
||||
text = text.replace(/(?:^|[^/\w])#([\S]+)/gi, '');
|
||||
text = text.replaceAll(/(?:^|[^/\w])#([\S]+)/gi, '');
|
||||
// Remove all non-word characters
|
||||
text = text.replace(/\s+/g, '');
|
||||
text = text.replaceAll(/\s+/g, '');
|
||||
|
||||
const matches = text.match(rtlChars);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ const rgbToHsl = (value: Rgb): Hsl => {
|
||||
const r = value.r / 255;
|
||||
const g = value.g / 255;
|
||||
const b = value.b / 255;
|
||||
const rgbOrdered = [r, g, b].sort();
|
||||
const rgbOrdered = [r, g, b].toSorted();
|
||||
const l = ((rgbOrdered[0] + rgbOrdered[2]) / 2) * 100;
|
||||
let s, h;
|
||||
if (rgbOrdered[0] === rgbOrdered[2]) {
|
||||
|
||||
@@ -160,7 +160,7 @@ const config = defineConfig(() => ({
|
||||
name: 'mock-api',
|
||||
configureServer(server) {
|
||||
server.middlewares.use((req, res, next) => {
|
||||
if (/^\/api\//.test(req.url!)) {
|
||||
if (req.url?.startsWith('/api')) {
|
||||
res.statusCode = 404;
|
||||
res.end('Not Found');
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user