mirror of
https://github.com/uetchy/namae.git
synced 2025-08-20 09:58:13 +09:00
chore: add eslint rules
This commit is contained in:
@@ -5,7 +5,7 @@ import {FaTwitter, FaGithubAlt} from 'react-icons/fa';
|
||||
|
||||
import {ExternalLink} from './Links';
|
||||
|
||||
export default function Footer() {
|
||||
const Footer: React.FC = () => {
|
||||
const {t} = useTranslation();
|
||||
|
||||
return (
|
||||
@@ -51,7 +51,8 @@ export default function Footer() {
|
||||
</Box>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
};
|
||||
export default Footer;
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
|
@@ -15,19 +15,19 @@ const Form: React.FC<{onQuery: (query: string) => void}> = ({onQuery}) => {
|
||||
const {t} = useTranslation();
|
||||
|
||||
// set input value
|
||||
function onInputChange(e: React.FormEvent<HTMLInputElement>) {
|
||||
function onInputChange(e: React.FormEvent<HTMLInputElement>): void {
|
||||
const value = e.currentTarget.value;
|
||||
setInputValue(value);
|
||||
}
|
||||
|
||||
// clear input form and focus on it
|
||||
function onLogoClick(e: React.MouseEvent<HTMLDivElement>) {
|
||||
function onLogoClick(): void {
|
||||
setInputValue('');
|
||||
inputRef.current!.focus();
|
||||
inputRef.current?.focus();
|
||||
}
|
||||
|
||||
// invoke when user clicked one of the suggested items
|
||||
function onSuggestionCompleted(name: string) {
|
||||
function onSuggestionCompleted(name: string): void {
|
||||
setInputValue(name);
|
||||
setSuggested(true);
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
export const SpectrumIcon = () => (
|
||||
export const SpectrumIcon: React.FC = () => (
|
||||
<svg
|
||||
width="1em"
|
||||
height="1em"
|
||||
@@ -13,7 +13,7 @@ export const SpectrumIcon = () => (
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const NowIcon = () => (
|
||||
export const NowIcon: React.FC = () => (
|
||||
<svg
|
||||
width="1em"
|
||||
height="1em"
|
||||
@@ -28,7 +28,7 @@ export const NowIcon = () => (
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const NetlifyIcon = () => (
|
||||
export const NetlifyIcon: React.FC = () => (
|
||||
<svg
|
||||
width="1em"
|
||||
height="1em"
|
||||
|
@@ -9,47 +9,47 @@ import {mobile} from '../util/css';
|
||||
|
||||
type Modifier = (word: string) => string;
|
||||
|
||||
const maximumCount = 3;
|
||||
const modifiers: Modifier[] = [
|
||||
(word) => `${capitalize(word)}ify`,
|
||||
(word) => `lib${lower(word)}`,
|
||||
(word) => `Omni${capitalize(word)}`,
|
||||
(word) => `${capitalize(word)}Lab`,
|
||||
(word) => `${capitalize(word)}Kit`,
|
||||
(word) => `Open${capitalize(word)}`,
|
||||
(word) => `${capitalize(word)}box`,
|
||||
(word) => `Insta${lower(word)}`,
|
||||
(word) => `${capitalize(word)}Hub`,
|
||||
(word) => `Cloud${capitalize(word)}`,
|
||||
(word) => `quick${lower(word)}`,
|
||||
(word) => `fast${lower(word)}`,
|
||||
(word) => `super-${lower(word)}`,
|
||||
(word) => `Hyper${capitalize(word)}`,
|
||||
(word) => `${capitalize(word)}Go`,
|
||||
(word) => `${lower(word)}-io`,
|
||||
(word) => `Go${capitalize(word)}`,
|
||||
(word) => `${capitalize(word)}X`,
|
||||
(word) => `${capitalize(word)}time`,
|
||||
(word) => `${capitalize(word)}flow`,
|
||||
(word) => `${capitalize(word)}ful`,
|
||||
(word) => `${capitalize(word)}ery`,
|
||||
(word) => `${lower(word)}ly`,
|
||||
(word) => `${lower(word)}joy`,
|
||||
(word) => `${capitalize(word)}Hunt`,
|
||||
(word) => `${capitalize(word)}gram`,
|
||||
(word) => `${capitalize(word)}base`,
|
||||
(word) => `${capitalize(word)}API`,
|
||||
(word) => `${capitalize(word)}note`,
|
||||
(word) => `In${capitalize(word)}`,
|
||||
(word) => `Uni${lower(word)}`,
|
||||
(word) => `${capitalize(word)}`,
|
||||
];
|
||||
|
||||
function lower(word: string) {
|
||||
function lower(word: string): string {
|
||||
return word.toLowerCase();
|
||||
}
|
||||
|
||||
function shuffleArray(array: any[]) {
|
||||
const maximumCount = 3;
|
||||
const modifiers: Modifier[] = [
|
||||
(word): string => `${capitalize(word)}ify`,
|
||||
(word): string => `lib${lower(word)}`,
|
||||
(word): string => `Omni${capitalize(word)}`,
|
||||
(word): string => `${capitalize(word)}Lab`,
|
||||
(word): string => `${capitalize(word)}Kit`,
|
||||
(word): string => `Open${capitalize(word)}`,
|
||||
(word): string => `${capitalize(word)}box`,
|
||||
(word): string => `Insta${lower(word)}`,
|
||||
(word): string => `${capitalize(word)}Hub`,
|
||||
(word): string => `Cloud${capitalize(word)}`,
|
||||
(word): string => `quick${lower(word)}`,
|
||||
(word): string => `fast${lower(word)}`,
|
||||
(word): string => `super-${lower(word)}`,
|
||||
(word): string => `Hyper${capitalize(word)}`,
|
||||
(word): string => `${capitalize(word)}Go`,
|
||||
(word): string => `${lower(word)}-io`,
|
||||
(word): string => `Go${capitalize(word)}`,
|
||||
(word): string => `${capitalize(word)}X`,
|
||||
(word): string => `${capitalize(word)}time`,
|
||||
(word): string => `${capitalize(word)}flow`,
|
||||
(word): string => `${capitalize(word)}ful`,
|
||||
(word): string => `${capitalize(word)}ery`,
|
||||
(word): string => `${lower(word)}ly`,
|
||||
(word): string => `${lower(word)}joy`,
|
||||
(word): string => `${capitalize(word)}Hunt`,
|
||||
(word): string => `${capitalize(word)}gram`,
|
||||
(word): string => `${capitalize(word)}base`,
|
||||
(word): string => `${capitalize(word)}API`,
|
||||
(word): string => `${capitalize(word)}note`,
|
||||
(word): string => `In${capitalize(word)}`,
|
||||
(word): string => `Uni${lower(word)}`,
|
||||
(word): string => `${capitalize(word)}`,
|
||||
];
|
||||
|
||||
function shuffleArray<T>(array: T[]): T[] {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
const temp = array[i];
|
||||
@@ -59,15 +59,15 @@ function shuffleArray(array: any[]) {
|
||||
return array;
|
||||
}
|
||||
|
||||
function sampleFromArray(array: any[], maximum: number) {
|
||||
function sampleFromArray<T>(array: T[], maximum: number): T[] {
|
||||
return shuffleArray(array).slice(0, maximum);
|
||||
}
|
||||
|
||||
function modifyWord(word: string) {
|
||||
function modifyWord(word: string): string {
|
||||
return modifiers[Math.floor(Math.random() * modifiers.length)](word);
|
||||
}
|
||||
|
||||
function fillArray(array: any[], filler: string, maximum: number) {
|
||||
function fillArray<T>(array: T[], filler: string, maximum: number): T[] {
|
||||
const deficit = maximum - array.length;
|
||||
if (deficit > 0) {
|
||||
array = [...array, ...Array(deficit).fill(filler)];
|
||||
@@ -75,7 +75,7 @@ function fillArray(array: any[], filler: string, maximum: number) {
|
||||
return array;
|
||||
}
|
||||
|
||||
async function findSynonyms(word: string) {
|
||||
async function findSynonyms(word: string): Promise<string[]> {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&dt=ss&ie=UTF-8&oe=UTF-8&dj=1&q=${encodeURIComponent(
|
||||
@@ -92,7 +92,7 @@ async function findSynonyms(word: string) {
|
||||
[] as string[],
|
||||
),
|
||||
),
|
||||
).filter((word) => !word.match(/[\s-]/));
|
||||
).filter((word) => !/[\s-]/.exec(word));
|
||||
return synonyms;
|
||||
} catch (err) {
|
||||
return [];
|
||||
@@ -107,7 +107,7 @@ const Suggestion: React.FC<{
|
||||
const synonymRef = useRef<string[]>([]);
|
||||
const [bestWords, setBestWords] = useState<string[]>([]);
|
||||
|
||||
function shuffle() {
|
||||
function shuffle(): void {
|
||||
const best = fillArray(
|
||||
sampleFromArray(synonymRef.current, maximumCount),
|
||||
query,
|
||||
@@ -116,12 +116,12 @@ const Suggestion: React.FC<{
|
||||
setBestWords(best);
|
||||
}
|
||||
|
||||
function applyQuery(name: string) {
|
||||
function applyQuery(name: string): void {
|
||||
onSubmit(name);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const fn = async () => {
|
||||
const fn = async (): Promise<void> => {
|
||||
if (query && query.length > 0) {
|
||||
const synonyms = await findSynonyms(query);
|
||||
synonymRef.current = synonyms;
|
||||
@@ -142,7 +142,7 @@ const Suggestion: React.FC<{
|
||||
<Items>
|
||||
{bestWords &&
|
||||
bestWords.map((name) => (
|
||||
<Item key={name} onClick={() => applyQuery(name)}>
|
||||
<Item key={name} onClick={(): void => applyQuery(name)}>
|
||||
{name}
|
||||
</Item>
|
||||
))}
|
||||
|
@@ -23,7 +23,7 @@ import {DiRust, DiHeroku} from 'react-icons/di';
|
||||
import {SpectrumIcon, NowIcon, NetlifyIcon} from './Icons';
|
||||
import {mobile} from '../util/css';
|
||||
|
||||
export default function Welcome() {
|
||||
const Welcome: React.FC = () => {
|
||||
const {t} = useTranslation();
|
||||
|
||||
return (
|
||||
@@ -96,7 +96,8 @@ export default function Welcome() {
|
||||
</List>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
};
|
||||
export default Welcome;
|
||||
|
||||
const Container = styled.div`
|
||||
padding-bottom: 40px;
|
||||
|
@@ -231,6 +231,7 @@ class ErrorBoundary extends React.Component<
|
||||
return {hasError: true, message: error.message};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
componentDidCatch(error: Error, errorInfo: any) {
|
||||
if (error instanceof APIError || error instanceof NotFoundError) {
|
||||
return;
|
||||
|
@@ -15,8 +15,9 @@ const isLocalhost = Boolean(
|
||||
// [::1] is the IPv6 localhost address.
|
||||
window.location.hostname === '[::1]' ||
|
||||
// 127.0.0.1/8 is considered localhost for IPv4.
|
||||
window.location.hostname.match(
|
||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/,
|
||||
|
||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/.exec(
|
||||
window.location.hostname,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -25,7 +26,87 @@ type Config = {
|
||||
onUpdate?: (registration: ServiceWorkerRegistration) => void;
|
||||
};
|
||||
|
||||
export function register(config?: Config) {
|
||||
function registerValidSW(swUrl: string, config?: Config): void {
|
||||
navigator.serviceWorker
|
||||
.register(swUrl)
|
||||
.then((registration) => {
|
||||
registration.onupdatefound = (): void => {
|
||||
const installingWorker = registration.installing;
|
||||
if (installingWorker == null) {
|
||||
return;
|
||||
}
|
||||
installingWorker.onstatechange = (): void => {
|
||||
if (installingWorker.state === 'installed') {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
// At this point, the updated precached content has been fetched,
|
||||
// but the previous service worker will still serve the older
|
||||
// content until all client tabs are closed.
|
||||
console.log(
|
||||
'New content is available and will be used when all ' +
|
||||
'tabs for this page are closed. See https://bit.ly/CRA-PWA.',
|
||||
);
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onUpdate) {
|
||||
config.onUpdate(registration);
|
||||
}
|
||||
} else {
|
||||
// At this point, everything has been precached.
|
||||
// It's the perfect time to display a
|
||||
// "Content is cached for offline use." message.
|
||||
console.log('Content is cached for offline use.');
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onSuccess) {
|
||||
config.onSuccess(registration);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error during service worker registration:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function checkValidServiceWorker(swUrl: string, config?: Config): void {
|
||||
// Check if the service worker can be found. If it can't reload the page.
|
||||
fetch(swUrl)
|
||||
.then((response) => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (
|
||||
response.status === 404 ||
|
||||
(contentType != null && !contentType.includes('javascript'))
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then((registration) => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Service worker found. Proceed as normal.
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.log(
|
||||
'No internet connection found. App is running in offline mode.',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function unregister(): void {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.ready.then((registration) => {
|
||||
registration.unregister();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function register(config?: Config): void {
|
||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||
// The URL constructor is available in all browsers that support SW.
|
||||
const publicUrl = new URL(
|
||||
@@ -61,83 +142,3 @@ export function register(config?: Config) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function registerValidSW(swUrl: string, config?: Config) {
|
||||
navigator.serviceWorker
|
||||
.register(swUrl)
|
||||
.then((registration) => {
|
||||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing;
|
||||
if (installingWorker == null) {
|
||||
return;
|
||||
}
|
||||
installingWorker.onstatechange = () => {
|
||||
if (installingWorker.state === 'installed') {
|
||||
if (navigator.serviceWorker.controller) {
|
||||
// At this point, the updated precached content has been fetched,
|
||||
// but the previous service worker will still serve the older
|
||||
// content until all client tabs are closed.
|
||||
console.log(
|
||||
'New content is available and will be used when all ' +
|
||||
'tabs for this page are closed. See https://bit.ly/CRA-PWA.',
|
||||
);
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onUpdate) {
|
||||
config.onUpdate(registration);
|
||||
}
|
||||
} else {
|
||||
// At this point, everything has been precached.
|
||||
// It's the perfect time to display a
|
||||
// "Content is cached for offline use." message.
|
||||
console.log('Content is cached for offline use.');
|
||||
|
||||
// Execute callback
|
||||
if (config && config.onSuccess) {
|
||||
config.onSuccess(registration);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error during service worker registration:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function checkValidServiceWorker(swUrl: string, config?: Config) {
|
||||
// Check if the service worker can be found. If it can't reload the page.
|
||||
fetch(swUrl)
|
||||
.then((response) => {
|
||||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (
|
||||
response.status === 404 ||
|
||||
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker.ready.then((registration) => {
|
||||
registration.unregister().then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// Service worker found. Proceed as normal.
|
||||
registerValidSW(swUrl, config);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
console.log(
|
||||
'No internet connection found. App is running in offline mode.',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function unregister() {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.ready.then((registration) => {
|
||||
registration.unregister();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -3,14 +3,14 @@ import * as Sentry from '@sentry/browser';
|
||||
|
||||
const isProduction = process.env.NODE_ENV !== 'development';
|
||||
|
||||
export function initGA() {
|
||||
export function initGA(): void {
|
||||
if (isProduction) {
|
||||
ReactGA.initialize('UA-28919359-15');
|
||||
ReactGA.pageview(window.location.pathname + window.location.search);
|
||||
}
|
||||
}
|
||||
|
||||
export function sendQueryStatistics(queryLength: number) {
|
||||
export function sendQueryStatistics(queryLength: number): void {
|
||||
if (isProduction) {
|
||||
ReactGA.event({
|
||||
category: 'Search',
|
||||
@@ -20,7 +20,7 @@ export function sendQueryStatistics(queryLength: number) {
|
||||
}
|
||||
}
|
||||
|
||||
export function initSentry() {
|
||||
export function initSentry(): void {
|
||||
if (isProduction) {
|
||||
Sentry.init({
|
||||
dsn: 'https://7ab2df74aead499b950ebef190cc40b7@sentry.io/1759299',
|
||||
@@ -28,7 +28,13 @@ export function initSentry() {
|
||||
}
|
||||
}
|
||||
|
||||
export function sendError(error: Error, errorInfo: any): Promise<string> {
|
||||
export function sendError(
|
||||
error: Error,
|
||||
errorInfo: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
[key: string]: any;
|
||||
},
|
||||
): Promise<string> {
|
||||
return new Promise((resolve) => {
|
||||
if (isProduction) {
|
||||
Sentry.withScope((scope) => {
|
||||
|
@@ -1,10 +1,10 @@
|
||||
interface CrispWindow extends Window {
|
||||
$crisp: any[];
|
||||
$crisp: unknown[];
|
||||
CRISP_WEBSITE_ID: string;
|
||||
}
|
||||
declare var window: CrispWindow;
|
||||
declare let window: CrispWindow;
|
||||
|
||||
export function initCrisp() {
|
||||
export function initCrisp(): void {
|
||||
window.$crisp = [];
|
||||
window.CRISP_WEBSITE_ID = '92b2e096-6892-47dc-bf4a-057bad52d82e';
|
||||
const s = document.createElement('script');
|
||||
|
@@ -12,7 +12,7 @@ export function useDeferredState<T>(
|
||||
setResponse(innerValue);
|
||||
}, duration);
|
||||
|
||||
return () => {
|
||||
return (): void => {
|
||||
clearTimeout(fn);
|
||||
};
|
||||
}, [duration, innerValue]);
|
||||
|
@@ -2,7 +2,7 @@ interface CustomNavigator extends Navigator {
|
||||
standalone?: boolean;
|
||||
}
|
||||
|
||||
export function isStandalone() {
|
||||
export function isStandalone(): boolean {
|
||||
const navigator: CustomNavigator = window.navigator;
|
||||
return 'standalone' in navigator && navigator.standalone;
|
||||
return 'standalone' in navigator && navigator.standalone === true;
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ const Container = styled.div`
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const Fallback = () => (
|
||||
const Fallback: React.FC = () => (
|
||||
<Container>
|
||||
<BarLoader />
|
||||
</Container>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
export function capitalize(text: string) {
|
||||
export function capitalize(text: string): string {
|
||||
if (text.length === 0) return '';
|
||||
return text[0].toUpperCase() + text.slice(1).toLowerCase();
|
||||
}
|
||||
|
Reference in New Issue
Block a user