mirror of
https://github.com/uetchy/namae.git
synced 2025-03-17 12:30:32 +09:00
chore: move components into separated files
This commit is contained in:
parent
7c18e0643c
commit
2438518e3c
170
web/src/App.tsx
170
web/src/App.tsx
@ -1,131 +1,40 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react'
|
import React, { useState } from 'react'
|
||||||
import styled, { createGlobalStyle } from 'styled-components'
|
import styled, { createGlobalStyle } from 'styled-components'
|
||||||
import { Helmet } from 'react-helmet'
|
import { Helmet } from 'react-helmet'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
import DomainCard from './components/cards/domains'
|
|
||||||
import GithubCard from './components/cards/github-repository'
|
|
||||||
import NpmCard from './components/cards/npm'
|
|
||||||
import PypiCard from './components/cards/pypi'
|
|
||||||
import RubyGemsCard from './components/cards/rubygems'
|
|
||||||
import CratesioCard from './components/cards/cratesio'
|
|
||||||
import HomebrewCard from './components/cards/homebrew'
|
|
||||||
import LinuxCard from './components/cards/linux'
|
|
||||||
import TwitterCard from './components/cards/twitter'
|
|
||||||
import SpectrumCard from './components/cards/spectrum'
|
|
||||||
import SlackCard from './components/cards/slack'
|
|
||||||
import S3Card from './components/cards/s3'
|
|
||||||
import JsOrgCard from './components/cards/jsorg'
|
|
||||||
import GithubSearchCard from './components/cards/github-search'
|
|
||||||
import AppStoreCard from './components/cards/appstore'
|
|
||||||
import HerokuCard from './components/cards/heroku'
|
|
||||||
import NowCard from './components/cards/now'
|
|
||||||
import NtaCard from './components/cards/nta'
|
|
||||||
|
|
||||||
import Welcome from './components/Welcome'
|
import Welcome from './components/Welcome'
|
||||||
|
import Form from './components/Form'
|
||||||
|
import Cards from './components/cards'
|
||||||
import Footer from './components/Footer'
|
import Footer from './components/Footer'
|
||||||
import Suggestion from './components/Suggestion'
|
|
||||||
|
|
||||||
import { useDeferredState } from './util/hooks'
|
|
||||||
import { mobile } from './util/css'
|
import { mobile } from './util/css'
|
||||||
import { isStandalone } from './util/pwa'
|
import { isStandalone } from './util/pwa'
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [query, setQuery] = useDeferredState(1000, '')
|
const [query, setQuery] = useState('')
|
||||||
const [inputValue, setInputValue] = useState('')
|
const { t } = useTranslation()
|
||||||
const [suggested, setSuggested] = useState(false)
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null)
|
|
||||||
const {
|
|
||||||
t,
|
|
||||||
i18n: { language },
|
|
||||||
} = useTranslation()
|
|
||||||
|
|
||||||
const queryGiven = query && query.length > 0
|
function onQuery(query: string) {
|
||||||
|
setQuery(query)
|
||||||
useEffect(() => {
|
|
||||||
const modifiedValue = inputValue.replace(/[\s@+!#$%^&*()[\]]/g, '')
|
|
||||||
setQuery(modifiedValue)
|
|
||||||
}, [inputValue, setQuery])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (query.length === 0) {
|
|
||||||
setSuggested(false)
|
|
||||||
}
|
|
||||||
}, [query])
|
|
||||||
|
|
||||||
// set input value
|
|
||||||
function onInputChange(e: React.FormEvent<HTMLInputElement>) {
|
|
||||||
const value = e.currentTarget.value
|
|
||||||
setInputValue(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear input form and focus on it
|
|
||||||
function onLogoClick(e: React.MouseEvent<HTMLDivElement>) {
|
|
||||||
setInputValue('')
|
|
||||||
inputRef.current!.focus()
|
|
||||||
}
|
|
||||||
|
|
||||||
// invoke when user clicked one of the suggested items
|
|
||||||
function onSuggestionCompleted(name: string) {
|
|
||||||
setInputValue(name)
|
|
||||||
setSuggested(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<GlobalStyle />
|
<GlobalStyle />
|
||||||
|
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>namae — {t('title')}</title>
|
<title>namae — {t('title')}</title>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
|
|
||||||
<Header>
|
<Header>
|
||||||
<InputContainer>
|
<Form onQuery={onQuery} />
|
||||||
<Logo onClick={onLogoClick}>namæ</Logo>
|
|
||||||
<InputView
|
|
||||||
onChange={onInputChange}
|
|
||||||
value={inputValue}
|
|
||||||
ref={inputRef}
|
|
||||||
placeholder={t('placeholder')}
|
|
||||||
aria-label="search query"
|
|
||||||
/>
|
|
||||||
{queryGiven && !suggested ? (
|
|
||||||
<Suggestion onSubmit={onSuggestionCompleted} query={query} />
|
|
||||||
) : null}
|
|
||||||
</InputContainer>
|
|
||||||
</Header>
|
</Header>
|
||||||
|
|
||||||
<Content>
|
<Content>
|
||||||
{queryGiven ? (
|
{query !== '' ? (
|
||||||
<SearchResult>
|
<Cards query={query} />
|
||||||
<Cards>
|
|
||||||
<DomainCard query={query} />
|
|
||||||
<GithubCard query={query} />
|
|
||||||
<NpmCard query={query} />
|
|
||||||
<PypiCard query={query} />
|
|
||||||
<RubyGemsCard query={query} />
|
|
||||||
<CratesioCard query={query} />
|
|
||||||
<HomebrewCard query={query} />
|
|
||||||
<LinuxCard query={query} />
|
|
||||||
<TwitterCard query={query} />
|
|
||||||
<SpectrumCard query={query} />
|
|
||||||
<SlackCard query={query} />
|
|
||||||
<HerokuCard query={query} />
|
|
||||||
<NowCard query={query} />
|
|
||||||
<JsOrgCard query={query} />
|
|
||||||
<S3Card query={query} />
|
|
||||||
</Cards>
|
|
||||||
<Cards>
|
|
||||||
<GithubSearchCard query={query} />
|
|
||||||
<AppStoreCard query={query} />
|
|
||||||
{language === 'ja' ? <NtaCard query={query} /> : null}
|
|
||||||
</Cards>
|
|
||||||
</SearchResult>
|
|
||||||
) : (
|
) : (
|
||||||
!isStandalone() && <Welcome />
|
!isStandalone() && <Welcome />
|
||||||
)}
|
)}
|
||||||
</Content>
|
</Content>
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
@ -171,62 +80,3 @@ const Header = styled.header`
|
|||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const InputContainer = styled.div`
|
|
||||||
transform: translateY(40px);
|
|
||||||
padding: 20px;
|
|
||||||
background: #ffffff;
|
|
||||||
box-shadow: 0 10px 20px 0 #c7dcf7;
|
|
||||||
border-radius: 20px;
|
|
||||||
|
|
||||||
${mobile} {
|
|
||||||
transform: translateY(20px);
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const Logo = styled.div`
|
|
||||||
margin-bottom: 5px;
|
|
||||||
text-align: center;
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 20px;
|
|
||||||
color: #4a90e2;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
${mobile} {
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const InputView = styled.input.attrs({
|
|
||||||
type: 'text',
|
|
||||||
autocomplete: 'off',
|
|
||||||
autocorrect: 'off',
|
|
||||||
autocapitalize: 'off',
|
|
||||||
spellcheck: 'false',
|
|
||||||
})`
|
|
||||||
width: 100%;
|
|
||||||
border: none;
|
|
||||||
outline: none;
|
|
||||||
text-align: center;
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 5rem;
|
|
||||||
line-height: 1.2em;
|
|
||||||
|
|
||||||
${mobile} {
|
|
||||||
font-size: 2rem;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const SearchResult = styled.div``
|
|
||||||
|
|
||||||
const Cards = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
${mobile} {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
112
web/src/components/Form.tsx
Normal file
112
web/src/components/Form.tsx
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
import React, { useState, useRef, useEffect } from 'react'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
import { useDeferredState } from '../util/hooks'
|
||||||
|
import { mobile } from '../util/css'
|
||||||
|
|
||||||
|
import Suggestion from './Suggestion'
|
||||||
|
|
||||||
|
const Form: React.FC<{ onQuery: (query: string) => void }> = ({ onQuery }) => {
|
||||||
|
const [query, setQuery] = useDeferredState(800, '')
|
||||||
|
const [inputValue, setInputValue] = useState('')
|
||||||
|
const [suggested, setSuggested] = useState(false)
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null)
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
// set input value
|
||||||
|
function onInputChange(e: React.FormEvent<HTMLInputElement>) {
|
||||||
|
const value = e.currentTarget.value
|
||||||
|
setInputValue(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear input form and focus on it
|
||||||
|
function onLogoClick(e: React.MouseEvent<HTMLDivElement>) {
|
||||||
|
setInputValue('')
|
||||||
|
inputRef.current!.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
// invoke when user clicked one of the suggested items
|
||||||
|
function onSuggestionCompleted(name: string) {
|
||||||
|
setInputValue(name)
|
||||||
|
setSuggested(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryGiven = query && query.length > 0
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (query.length === 0) {
|
||||||
|
setSuggested(false)
|
||||||
|
}
|
||||||
|
onQuery(query)
|
||||||
|
}, [query, onQuery])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const modifiedValue = inputValue.replace(/[\s@+!#$%^&*()[\]]/g, '')
|
||||||
|
setQuery(modifiedValue)
|
||||||
|
}, [inputValue, setQuery])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InputContainer>
|
||||||
|
<Logo onClick={onLogoClick}>namæ</Logo>
|
||||||
|
<InputView
|
||||||
|
onChange={onInputChange}
|
||||||
|
value={inputValue}
|
||||||
|
ref={inputRef}
|
||||||
|
placeholder={t('placeholder')}
|
||||||
|
aria-label="search query"
|
||||||
|
/>
|
||||||
|
{queryGiven && !suggested ? (
|
||||||
|
<Suggestion onSubmit={onSuggestionCompleted} query={query} />
|
||||||
|
) : null}
|
||||||
|
</InputContainer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Form
|
||||||
|
|
||||||
|
const InputContainer = styled.div`
|
||||||
|
transform: translateY(40px);
|
||||||
|
padding: 20px;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0 10px 20px 0 #c7dcf7;
|
||||||
|
border-radius: 20px;
|
||||||
|
|
||||||
|
${mobile} {
|
||||||
|
transform: translateY(20px);
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const Logo = styled.div`
|
||||||
|
margin-bottom: 5px;
|
||||||
|
text-align: center;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #4a90e2;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
${mobile} {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const InputView = styled.input.attrs({
|
||||||
|
type: 'text',
|
||||||
|
autocomplete: 'off',
|
||||||
|
autocorrect: 'off',
|
||||||
|
autocapitalize: 'off',
|
||||||
|
spellcheck: 'false',
|
||||||
|
})`
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
text-align: center;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 5rem;
|
||||||
|
line-height: 1.2em;
|
||||||
|
|
||||||
|
${mobile} {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
`
|
@ -3,7 +3,7 @@ import useFetch from 'fetch-suspense'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FaAppStore, FaInfoCircle } from 'react-icons/fa'
|
import { FaAppStore, FaInfoCircle } from 'react-icons/fa'
|
||||||
|
|
||||||
import { Card, Result } from '../Cards'
|
import { Card, Result } from './core'
|
||||||
|
|
||||||
const Search: React.FC<{ query: string }> = ({ query }) => {
|
const Search: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { DiRust } from 'react-icons/di'
|
import { DiRust } from 'react-icons/di'
|
||||||
|
|
||||||
import { Card, Repeater, DedicatedAvailability } from '../Cards'
|
import { Card, Repeater, DedicatedAvailability } from './core'
|
||||||
|
|
||||||
const CratesioCard: React.FC<{ query: string }> = ({ query }) => {
|
const CratesioCard: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FaMapSigns } from 'react-icons/fa'
|
import { FaMapSigns } from 'react-icons/fa'
|
||||||
|
|
||||||
import { Card, Repeater, DedicatedAvailability } from '../Cards'
|
import { Card, Repeater, DedicatedAvailability } from './core'
|
||||||
|
|
||||||
const DomainCard: React.FC<{ query: string }> = ({ query }) => {
|
const DomainCard: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FaGithub } from 'react-icons/fa'
|
import { FaGithub } from 'react-icons/fa'
|
||||||
|
|
||||||
import { Card, Repeater, DedicatedAvailability } from '../Cards'
|
import { Card, Repeater, DedicatedAvailability } from './core'
|
||||||
|
|
||||||
const GithubCard: React.FC<{ query: string }> = ({ query }) => {
|
const GithubCard: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -3,7 +3,7 @@ import useFetch from 'fetch-suspense'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FaGithub, FaInfoCircle } from 'react-icons/fa'
|
import { FaGithub, FaInfoCircle } from 'react-icons/fa'
|
||||||
|
|
||||||
import { Card, Result } from '../Cards'
|
import { Card, Result } from './core'
|
||||||
|
|
||||||
const Search: React.FC<{ query: string }> = ({ query }) => {
|
const Search: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { DiHeroku } from 'react-icons/di'
|
import { DiHeroku } from 'react-icons/di'
|
||||||
|
|
||||||
import { Card, Repeater, DedicatedAvailability } from '../Cards'
|
import { Card, Repeater, DedicatedAvailability } from './core'
|
||||||
|
|
||||||
const HerokuCard: React.FC<{ query: string }> = ({ query }) => {
|
const HerokuCard: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { IoIosBeer } from 'react-icons/io'
|
import { IoIosBeer } from 'react-icons/io'
|
||||||
|
|
||||||
import { Card, Repeater, ExistentialAvailability } from '../Cards'
|
import { Card, Repeater, ExistentialAvailability } from './core'
|
||||||
|
|
||||||
const HomebrewCard: React.FC<{ query: string }> = ({ query }) => {
|
const HomebrewCard: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FaJsSquare } from 'react-icons/fa'
|
import { FaJsSquare } from 'react-icons/fa'
|
||||||
|
|
||||||
import { Card, Repeater, DedicatedAvailability } from '../Cards'
|
import { Card, Repeater, DedicatedAvailability } from './core'
|
||||||
|
|
||||||
const JsOrgCard: React.FC<{ query: string }> = ({ query }) => {
|
const JsOrgCard: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { DiUbuntu } from 'react-icons/di'
|
import { DiUbuntu } from 'react-icons/di'
|
||||||
import { DiDebian } from 'react-icons/di'
|
import { DiDebian } from 'react-icons/di'
|
||||||
|
|
||||||
import { Card, Repeater, DedicatedAvailability } from '../Cards'
|
import { Card, Repeater, DedicatedAvailability } from './core'
|
||||||
|
|
||||||
const LinuxCard: React.FC<{ query: string }> = ({ query }) => {
|
const LinuxCard: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { NowIcon } from '../Icons'
|
import { NowIcon } from '../Icons'
|
||||||
|
|
||||||
import { Card, Repeater, DedicatedAvailability } from '../Cards'
|
import { Card, Repeater, DedicatedAvailability } from './core'
|
||||||
|
|
||||||
const NowCard: React.FC<{ query: string }> = ({ query }) => {
|
const NowCard: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FaNpm } from 'react-icons/fa'
|
import { FaNpm } from 'react-icons/fa'
|
||||||
|
|
||||||
import { Card, Repeater, DedicatedAvailability } from '../Cards'
|
import { Card, Repeater, DedicatedAvailability } from './core'
|
||||||
|
|
||||||
const NpmCard: React.FC<{ query: string }> = ({ query }) => {
|
const NpmCard: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -3,7 +3,7 @@ import useFetch from 'fetch-suspense'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FaBuilding, FaInfoCircle } from 'react-icons/fa'
|
import { FaBuilding, FaInfoCircle } from 'react-icons/fa'
|
||||||
|
|
||||||
import { Card, Result } from '../Cards'
|
import { Card, Result } from './core'
|
||||||
|
|
||||||
const Search: React.FC<{ query: string }> = ({ query }) => {
|
const Search: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { FaPython } from 'react-icons/fa'
|
import { FaPython } from 'react-icons/fa'
|
||||||
|
|
||||||
import { capitalize } from '../../util/text'
|
import { capitalize } from '../../util/text'
|
||||||
import { Card, DedicatedAvailability, Repeater } from '../Cards'
|
import { Card, DedicatedAvailability, Repeater } from './core'
|
||||||
|
|
||||||
const PypiCard: React.FC<{ query: string }> = ({ query }) => {
|
const PypiCard: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FaGem } from 'react-icons/fa'
|
import { FaGem } from 'react-icons/fa'
|
||||||
|
|
||||||
import { Card, Repeater, DedicatedAvailability } from '../Cards'
|
import { Card, Repeater, DedicatedAvailability } from './core'
|
||||||
|
|
||||||
const RubyGemsCard: React.FC<{ query: string }> = ({ query }) => {
|
const RubyGemsCard: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FaAws } from 'react-icons/fa'
|
import { FaAws } from 'react-icons/fa'
|
||||||
|
|
||||||
import { Card, DedicatedAvailability, Repeater } from '../Cards'
|
import { Card, DedicatedAvailability, Repeater } from './core'
|
||||||
|
|
||||||
const S3Card: React.FC<{ query: string }> = ({ query }) => {
|
const S3Card: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FaSlack } from 'react-icons/fa'
|
import { FaSlack } from 'react-icons/fa'
|
||||||
|
|
||||||
import { Card, DedicatedAvailability, Repeater } from '../Cards'
|
import { Card, DedicatedAvailability, Repeater } from './core'
|
||||||
|
|
||||||
const SlackCard: React.FC<{ query: string }> = ({ query }) => {
|
const SlackCard: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Card, Repeater, DedicatedAvailability } from '../Cards'
|
import { Card, Repeater, DedicatedAvailability } from './core'
|
||||||
import { SpectrumIcon } from '../Icons'
|
import { SpectrumIcon } from '../Icons'
|
||||||
|
|
||||||
const SpectrumCard: React.FC<{ query: string }> = ({ query }) => {
|
const SpectrumCard: React.FC<{ query: string }> = ({ query }) => {
|
@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { FaTwitter } from 'react-icons/fa'
|
import { FaTwitter } from 'react-icons/fa'
|
||||||
|
|
||||||
import { capitalize } from '../../util/text'
|
import { capitalize } from '../../util/text'
|
||||||
import { Card, Repeater, DedicatedAvailability } from '../Cards'
|
import { Card, Repeater, DedicatedAvailability } from './core'
|
||||||
|
|
||||||
const TwitterCard: React.FC<{ query: string }> = ({ query }) => {
|
const TwitterCard: React.FC<{ query: string }> = ({ query }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
@ -7,8 +7,8 @@ import BarLoader from 'react-spinners/BarLoader'
|
|||||||
import { GoInfo } from 'react-icons/go'
|
import { GoInfo } from 'react-icons/go'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
import { ExternalLink } from './Links'
|
import { mobile } from '../../util/css'
|
||||||
import { mobile } from '../util/css'
|
import { ExternalLink } from '../Links'
|
||||||
|
|
||||||
const COLORS = {
|
const COLORS = {
|
||||||
available: '#6e00ff',
|
available: '#6e00ff',
|
69
web/src/components/cards/index.tsx
Normal file
69
web/src/components/cards/index.tsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
|
import { mobile } from '../../util/css'
|
||||||
|
import DomainCard from './Domains'
|
||||||
|
import GithubCard from './GitHubRepository'
|
||||||
|
import NpmCard from './Npm'
|
||||||
|
import PypiCard from './PyPI'
|
||||||
|
import RubyGemsCard from './RubyGems'
|
||||||
|
import CratesioCard from './Cratesio'
|
||||||
|
import HomebrewCard from './Homebrew'
|
||||||
|
import LinuxCard from './Linux'
|
||||||
|
import TwitterCard from './Twitter'
|
||||||
|
import SpectrumCard from './Spectrum'
|
||||||
|
import SlackCard from './Slack'
|
||||||
|
import S3Card from './S3'
|
||||||
|
import JsOrgCard from './JsOrg'
|
||||||
|
import GithubSearchCard from './GitHubSearch'
|
||||||
|
import AppStoreCard from './AppStore'
|
||||||
|
import HerokuCard from './Heroku'
|
||||||
|
import NowCard from './Now'
|
||||||
|
import NtaCard from './Nta'
|
||||||
|
|
||||||
|
const Index: React.FC<{ query: string }> = ({ query }) => {
|
||||||
|
const {
|
||||||
|
i18n: { language },
|
||||||
|
} = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Cards>
|
||||||
|
<DomainCard query={query} />
|
||||||
|
<GithubCard query={query} />
|
||||||
|
<NpmCard query={query} />
|
||||||
|
<PypiCard query={query} />
|
||||||
|
<RubyGemsCard query={query} />
|
||||||
|
<CratesioCard query={query} />
|
||||||
|
<HomebrewCard query={query} />
|
||||||
|
<LinuxCard query={query} />
|
||||||
|
<TwitterCard query={query} />
|
||||||
|
<SpectrumCard query={query} />
|
||||||
|
<SlackCard query={query} />
|
||||||
|
<HerokuCard query={query} />
|
||||||
|
<NowCard query={query} />
|
||||||
|
<JsOrgCard query={query} />
|
||||||
|
<S3Card query={query} />
|
||||||
|
</Cards>
|
||||||
|
<Cards>
|
||||||
|
<GithubSearchCard query={query} />
|
||||||
|
<AppStoreCard query={query} />
|
||||||
|
{language === 'ja' ? <NtaCard query={query} /> : null}
|
||||||
|
</Cards>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Index
|
||||||
|
|
||||||
|
const Cards = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
${mobile} {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
`
|
Loading…
x
Reference in New Issue
Block a user