1
0
mirror of https://github.com/uetchy/namae.git synced 2025-03-16 12:10:32 +09:00

feat: support Docker Hub

This commit is contained in:
uetchy 2022-07-10 09:59:16 +09:00
parent 09f2755410
commit ad6052c29a
8 changed files with 67 additions and 22 deletions

1
.gitignore vendored
View File

@ -99,3 +99,4 @@ typings/
.now .now
.vercel .vercel
.sentryclirc

View File

@ -6,7 +6,9 @@ export default async function handler(
req: VercelRequest, req: VercelRequest,
res: VercelResponse res: VercelResponse
): Promise<void> { ): Promise<void> {
const { query } = req.query; const { query, existIf = '404' } = req.query;
const availableStatus = (existIf as string).split(',').map((s) => s.trim());
if (!query || typeof query !== 'string') { if (!query || typeof query !== 'string') {
return sendError(res, new Error('no query given')); return sendError(res, new Error('no query given'));
@ -18,7 +20,7 @@ export default async function handler(
try { try {
const response = await fetch(`https://${query}`); const response = await fetch(`https://${query}`);
const availability = response.status === 404; const availability = availableStatus.includes(response.status.toString());
send(res, { availability }); send(res, { availability });
} catch (err: any) { } catch (err: any) {
if ((err as any).code === 'ENOTFOUND') { if ((err as any).code === 'ENOTFOUND') {

View File

@ -51,7 +51,8 @@
"youtube": "YouTube", "youtube": "YouTube",
"hexpm": "Hex", "hexpm": "Hex",
"fly": "Fly.io", "fly": "Fly.io",
"productHunt": "Product Hunt" "productHunt": "Product Hunt",
"docker": "Docker Hub"
}, },
"showMore": "show more", "showMore": "show more",
"try": "How about this?", "try": "How about this?",

View File

@ -3,29 +3,31 @@ import { useTranslation } from 'react-i18next';
import { DiHeroku } from 'react-icons/di'; import { DiHeroku } from 'react-icons/di';
import { import {
FaAws, FaAws,
FaCloudflare,
FaDocker,
FaFirefoxBrowser,
FaFly,
FaGithub, FaGithub,
FaGithubAlt, FaGithubAlt,
FaGitlab, FaGitlab,
// FaInstagram, // FaInstagram,
FaJsSquare, FaJsSquare,
FaProductHunt,
FaPython, FaPython,
FaReddit, FaReddit,
FaSlack, FaSlack,
FaTwitter, FaTwitter,
FaCloudflare,
FaFirefoxBrowser,
FaYoutube, FaYoutube,
FaProductHunt,
FaFly,
} from 'react-icons/fa'; } from 'react-icons/fa';
import { IoIosBeer, IoMdAppstore } from 'react-icons/io'; import { IoIosBeer } from 'react-icons/io';
import { MdDomain } from 'react-icons/md'; import { MdDomain } from 'react-icons/md';
import { RiBuilding2Fill, RiChromeFill, RiNpmjsFill } from 'react-icons/ri'; import { RiBuilding2Fill, RiChromeFill, RiNpmjsFill } from 'react-icons/ri';
import { SiDeno, SiElixir } from 'react-icons/si';
import { import {
SiAppstore, SiAppstore,
SiArchlinux, SiArchlinux,
SiDebian, SiDebian,
SiDeno,
SiElixir,
SiFirebase, SiFirebase,
SiRubygems, SiRubygems,
SiRust, SiRust,
@ -41,37 +43,38 @@ const supportedProviders: Record<string, React.ReactNode> = {
domains: <MdDomain />, domains: <MdDomain />,
github: <FaGithub />, github: <FaGithub />,
gitlab: <FaGitlab />, gitlab: <FaGitlab />,
slack: <FaSlack />,
productHunt: <FaProductHunt />,
githubSearch: <FaGithubAlt />,
nta: <RiBuilding2Fill />,
twitter: <FaTwitter />, twitter: <FaTwitter />,
reddit: <FaReddit />,
youtube: <FaYoutube />, youtube: <FaYoutube />,
docker: <FaDocker />,
homebrew: <IoIosBeer />, homebrew: <IoIosBeer />,
archlinux: <SiArchlinux />,
debian: <SiDebian />,
ubuntu: <SiUbuntu />,
npm: <RiNpmjsFill />, npm: <RiNpmjsFill />,
rust: <SiRust />,
pypi: <FaPython />, pypi: <FaPython />,
rust: <SiRust />,
rubygems: <SiRubygems />, rubygems: <SiRubygems />,
hexpm: <SiElixir />, hexpm: <SiElixir />,
ocaml: <OcamlIcon />, ocaml: <OcamlIcon />,
archlinux: <SiArchlinux />,
ubuntu: <SiUbuntu />,
debian: <SiDebian />,
reddit: <FaReddit />,
// instagram: <FaInstagram />, // instagram: <FaInstagram />,
slack: <FaSlack />,
fly: <FaFly />, fly: <FaFly />,
heroku: <DiHeroku />,
now: <NowIcon />, now: <NowIcon />,
heroku: <DiHeroku />,
netlify: <NetlifyIcon />, netlify: <NetlifyIcon />,
cloudflare: <FaCloudflare />, cloudflare: <FaCloudflare />,
s3: <FaAws />, s3: <FaAws />,
firebase: <SiFirebase />, firebase: <SiFirebase />,
jsorg: <FaJsSquare />, jsorg: <FaJsSquare />,
modland: <SiDeno />, modland: <SiDeno />,
productHunt: <FaProductHunt />,
githubSearch: <FaGithubAlt />,
appStore: <SiAppstore />, appStore: <SiAppstore />,
// playStore: <IoMdAppstore />, // playStore: <IoMdAppstore />,
firefoxAddons: <FaFirefoxBrowser />, firefoxAddons: <FaFirefoxBrowser />,
chromeWebStore: <RiChromeFill />, chromeWebStore: <RiChromeFill />,
nta: <RiBuilding2Fill />,
}; };
const Welcome: React.FC = () => { const Welcome: React.FC = () => {

View File

@ -83,6 +83,7 @@ class NotFoundError extends Error {
export const DedicatedAvailability: React.FC<{ export const DedicatedAvailability: React.FC<{
name: string; name: string;
query?: string; query?: string;
args?: Record<string, string>;
message?: string; message?: string;
messageIfTaken?: string; messageIfTaken?: string;
service: string; service: string;
@ -94,6 +95,7 @@ export const DedicatedAvailability: React.FC<{
}> = ({ }> = ({
name, name,
query = undefined, query = undefined,
args = {},
message = '', message = '',
messageIfTaken = undefined, messageIfTaken = undefined,
service, service,
@ -105,7 +107,8 @@ export const DedicatedAvailability: React.FC<{
}) => { }) => {
const increaseCounter = useStoreActions((actions) => actions.stats.add); const increaseCounter = useStoreActions((actions) => actions.stats.add);
const response = useFetch( const response = useFetch(
`/api/services/${service}/${encodeURIComponent(query || name)}` `/api/services/${service}/${encodeURIComponent(query || name)}` +
new URLSearchParams(args).toString()
) as Response; ) as Response;
if (response.error) { if (response.error) {

View File

@ -6,6 +6,7 @@ import AppStoreCard from './providers/AppStore';
import ChromeWebStoreCard from './providers/ChromeWebStore'; import ChromeWebStoreCard from './providers/ChromeWebStore';
import CloudflareCard from './providers/Cloudflare'; import CloudflareCard from './providers/Cloudflare';
import CratesioCard from './providers/Cratesio'; import CratesioCard from './providers/Cratesio';
import DockerCard from './providers/Docker';
import DomainCard from './providers/Domains'; import DomainCard from './providers/Domains';
import FirebaseCard from './providers/Firebase'; import FirebaseCard from './providers/Firebase';
import FirefoxAddonsCard from './providers/FirefoxAddons'; import FirefoxAddonsCard from './providers/FirefoxAddons';
@ -23,7 +24,7 @@ import NetlifyCard from './providers/Netlify';
import NpmCard from './providers/Npm'; import NpmCard from './providers/Npm';
import NtaCard from './providers/Nta'; import NtaCard from './providers/Nta';
import OcamlCard from './providers/Ocaml'; import OcamlCard from './providers/Ocaml';
import PlayStoreCard from './providers/PlayStore'; // import PlayStoreCard from './providers/PlayStore';
import ProductHuntCard from './providers/ProductHunt'; import ProductHuntCard from './providers/ProductHunt';
import PypiCard from './providers/PyPI'; import PypiCard from './providers/PyPI';
import RubyGemsCard from './providers/RubyGems'; import RubyGemsCard from './providers/RubyGems';
@ -64,6 +65,7 @@ const Index: React.FC<{ query: string }> = ({ query }) => {
<Section> <Section>
<Title>{t('section.package')}</Title> <Title>{t('section.package')}</Title>
<Cards> <Cards>
<DockerCard query={query} />
<HomebrewCard query={query} /> <HomebrewCard query={query} />
<LinuxCard query={query} /> <LinuxCard query={query} />
<NpmCard query={query} /> <NpmCard query={query} />

View File

@ -0,0 +1,33 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { FaDocker } from 'react-icons/fa';
import { normalize } from '../../../util/text';
import { Card, DedicatedAvailability, Repeater } from '../core';
const DockerCard: React.FC<{ query: string }> = ({ query }) => {
const { t } = useTranslation();
const normalizedQuery = normalize(query, { allowUnderscore: false });
const lowerCase = normalizedQuery.toLowerCase();
const names = [lowerCase];
return (
<Card title={t('providers.docker')}>
<Repeater items={names}>
{(name) => (
<DedicatedAvailability
name={name}
query={`hub.docker.com/v2/orgs/${name}`}
service="existence"
message="Go to Docker Hub"
link={`https://hub.docker.com/orgs/${name}`}
icon={<FaDocker />}
/>
)}
</Repeater>
</Card>
);
};
export default DockerCard;

View File

@ -5,7 +5,7 @@ import XHR from 'i18next-xhr-backend';
import LanguageDetector from 'i18next-browser-languagedetector'; import LanguageDetector from 'i18next-browser-languagedetector';
import { initReactI18next } from 'react-i18next'; import { initReactI18next } from 'react-i18next';
const TRANSLATION_VERSION = '19'; const TRANSLATION_VERSION = '20';
i18n i18n
.use(Backend) .use(Backend)