mirror of
https://github.com/uetchy/namae.git
synced 2025-03-16 20:20:38 +09:00
Merge pull request #141 from ArnaudLier/subreddit-card
feat: subreddit card
This commit is contained in:
commit
b861be6cd9
@ -1,11 +1,11 @@
|
||||
import { NowRequest, NowResponse } from '@vercel/node';
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
import assert from 'assert';
|
||||
import fetch from 'cross-fetch';
|
||||
import { send, sendError } from '../../../util/http';
|
||||
|
||||
export default async function handler(
|
||||
req: NowRequest,
|
||||
res: NowResponse
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
): Promise<void> {
|
||||
const { query } = req.query;
|
||||
|
||||
@ -27,7 +27,7 @@ export default async function handler(
|
||||
}
|
||||
).then((res) => res.json());
|
||||
send(res, response);
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { send, sendError, fetch } from '../../../util/http';
|
||||
import { NowRequest, NowResponse } from '@vercel/node';
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
|
||||
interface App {
|
||||
trackId: string;
|
||||
@ -15,8 +15,8 @@ interface AppStoreResponse {
|
||||
}
|
||||
|
||||
export default async function handler(
|
||||
req: NowRequest,
|
||||
res: NowResponse
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
): Promise<void> {
|
||||
const { query, country } = req.query;
|
||||
|
||||
@ -43,7 +43,7 @@ export default async function handler(
|
||||
viewURL: app.trackViewUrl,
|
||||
}));
|
||||
send(res, { result: apps });
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { send, sendError, fetch } from '../../../util/http';
|
||||
import { NowRequest, NowResponse } from '@vercel/node';
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
|
||||
export default async function handler(
|
||||
req: NowRequest,
|
||||
res: NowResponse
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
): Promise<void> {
|
||||
const { query } = req.query;
|
||||
|
||||
@ -22,7 +22,7 @@ export default async function handler(
|
||||
).then((res) => res.text());
|
||||
const availability = !/<div id="exact-matches"/.test(response);
|
||||
send(res, { availability });
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { send, sendError, fetch } from '../../../util/http';
|
||||
import { NowRequest, NowResponse } from '@vercel/node';
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
|
||||
export default async function handler(
|
||||
req: NowRequest,
|
||||
res: NowResponse
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
): Promise<void> {
|
||||
const { query } = req.query;
|
||||
|
||||
@ -23,7 +23,7 @@ export default async function handler(
|
||||
const body = await response.text();
|
||||
const availability = body.includes('No such package');
|
||||
send(res, { availability });
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import dns from 'dns';
|
||||
import { send, sendError } from '../../../util/http';
|
||||
import { NowRequest, NowResponse } from '@vercel/node';
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
|
||||
function resolvePromise(hostname: string): Promise<string[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
@ -12,8 +12,8 @@ function resolvePromise(hostname: string): Promise<string[]> {
|
||||
}
|
||||
|
||||
export default async function handler(
|
||||
req: NowRequest,
|
||||
res: NowResponse
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
): Promise<void> {
|
||||
const { query } = req.query;
|
||||
|
||||
@ -25,7 +25,7 @@ export default async function handler(
|
||||
const response = await resolvePromise(query);
|
||||
const availability = response && response.length > 0 ? false : true;
|
||||
send(res, { availability });
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
if (err.code === 'ENODATA' || err.code === 'ENOTFOUND') {
|
||||
return send(res, { availability: true });
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { NowRequest, NowResponse } from '@vercel/node';
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
import 'cross-fetch';
|
||||
import whois from 'whois-json';
|
||||
import { send, sendError } from '../../../util/http';
|
||||
|
||||
export default async function handler(
|
||||
req: NowRequest,
|
||||
res: NowResponse
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
): Promise<void> {
|
||||
const { query } = req.query;
|
||||
|
||||
@ -17,7 +17,7 @@ export default async function handler(
|
||||
const response = await whois(query, { follow: 3, verbose: true });
|
||||
const availability = response[0].data.domainName ? false : true;
|
||||
send(res, { availability });
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
||||
|
@ -20,10 +20,10 @@ export default async function handler(
|
||||
const response = await fetch(`https://${query}`);
|
||||
const availability = response.status === 404;
|
||||
send(res, { availability });
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
if ((err as any).code === 'ENOTFOUND') {
|
||||
return send(res, { availability: true });
|
||||
}
|
||||
sendError(res, err as any);
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { NowRequest, NowResponse } from '@vercel/node';
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
import nodeFetch from 'cross-fetch';
|
||||
import { send, sendError } from '../../../util/http';
|
||||
|
||||
export default async function handler(
|
||||
req: NowRequest,
|
||||
res: NowResponse
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
): Promise<void> {
|
||||
const { query } = req.query;
|
||||
|
||||
@ -22,7 +22,7 @@ export default async function handler(
|
||||
});
|
||||
const availability = response.status === 302;
|
||||
send(res, { availability });
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ export default async function handler(
|
||||
} else {
|
||||
send(res, { availability: true });
|
||||
}
|
||||
} catch (err) {
|
||||
sendError(res, err as any);
|
||||
} catch (err: any) {
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { send, sendError, fetch } from '../../../util/http';
|
||||
import { NowRequest, NowResponse } from '@vercel/node';
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
|
||||
export default async function handler(
|
||||
req: NowRequest,
|
||||
res: NowResponse
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
): Promise<void> {
|
||||
const { query } = req.query;
|
||||
|
||||
@ -24,7 +24,7 @@ export default async function handler(
|
||||
);
|
||||
const availability = response.status !== 200;
|
||||
send(res, { availability });
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import npmName from 'npm-name';
|
||||
import { send, sendError } from '../../../util/http';
|
||||
import { NowRequest, NowResponse } from '@vercel/node';
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
|
||||
export default async function handler(
|
||||
req: NowRequest,
|
||||
res: NowResponse
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
): Promise<void> {
|
||||
const { query } = req.query;
|
||||
|
||||
@ -15,7 +15,7 @@ export default async function handler(
|
||||
try {
|
||||
const availability = await npmName(`@${query}`);
|
||||
send(res, { availability });
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
if (err.code === 'ENOTFOUND') {
|
||||
return send(res, { availability: true });
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ export default async function handler(
|
||||
try {
|
||||
const availability = await npmName(query);
|
||||
send(res, { availability });
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ export default async function handler(
|
||||
}))
|
||||
.slice(0, 10) || [],
|
||||
});
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { NowRequest, NowResponse } from '@vercel/node';
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
import 'cross-fetch';
|
||||
import { fetch, send, sendError } from '../../../util/http';
|
||||
|
||||
export default async function handler(
|
||||
req: NowRequest,
|
||||
res: NowResponse
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
): Promise<void> {
|
||||
const { query } = req.query;
|
||||
|
||||
@ -34,7 +34,7 @@ export default async function handler(
|
||||
url: 'https://play.google.com' + entry[9][4][2],
|
||||
}));
|
||||
send(res, { result: apps.slice(0, 10) });
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
||||
|
28
api/services/reddit/[query].ts
Normal file
28
api/services/reddit/[query].ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { send, sendError, fetch } from '../../../util/http';
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
|
||||
export default async function handler(
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
): Promise<void> {
|
||||
const { query } = req.query;
|
||||
|
||||
if (!query || typeof query !== 'string') {
|
||||
return sendError(res, new Error('No query given'));
|
||||
}
|
||||
|
||||
if (/[^a-zA-Z0-9_]/.test(query)) {
|
||||
return sendError(res, new Error('Invalid characters'));
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`https://reddit.com/r/${query}`, 'GET');
|
||||
const body = await response.text();
|
||||
const availability = body.includes(
|
||||
'Sorry, there aren’t any communities on Reddit with that name.'
|
||||
);
|
||||
send(res, { availability });
|
||||
} catch (err: any) {
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
import { send, sendError, fetch } from '../../../util/http';
|
||||
import { NowRequest, NowResponse } from '@vercel/node';
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
|
||||
export default async function handler(
|
||||
req: NowRequest,
|
||||
res: NowResponse
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
): Promise<void> {
|
||||
const { query } = req.query;
|
||||
|
||||
@ -21,7 +21,7 @@ export default async function handler(
|
||||
);
|
||||
const availability = response.status !== 200;
|
||||
send(res, { availability });
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { send, sendError, fetch } from '../../../util/http';
|
||||
import { NowRequest, NowResponse } from '@vercel/node';
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
|
||||
export default async function handler(
|
||||
req: NowRequest,
|
||||
res: NowResponse
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
): Promise<void> {
|
||||
const { query } = req.query;
|
||||
|
||||
@ -25,7 +25,7 @@ export default async function handler(
|
||||
'You may be trying to view something that is deleted'
|
||||
);
|
||||
send(res, { availability });
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { NowRequest, NowResponse } from '@vercel/node';
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
import { fetch, send, sendError } from '../../../util/http';
|
||||
|
||||
export default async function handler(
|
||||
req: NowRequest,
|
||||
res: NowResponse
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
): Promise<void> {
|
||||
const { query } = req.query;
|
||||
|
||||
@ -22,7 +22,7 @@ export default async function handler(
|
||||
).then((res) => res.json());
|
||||
const availability = response.valid;
|
||||
send(res, { availability });
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
sendError(res, err);
|
||||
}
|
||||
}
|
||||
|
@ -37,6 +37,7 @@
|
||||
"s3": "AWS S3",
|
||||
"slack": "Slack",
|
||||
"spectrum": "Spectrum",
|
||||
"reddit": "Reddit",
|
||||
"twitter": "Twitter"
|
||||
},
|
||||
"showMore": "Zeig mehr",
|
||||
|
@ -41,6 +41,7 @@
|
||||
"s3": "AWS S3",
|
||||
"slack": "Slack",
|
||||
"spectrum": "Spectrum",
|
||||
"reddit": "Reddit",
|
||||
"twitter": "Twitter"
|
||||
},
|
||||
"showMore": "show more",
|
||||
|
@ -37,6 +37,7 @@
|
||||
"s3": "AWS S3",
|
||||
"slack": "Slack",
|
||||
"spectrum": "Spectrum",
|
||||
"reddit": "Reddit",
|
||||
"twitter": "Twitter"
|
||||
},
|
||||
"showMore": "afficher plus",
|
||||
|
@ -37,6 +37,7 @@
|
||||
"s3": "AWS S3",
|
||||
"slack": "Slack",
|
||||
"spectrum": "Spectrum",
|
||||
"reddit": "Reddit",
|
||||
"twitter": "Twitter"
|
||||
},
|
||||
"showMore": "さらに表示",
|
||||
|
@ -41,6 +41,7 @@
|
||||
"s3": "AWS S3",
|
||||
"slack": "Slack",
|
||||
"spectrum": "Spectrum",
|
||||
"reddit": "Reddit",
|
||||
"twitter": "Twitter"
|
||||
},
|
||||
"showMore": "Mostrar +",
|
||||
|
@ -37,6 +37,7 @@
|
||||
"s3": "AWS S3",
|
||||
"slack": "Slack",
|
||||
"spectrum": "Spectrum",
|
||||
"reddit": "Reddit",
|
||||
"twitter": "推特"
|
||||
},
|
||||
"showMore": "更多",
|
||||
|
@ -37,6 +37,7 @@
|
||||
"s3": "AWS S3",
|
||||
"slack": "Slack",
|
||||
"spectrum": "Spectrum",
|
||||
"reddit": "Reddit",
|
||||
"twitter": "推特"
|
||||
},
|
||||
"showMore": "更多",
|
||||
|
@ -24,6 +24,7 @@ import RubyGemsCard from './providers/RubyGems';
|
||||
import S3Card from './providers/S3';
|
||||
import SlackCard from './providers/Slack';
|
||||
import SpectrumCard from './providers/Spectrum';
|
||||
import SubredditCard from './providers/Subreddit';
|
||||
import TwitterCard from './providers/Twitter';
|
||||
import VercelCard from './providers/Vercel';
|
||||
|
||||
@ -53,6 +54,7 @@ const Index: React.FC<{ query: string }> = ({ query }) => {
|
||||
<SlackCard query={query} />
|
||||
{/* <InstagramCard query={query} /> */}
|
||||
<SpectrumCard query={query} />
|
||||
<SubredditCard query={query} />
|
||||
<S3Card query={query} />
|
||||
<FirebaseCard query={query} />
|
||||
</Cards>
|
||||
|
39
src/components/cards/providers/Subreddit.tsx
Normal file
39
src/components/cards/providers/Subreddit.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaReddit } from 'react-icons/fa';
|
||||
import { normalize } from '../../../util/text';
|
||||
|
||||
import { Card, Repeater, DedicatedAvailability } from '../core';
|
||||
|
||||
const SubredditCard: React.FC<{ query: string }> = ({ query }) => {
|
||||
const { t } = useTranslation();
|
||||
const normalizedQuery = normalize(query, {
|
||||
allowUnderscore: true,
|
||||
});
|
||||
const lowerCase = normalizedQuery.toLowerCase();
|
||||
|
||||
const names = [normalizedQuery];
|
||||
const moreNames = [
|
||||
`get${lowerCase}`,
|
||||
`${lowerCase}_team`,
|
||||
];
|
||||
|
||||
return (
|
||||
<Card title={t('providers.reddit')}>
|
||||
<Repeater items={names} moreItems={moreNames}>
|
||||
{(name) => (
|
||||
<DedicatedAvailability
|
||||
name={name}
|
||||
service="reddit" // route to http://namae.dev/api/services/reddit/<query> which is /api/services/reddit/[query].ts on GitHub
|
||||
message={`Go to reddit.com/r/${name}`}
|
||||
link={`https://reddit.com/r/${name}`}
|
||||
prefix="reddit.com/r/"
|
||||
icon={<FaReddit />}
|
||||
/>
|
||||
)}
|
||||
</Repeater>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default SubredditCard;
|
@ -4,7 +4,8 @@ import '@testing-library/jest-dom/extend-expect';
|
||||
// i18next
|
||||
import { join } from 'path';
|
||||
import i18n from 'i18next';
|
||||
import Backend from 'i18next-node-fs-backend';
|
||||
import Backend from 'i18next-chained-backend';
|
||||
import NodeFs from 'i18next-node-fs-backend';
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
|
||||
@ -14,7 +15,10 @@ i18n
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
backend: {
|
||||
loadPath: join(__dirname, '../public/locales/{{lng}}/{{ns}}.json'),
|
||||
backends: [NodeFs],
|
||||
backendOptions: [
|
||||
{ loadPath: join(__dirname, '../public/locales/{{lng}}/{{ns}}.json') },
|
||||
],
|
||||
},
|
||||
fallbackLng: 'en',
|
||||
ns: ['translation'],
|
||||
|
@ -21,7 +21,7 @@ export function trackEvent({
|
||||
if (isProduction) {
|
||||
try {
|
||||
umami && umami.trackEvent(value, type);
|
||||
} catch (err) {}
|
||||
} catch (err: any) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user