1
0
mirror of https://github.com/uetchy/namae.git synced 2025-07-02 06:20:02 +09:00
namae/src/App.tsx

207 lines
4.5 KiB
TypeScript
Raw Normal View History

2020-06-20 18:19:05 +09:00
import Tooltip from 'rc-tooltip';
2020-06-29 12:24:01 +09:00
import React from 'react';
import { Helmet } from 'react-helmet';
import { useTranslation } from 'react-i18next';
import { IoIosFlash, IoIosRocket } from 'react-icons/io';
import { Redirect, Route, Switch, useParams } from 'react-router-dom';
import styled, { createGlobalStyle } from 'styled-components';
2019-09-17 14:30:26 +09:00
import Cards from './components/cards';
2020-03-26 15:34:34 +09:00
import {
2020-06-29 12:24:01 +09:00
AvailableIcon,
COLORS as ResultColor,
2020-03-26 15:34:34 +09:00
ResultIcon,
2020-06-29 12:24:01 +09:00
ResultItem,
2020-03-26 15:34:34 +09:00
ResultName,
} from './components/cards/core';
2020-06-29 12:24:01 +09:00
import Footer from './components/Footer';
import Form from './components/Form';
import Welcome from './components/Welcome';
import { useStoreState } from './store';
import { mobile } from './util/css';
import { isStandalone } from './util/pwa';
import { sanitize } from './util/text';
2019-08-03 00:35:47 +09:00
2019-07-30 23:27:28 +09:00
export default function App() {
2020-02-05 15:59:53 +09:00
return (
<>
<GlobalStyle />
2020-05-26 21:00:01 +09:00
<Helmet>
<link
rel="search"
type="application/opensearchdescription+xml"
title="namae"
href="/opensearch.xml"
/>
</Helmet>
2020-02-05 15:59:53 +09:00
<Switch>
2020-02-05 17:28:22 +09:00
<Route exact path="/">
<Home />
</Route>
2020-02-05 15:59:53 +09:00
<Route path="/s/:query">
<Search />
</Route>
2020-02-05 17:28:22 +09:00
<Route path="*">
<Redirect to="/" />
2020-02-05 15:59:53 +09:00
</Route>
</Switch>
{!isStandalone() && <Footer />}
2020-02-05 15:59:53 +09:00
</>
);
}
2020-03-05 22:09:12 +09:00
function Home() {
2020-06-29 12:24:01 +09:00
const { t } = useTranslation();
2019-08-03 16:44:48 +09:00
2019-07-27 19:18:54 +09:00
return (
<>
2019-08-03 13:36:29 +09:00
<Helmet>
2020-03-05 22:09:12 +09:00
<title>namae {t('title')}</title>
2019-08-03 13:36:29 +09:00
</Helmet>
2019-08-02 04:23:21 +09:00
<Header>
2020-03-05 22:09:12 +09:00
<Form />
2019-08-02 04:23:21 +09:00
</Header>
<Content>
2020-03-05 22:09:12 +09:00
<Welcome />
</Content>
2020-02-05 15:59:53 +09:00
</>
);
}
2020-03-05 22:09:12 +09:00
function Search() {
2020-06-29 12:24:01 +09:00
const { query } = useParams<{ query: string }>();
2020-03-05 22:09:12 +09:00
const currentQuery = sanitize(query);
2020-06-29 12:24:01 +09:00
const { t } = useTranslation();
2020-02-05 15:59:53 +09:00
return (
<>
<Helmet>
2020-03-05 22:09:12 +09:00
<title>Search for &quot;{currentQuery}&quot; namae</title>
2020-02-05 15:59:53 +09:00
</Helmet>
<Header>
2020-03-05 22:09:12 +09:00
<Form initialValue={currentQuery} />
2020-02-05 15:59:53 +09:00
</Header>
<Content>
2020-03-26 16:32:52 +09:00
<Legend>
2020-03-26 20:22:06 +09:00
<Stat />
<ResultItem color={ResultColor.available}>
2020-03-26 16:32:52 +09:00
<ResultIcon>
<IoIosRocket />
</ResultIcon>
<ResultName>{t('available')}</ResultName>
<AvailableIcon>
<IoIosFlash />
</AvailableIcon>
</ResultItem>
2020-03-26 20:22:06 +09:00
<ResultItem color={ResultColor.unavailable}>
2020-03-26 16:32:52 +09:00
<ResultIcon>
<IoIosRocket />
</ResultIcon>
<ResultName>{t('unavailable')}</ResultName>
</ResultItem>
</Legend>
2020-03-05 22:09:12 +09:00
<Cards query={currentQuery} />
</Content>
</>
2019-09-17 14:30:26 +09:00
);
2019-07-27 19:18:54 +09:00
}
2020-03-26 20:22:06 +09:00
function Stat() {
const totalCount = useStoreState((state) => state.stats.totalCount);
const availableCount = useStoreState((state) => state.stats.availableCount);
2020-06-29 12:24:01 +09:00
const { t } = useTranslation();
2020-03-26 20:22:06 +09:00
2020-06-20 18:19:05 +09:00
const uniqueness = availableCount !== 0 ? availableCount / totalCount : 0.0;
2020-04-30 14:05:43 +09:00
const uniquenessText = ((n) => {
2020-03-26 20:22:06 +09:00
if (n > 0.7 && n <= 1.0) {
return t('uniqueness.high');
} else if (n > 0.4 && n <= 0.7) {
return t('uniqueness.moderate');
} else {
return t('uniqueness.low');
}
2020-04-30 14:05:43 +09:00
})(uniqueness);
2020-03-26 20:22:06 +09:00
2020-04-30 14:05:43 +09:00
return (
<UniquenessIndicator>
2020-06-20 18:19:05 +09:00
<Tooltip
overlay={t('uniqueness.description')}
placement="top"
2020-06-29 12:24:01 +09:00
trigger={['hover']}>
2020-06-20 18:19:05 +09:00
<span>
{uniquenessText} ({(uniqueness * 100).toFixed(1)} UNIQ)
</span>
</Tooltip>
2020-04-30 14:05:43 +09:00
</UniquenessIndicator>
);
2020-03-26 20:22:06 +09:00
}
const GlobalStyle = createGlobalStyle`
2019-08-01 13:21:23 +09:00
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
2020-02-06 13:16:30 +09:00
font-size: 100%;
2019-08-01 13:21:23 +09:00
}
body {
2019-08-01 13:21:23 +09:00
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
2020-02-06 13:16:30 +09:00
line-height: 1.625em;
2019-08-01 13:21:23 +09:00
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
2019-08-02 04:23:21 +09:00
background: #ffffff;
2020-03-26 15:34:34 +09:00
2019-08-02 04:23:21 +09:00
${mobile} {
background: #f5f5f5;
}
}
2019-09-17 14:30:26 +09:00
`;
2019-08-02 04:23:21 +09:00
const Content = styled.div`
2020-03-26 16:32:52 +09:00
padding-top: 100px;
2019-08-02 04:23:21 +09:00
${mobile} {
2020-03-26 16:32:52 +09:00
padding-top: 60px;
2019-08-02 04:23:21 +09:00
}
2019-09-17 14:30:26 +09:00
`;
2019-08-01 01:48:55 +09:00
2019-07-31 03:43:13 +09:00
const Header = styled.header`
2019-08-01 02:30:35 +09:00
padding: 0 40px;
2020-02-06 17:21:22 +09:00
background-image: linear-gradient(180deg, #bda2ff 0%, #1b24cc 99%);
2019-08-01 01:48:55 +09:00
${mobile} {
2019-08-01 02:30:35 +09:00
padding: 0 20px;
2019-08-01 01:48:55 +09:00
}
2019-09-17 14:30:26 +09:00
`;
2020-03-26 16:32:52 +09:00
const Legend = styled.div`
margin-top: -100px;
2020-03-26 16:48:05 +09:00
padding: 100px 0 30px;
2020-03-26 16:32:52 +09:00
display: flex;
flex-direction: row;
justify-content: center;
user-select: none;
cursor: default;
background-color: #f6f6fa;
${mobile} {
2020-03-26 20:22:06 +09:00
flex-direction: column;
align-items: center;
2020-03-26 16:32:52 +09:00
margin-top: -80px;
2020-03-26 16:48:05 +09:00
padding: 70px 0 30px;
2020-03-26 16:32:52 +09:00
background-color: none;
}
2020-03-26 20:22:06 +09:00
> * {
2020-03-26 16:32:52 +09:00
margin: 0 10px 0;
}
`;
2020-03-26 20:22:06 +09:00
const UniquenessIndicator = styled.div`
color: #7b7b7b;
`;