diff --git a/src/components/Card.js b/src/components/Card.js index 1e44466..a677b77 100644 --- a/src/components/Card.js +++ b/src/components/Card.js @@ -1,5 +1,6 @@ -import React, { Suspense } from 'react' +import React, { Suspense, useState } from 'react' import styled from 'styled-components' +import useFetch from 'fetch-suspense' import { BarLoader } from 'react-spinners' export function Card({ children }) { @@ -49,6 +50,96 @@ export function AvailabilityCell({ ) } +export function DedicatedAvailability({ + name, + provider, + url, + prefix = '', + suffix = '', + icon, +}) { + const response = useFetch(`/availability/${provider}/${name}`) + + if (response.error) { + throw new Error(`${provider}: ${response.error}`) + } + + return ( + + ) +} + +export function ExistenceAvailability({ + name, + target, + prefix = '', + suffix = '', + icon, +}) { + const response = useFetch(target, null, { metadata: true }) + + if (response.status !== 404 && response.status !== 200) { + throw new Error(`Homebrew: ${response.statusText}`) + } + + const availability = response.status === 404 + + return ( + + ) +} + +export function Alternatives({ nameList, children }) { + const [show, setShow] = useState(false) + + console.log(children) + + function onClick() { + setShow(true) + } + + return ( + <> + {show ? ( + nameList.map((name) => ( + + }>{children(name)} + + )) + ) : ( + + Show Alternatives + + )} + + ) +} + +const ShowAlternativesButton = styled.div` + display: inline-block; + margin-top: 10px; + padding: 5px 0; + border: none; + border-bottom: 1px dashed black; + cursor: pointer; + font-family: monospace; + font-size: 1rem; +` + class ErrorBoundary extends React.Component { constructor(props) { super(props) @@ -77,7 +168,7 @@ const CardWrapper = styled.div` border-radius: 2px; ` -const ItemContainer = styled.span` +const ItemContainer = styled.div` display: flex; flex-direction: row; align-items: flex-start; diff --git a/src/components/GithubCard.js b/src/components/GithubCard.js index 13a43b5..2794887 100644 --- a/src/components/GithubCard.js +++ b/src/components/GithubCard.js @@ -1,31 +1,30 @@ import React from 'react' -import useFetch from 'fetch-suspense' -import { Card, CardTitle, AvailabilityCell } from './Card' import { FaGithub } from 'react-icons/fa' - -function Availability({ name }) { - const response = useFetch(`/availability/github/${name}`) - - if (response.error) { - throw new Error(`GitHub: ${response.error}`) - } - - return ( - } - /> - ) -} +import { Card, CardTitle, DedicatedAvailability, Alternatives } from './Card' export default function GithubCard({ name }) { return ( GitHub - + } + /> + + {(name) => ( + } + /> + )} + ) } diff --git a/src/components/HomebrewCard.js b/src/components/HomebrewCard.js index ef6aa23..9601b05 100644 --- a/src/components/HomebrewCard.js +++ b/src/components/HomebrewCard.js @@ -1,36 +1,17 @@ import React from 'react' -import useFetch from 'fetch-suspense' -import { Card, CardTitle, AvailabilityCell } from './Card' +import { Card, CardTitle, ExistenceAvailability } from './Card' import { IoIosBeer } from 'react-icons/io' -function Availability({ name }) { - const response = useFetch( - `https://formulae.brew.sh/api/formula/${name}.json`, - null, - { metadata: true } - ) - - if (response.status !== 404 && response.status !== 200) { - throw new Error(`Homebrew: ${response.statusText}`) - } - - const availability = response.status === 404 - - return ( - } - /> - ) -} - export default function HomebrewCard({ name }) { return ( Homebrew - + } + /> ) } diff --git a/src/components/JsOrgCard.js b/src/components/JsOrgCard.js index c3d9aaf..bd06276 100644 --- a/src/components/JsOrgCard.js +++ b/src/components/JsOrgCard.js @@ -1,31 +1,18 @@ import React from 'react' -import useFetch from 'fetch-suspense' -import { Card, CardTitle, AvailabilityCell } from './Card' import { FaJsSquare } from 'react-icons/fa' - -function Availability({ name }) { - const response = useFetch(`/availability/jsorg/${name}`) - - if (response.error) { - throw new Error(`Twitter: ${response.error}`) - } - - return ( - } - /> - ) -} +import { Card, CardTitle, DedicatedAvailability } from './Card' export default function JsOrgCard({ name }) { return ( js.org - + } + /> ) } diff --git a/src/components/NpmCard.js b/src/components/NpmCard.js index f448906..5a66d5a 100644 --- a/src/components/NpmCard.js +++ b/src/components/NpmCard.js @@ -1,40 +1,25 @@ import React from 'react' -import useFetch from 'fetch-suspense' -import { Card, CardTitle, AvailabilityCell } from './Card' import { FaNpm } from 'react-icons/fa' - -function Availability({ name }) { - const response = useFetch(`/availability/npm/${name}`) - - if (response.error) { - throw new Error(`npm: ${response.error}`) - } - - return ( - <> - } - /> - } - url="https://www.npmjs.com/org/" - prefix="npmjs.com/org/" - /> - - ) -} +import { Card, CardTitle, DedicatedAvailability } from './Card' export default function NpmCard({ name }) { return ( npm - + } + /> + } + /> ) } diff --git a/src/components/TwitterCard.js b/src/components/TwitterCard.js index cd7d2a7..e283ac6 100644 --- a/src/components/TwitterCard.js +++ b/src/components/TwitterCard.js @@ -1,31 +1,31 @@ import React from 'react' -import useFetch from 'fetch-suspense' -import { Card, CardTitle, AvailabilityCell } from './Card' import { FaTwitter } from 'react-icons/fa' - -function Availability({ name }) { - const response = useFetch(`/availability/twitter/${name}`) - - if (response.error) { - throw new Error(`Twitter: ${response.error}`) - } - - return ( - } - /> - ) -} +import { Card, CardTitle, DedicatedAvailability, Alternatives } from './Card' +import { capitalize } from '../util/text' export default function TwitterCard({ name }) { return ( Twitter - + } + /> + + {(name) => ( + } + /> + )} + ) } diff --git a/src/services/npm-org.js b/src/services/npm-org.js new file mode 100644 index 0000000..6a85958 --- /dev/null +++ b/src/services/npm-org.js @@ -0,0 +1,16 @@ +const npmName = require('npm-name') + +module.exports = async (req, res) => { + const name = req.query.name + + if (!name) { + return res.status(400).json({ error: 'no query given' }) + } + + try { + const availability = await npmName(`@${name}`) + res.json({ availability }) + } catch (err) { + res.status(400).json({ error: err.message }) + } +} diff --git a/src/services/npm.js b/src/services/npm.js index 9be607b..f50e6e6 100644 --- a/src/services/npm.js +++ b/src/services/npm.js @@ -8,9 +8,8 @@ module.exports = async (req, res) => { } try { - const packageAvailability = await npmName(name) - const orgAvailability = await npmName(`@${name}`) - res.json({ packageAvailability, orgAvailability }) + const availability = await npmName(name) + res.json({ availability }) } catch (err) { res.status(400).json({ error: err.message }) } diff --git a/src/util/text.js b/src/util/text.js new file mode 100644 index 0000000..95f67a1 --- /dev/null +++ b/src/util/text.js @@ -0,0 +1,3 @@ +export function capitalize(text) { + return text[0].toUpperCase() + text.slice(1) +}