mirror of
https://github.com/uetchy/namae.git
synced 2025-03-17 04:30:31 +09:00
feat: refine footer
This commit is contained in:
parent
04725d0a65
commit
0d632a8eb2
195
src/App.tsx
195
src/App.tsx
@ -1,206 +1,35 @@
|
|||||||
import Tooltip from 'rc-tooltip';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Helmet } from 'react-helmet';
|
import { Redirect, Route, Switch } from 'react-router-dom';
|
||||||
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';
|
|
||||||
import Cards from './components/cards';
|
|
||||||
import {
|
|
||||||
AvailableIcon,
|
|
||||||
COLORS as ResultColor,
|
|
||||||
ResultIcon,
|
|
||||||
ResultItem,
|
|
||||||
ResultName,
|
|
||||||
} from './components/cards/core';
|
|
||||||
import Footer from './components/Footer';
|
import Footer from './components/Footer';
|
||||||
import Form from './components/Form';
|
import Home from './pages/Home';
|
||||||
import Welcome from './components/Welcome';
|
import Search from './pages/Search';
|
||||||
import { useStoreState } from './store';
|
import { GlobalStyle } from './theme';
|
||||||
import { mobile } from './util/css';
|
import { useOpenSearch } from './util/hooks';
|
||||||
import { isStandalone } from './util/pwa';
|
import { isStandalone } from './util/pwa';
|
||||||
import { sanitize } from './util/text';
|
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
|
const OpenSearch = useOpenSearch('/opensearch.xml');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<GlobalStyle />
|
<GlobalStyle />
|
||||||
<Helmet>
|
<OpenSearch />
|
||||||
<link
|
|
||||||
rel="search"
|
|
||||||
type="application/opensearchdescription+xml"
|
|
||||||
title="namae"
|
|
||||||
href="/opensearch.xml"
|
|
||||||
/>
|
|
||||||
</Helmet>
|
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path="/">
|
<Route exact path="/">
|
||||||
<Home />
|
<Home />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
<Route path="/s/:query">
|
<Route path="/s/:query">
|
||||||
<Search />
|
<Search />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
<Route path="*">
|
<Route path="*">
|
||||||
<Redirect to="/" />
|
<Redirect to="/" />
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
|
|
||||||
{!isStandalone() && <Footer />}
|
{!isStandalone() && <Footer />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Home() {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Helmet>
|
|
||||||
<title>namae — {t('title')}</title>
|
|
||||||
</Helmet>
|
|
||||||
<Header>
|
|
||||||
<Form />
|
|
||||||
</Header>
|
|
||||||
<Content>
|
|
||||||
<Welcome />
|
|
||||||
</Content>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Search() {
|
|
||||||
const { query } = useParams<{ query: string }>();
|
|
||||||
const currentQuery = sanitize(query);
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Helmet>
|
|
||||||
<title>Search for "{currentQuery}" — namae</title>
|
|
||||||
</Helmet>
|
|
||||||
<Header>
|
|
||||||
<Form initialValue={currentQuery} />
|
|
||||||
</Header>
|
|
||||||
<Content>
|
|
||||||
<Legend>
|
|
||||||
<Stat />
|
|
||||||
<ResultItem color={ResultColor.available}>
|
|
||||||
<ResultIcon>
|
|
||||||
<IoIosRocket />
|
|
||||||
</ResultIcon>
|
|
||||||
<ResultName>{t('available')}</ResultName>
|
|
||||||
<AvailableIcon>
|
|
||||||
<IoIosFlash />
|
|
||||||
</AvailableIcon>
|
|
||||||
</ResultItem>
|
|
||||||
<ResultItem color={ResultColor.unavailable}>
|
|
||||||
<ResultIcon>
|
|
||||||
<IoIosRocket />
|
|
||||||
</ResultIcon>
|
|
||||||
<ResultName>{t('unavailable')}</ResultName>
|
|
||||||
</ResultItem>
|
|
||||||
</Legend>
|
|
||||||
<Cards query={currentQuery} />
|
|
||||||
</Content>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function Stat() {
|
|
||||||
const totalCount = useStoreState((state) => state.stats.totalCount);
|
|
||||||
const availableCount = useStoreState((state) => state.stats.availableCount);
|
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
const uniqueness = availableCount !== 0 ? availableCount / totalCount : 0.0;
|
|
||||||
const uniquenessText = ((n) => {
|
|
||||||
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');
|
|
||||||
}
|
|
||||||
})(uniqueness);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<UniquenessIndicator>
|
|
||||||
<Tooltip
|
|
||||||
overlay={t('uniqueness.description')}
|
|
||||||
placement="top"
|
|
||||||
trigger={['hover']}>
|
|
||||||
<span>
|
|
||||||
{uniquenessText} ({(uniqueness * 100).toFixed(1)} UNIQ)
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
</UniquenessIndicator>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const GlobalStyle = createGlobalStyle`
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-size: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
||||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
||||||
sans-serif;
|
|
||||||
line-height: 1.625em;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
background: #ffffff;
|
|
||||||
|
|
||||||
${mobile} {
|
|
||||||
background: #f5f5f5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Content = styled.div`
|
|
||||||
padding-top: 100px;
|
|
||||||
|
|
||||||
${mobile} {
|
|
||||||
padding-top: 60px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Header = styled.header`
|
|
||||||
padding: 0 40px;
|
|
||||||
background-image: linear-gradient(180deg, #bda2ff 0%, #1b24cc 99%);
|
|
||||||
|
|
||||||
${mobile} {
|
|
||||||
padding: 0 20px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Legend = styled.div`
|
|
||||||
margin-top: -100px;
|
|
||||||
padding: 100px 0 30px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
user-select: none;
|
|
||||||
cursor: default;
|
|
||||||
background-color: #f6f6fa;
|
|
||||||
|
|
||||||
${mobile} {
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
margin-top: -80px;
|
|
||||||
padding: 70px 0 30px;
|
|
||||||
background-color: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
> * {
|
|
||||||
margin: 0 10px 0;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const UniquenessIndicator = styled.div`
|
|
||||||
color: #7b7b7b;
|
|
||||||
`;
|
|
||||||
|
@ -2,27 +2,72 @@ import React from 'react';
|
|||||||
import { OutboundLink } from 'react-ga';
|
import { OutboundLink } from 'react-ga';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { FaGithub, FaProductHunt, FaTwitter } from 'react-icons/fa';
|
import { FaGithub, FaProductHunt, FaTwitter } from 'react-icons/fa';
|
||||||
|
import { GoHeart } from 'react-icons/go';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
import { Section } from '../theme';
|
||||||
|
import { mobile } from '../util/css';
|
||||||
|
|
||||||
const Footer: React.FC = () => {
|
const Footer: React.FC = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<LangBox>
|
<Pane>
|
||||||
<a href="/?lng=en">
|
<Title>Language</Title>
|
||||||
<span role="img" aria-label="English">
|
<LangBox>
|
||||||
🇬🇧
|
<Links>
|
||||||
</span>
|
<a href="/?lng=en">
|
||||||
</a>
|
<span role="img" aria-label="English">
|
||||||
<a href="/?lng=ja">
|
🇬🇧
|
||||||
<span role="img" aria-label="Japanese">
|
</span>
|
||||||
🇯🇵
|
</a>
|
||||||
</span>
|
<a href="/?lng=ja">
|
||||||
</a>
|
<span role="img" aria-label="Japanese">
|
||||||
</LangBox>
|
🇯🇵
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</Links>
|
||||||
|
</LangBox>
|
||||||
|
</Pane>
|
||||||
|
|
||||||
<Box>
|
<Pane>
|
||||||
|
<Title>Community</Title>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<OutboundLink
|
||||||
|
to="https://github.com/uetchy/namae"
|
||||||
|
eventLabel="GitHub Repo"
|
||||||
|
aria-label="Go to GitHub repository"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
GitHub
|
||||||
|
</OutboundLink>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<OutboundLink
|
||||||
|
to="https://github.com/uetchy/namae/issues"
|
||||||
|
eventLabel="GitHub Issues"
|
||||||
|
aria-label="Go to GitHub Issues"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Issues
|
||||||
|
</OutboundLink>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<OutboundLink
|
||||||
|
to="https://dev.to/uetchy/give-your-app-slick-name-with-namae-dev-5c4h"
|
||||||
|
eventLabel="Blog article"
|
||||||
|
aria-label="Go to blog"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Blog Article
|
||||||
|
</OutboundLink>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</Pane>
|
||||||
|
|
||||||
|
<Pane>
|
||||||
|
<Title>About</Title>
|
||||||
<p>
|
<p>
|
||||||
Made with{' '}
|
Made with{' '}
|
||||||
<span role="img" aria-label="coffee">
|
<span role="img" aria-label="coffee">
|
||||||
@ -33,74 +78,109 @@ const Footer: React.FC = () => {
|
|||||||
to="https://twitter.com/uechz"
|
to="https://twitter.com/uechz"
|
||||||
eventLabel="Author Page"
|
eventLabel="Author Page"
|
||||||
aria-label="Author page"
|
aria-label="Author page"
|
||||||
target="_blank">
|
target="_blank"
|
||||||
|
>
|
||||||
<Bold>Yasuaki Uechi</Bold>
|
<Bold>Yasuaki Uechi</Bold>
|
||||||
</OutboundLink>
|
</OutboundLink>
|
||||||
</p>
|
</p>
|
||||||
</Box>
|
<ShareBox>
|
||||||
|
<Links>
|
||||||
<ShareBox>
|
<OutboundLink
|
||||||
<Links>
|
to={`https://twitter.com/intent/tweet?text=${encodeURIComponent(
|
||||||
<OutboundLink
|
`namae — ${t('title')}`,
|
||||||
to={`https://twitter.com/intent/tweet?text=${encodeURIComponent(
|
)}&url=${encodeURIComponent('https://namae.dev')}`}
|
||||||
`namae — ${t('title')}`,
|
eventLabel="Tweet"
|
||||||
)}&url=${encodeURIComponent('https://namae.dev')}`}
|
aria-label="Tweet this page"
|
||||||
eventLabel="Tweet"
|
target="_blank"
|
||||||
aria-label="Tweet this page"
|
>
|
||||||
target="_blank">
|
<FaTwitter />
|
||||||
<FaTwitter />
|
</OutboundLink>
|
||||||
</OutboundLink>
|
<OutboundLink
|
||||||
<OutboundLink
|
to="https://www.producthunt.com/posts/namae"
|
||||||
to="https://www.producthunt.com/posts/namae"
|
eventLabel="ProductHunt"
|
||||||
eventLabel="ProductHunt"
|
aria-label="Go to ProductHunt page"
|
||||||
aria-label="Go to ProductHunt page"
|
target="_blank"
|
||||||
target="_blank">
|
>
|
||||||
<FaProductHunt />
|
<FaProductHunt />
|
||||||
</OutboundLink>
|
</OutboundLink>
|
||||||
<OutboundLink
|
<OutboundLink
|
||||||
to="https://github.com/uetchy/namae"
|
to="https://github.com/uetchy/namae"
|
||||||
eventLabel="GitHub Repo"
|
eventLabel="GitHub Repo"
|
||||||
aria-label="Go to GitHub repository"
|
aria-label="Go to GitHub repository"
|
||||||
target="_blank">
|
target="_blank"
|
||||||
<FaGithub />
|
>
|
||||||
</OutboundLink>
|
<FaGithub />
|
||||||
</Links>
|
</OutboundLink>
|
||||||
</ShareBox>
|
<OutboundLink
|
||||||
|
to="https://github.com/sponsors/uetchy"
|
||||||
|
eventLabel="GitHub Sponsors"
|
||||||
|
aria-label="Go to GitHub Sponsors"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<SponsorBadge>
|
||||||
|
<GoHeart size="1.3rem" />
|
||||||
|
<span>Sponsor</span>
|
||||||
|
</SponsorBadge>
|
||||||
|
</OutboundLink>
|
||||||
|
</Links>
|
||||||
|
</ShareBox>
|
||||||
|
</Pane>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default Footer;
|
export default Footer;
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled(Section)`
|
||||||
|
--text: #bdbdbd;
|
||||||
|
--background: #404040;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
align-items: center;
|
justify-content: space-around;
|
||||||
margin: 40px 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
|
||||||
Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
background: var(--background);
|
||||||
|
color: var(--text);
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: black;
|
color: var(--text);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
li {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${mobile} {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Box = styled.footer`
|
const Pane = styled.div`
|
||||||
margin-bottom: 10px;
|
font-size: 1rem;
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
${mobile} {
|
||||||
justify-content: center;
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Title = styled.h3`
|
||||||
|
margin-bottom: 15px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const LangBox = styled.div`
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
font-size: 0.8rem;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const LangBox = styled(Box)`
|
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
margin-bottom: 20px;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ShareBox = styled(Box)`
|
const ShareBox = styled.div`
|
||||||
|
margin-top: 15px;
|
||||||
|
line-height: 1em;
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Links = styled.div`
|
const Links = styled.div`
|
||||||
@ -108,10 +188,35 @@ const Links = styled.div`
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
a {
|
a {
|
||||||
margin: 0 3px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Bold = styled.span`
|
const Bold = styled.span`
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const SponsorBadge = styled.div`
|
||||||
|
padding: 5px 13px 5px 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 1rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
color: black;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
transition: opacity 200ms ease-out;
|
||||||
|
|
||||||
|
:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
color: rgb(236, 69, 171);
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
26
src/pages/Home.tsx
Normal file
26
src/pages/Home.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Helmet } from 'react-helmet';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { Content, Header } from '../theme';
|
||||||
|
import Form from '../components/Form';
|
||||||
|
import Welcome from '../components/Welcome';
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Helmet>
|
||||||
|
<title>namae — {t('title')}</title>
|
||||||
|
</Helmet>
|
||||||
|
|
||||||
|
<Header>
|
||||||
|
<Form />
|
||||||
|
</Header>
|
||||||
|
|
||||||
|
<Content>
|
||||||
|
<Welcome />
|
||||||
|
</Content>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
116
src/pages/Search.tsx
Normal file
116
src/pages/Search.tsx
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
import Tooltip from 'rc-tooltip';
|
||||||
|
import React from 'react';
|
||||||
|
import { Helmet } from 'react-helmet';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { IoIosFlash, IoIosRocket } from 'react-icons/io';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import Cards from '../components/cards';
|
||||||
|
import {
|
||||||
|
AvailableIcon,
|
||||||
|
COLORS as ResultColor,
|
||||||
|
ResultIcon,
|
||||||
|
ResultItem,
|
||||||
|
ResultName,
|
||||||
|
} from '../components/cards/core';
|
||||||
|
import Form from '../components/Form';
|
||||||
|
import { useStoreState } from '../store';
|
||||||
|
import { Content, Header } from '../theme';
|
||||||
|
import { mobile } from '../util/css';
|
||||||
|
import { sanitize } from '../util/text';
|
||||||
|
|
||||||
|
export default function Search() {
|
||||||
|
const { query } = useParams<{ query: string }>();
|
||||||
|
const currentQuery = sanitize(query);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Helmet>
|
||||||
|
<title>Search for "{currentQuery}" — namae</title>
|
||||||
|
</Helmet>
|
||||||
|
<Header>
|
||||||
|
<Form initialValue={currentQuery} />
|
||||||
|
</Header>
|
||||||
|
<Content>
|
||||||
|
<Legend>
|
||||||
|
<Stat />
|
||||||
|
<ResultItem color={ResultColor.available}>
|
||||||
|
<ResultIcon>
|
||||||
|
<IoIosRocket />
|
||||||
|
</ResultIcon>
|
||||||
|
<ResultName>{t('available')}</ResultName>
|
||||||
|
<AvailableIcon>
|
||||||
|
<IoIosFlash />
|
||||||
|
</AvailableIcon>
|
||||||
|
</ResultItem>
|
||||||
|
<ResultItem color={ResultColor.unavailable}>
|
||||||
|
<ResultIcon>
|
||||||
|
<IoIosRocket />
|
||||||
|
</ResultIcon>
|
||||||
|
<ResultName>{t('unavailable')}</ResultName>
|
||||||
|
</ResultItem>
|
||||||
|
</Legend>
|
||||||
|
<Cards query={currentQuery} />
|
||||||
|
</Content>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Stat() {
|
||||||
|
const totalCount = useStoreState((state) => state.stats.totalCount);
|
||||||
|
const availableCount = useStoreState((state) => state.stats.availableCount);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const uniqueness = availableCount !== 0 ? availableCount / totalCount : 0.0;
|
||||||
|
const uniquenessText = ((n) => {
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
})(uniqueness);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UniquenessIndicator>
|
||||||
|
<Tooltip
|
||||||
|
overlay={t('uniqueness.description')}
|
||||||
|
placement="top"
|
||||||
|
trigger={['hover']}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
{uniquenessText} ({(uniqueness * 100).toFixed(1)} UNIQ)
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
</UniquenessIndicator>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Legend = styled.div`
|
||||||
|
margin-top: -100px;
|
||||||
|
padding: 100px 0 30px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
user-select: none;
|
||||||
|
cursor: default;
|
||||||
|
background-color: #f6f6fa;
|
||||||
|
|
||||||
|
${mobile} {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: -80px;
|
||||||
|
padding: 70px 0 30px;
|
||||||
|
background-color: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
> * {
|
||||||
|
margin: 0 10px 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const UniquenessIndicator = styled.div`
|
||||||
|
color: #7b7b7b;
|
||||||
|
`;
|
53
src/theme/index.tsx
Normal file
53
src/theme/index.tsx
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import styled, { createGlobalStyle } from 'styled-components';
|
||||||
|
import { mobile } from '../util/css';
|
||||||
|
|
||||||
|
export const GlobalStyle = createGlobalStyle`
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||||
|
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||||
|
sans-serif;
|
||||||
|
line-height: 1.625em;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
background: #ffffff;
|
||||||
|
|
||||||
|
${mobile} {
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const Content = styled.div`
|
||||||
|
padding-top: 100px;
|
||||||
|
|
||||||
|
${mobile} {
|
||||||
|
padding-top: 60px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const Header = styled.header`
|
||||||
|
padding: 0 40px;
|
||||||
|
background-image: linear-gradient(180deg, #bda2ff 0%, #1b24cc 99%);
|
||||||
|
|
||||||
|
${mobile} {
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const Section = styled.div`
|
||||||
|
padding: 100px 20vw;
|
||||||
|
|
||||||
|
${mobile} {
|
||||||
|
padding: 60px 40px;
|
||||||
|
}
|
||||||
|
`;
|
@ -1,4 +1,5 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Helmet } from 'react-helmet';
|
||||||
|
|
||||||
export function useDeferredState<T>(
|
export function useDeferredState<T>(
|
||||||
duration = 1000,
|
duration = 1000,
|
||||||
@ -19,3 +20,16 @@ export function useDeferredState<T>(
|
|||||||
|
|
||||||
return [response, setInnerValue];
|
return [response, setInnerValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useOpenSearch(xmlPath: string) {
|
||||||
|
return () => (
|
||||||
|
<Helmet>
|
||||||
|
<link
|
||||||
|
rel="search"
|
||||||
|
type="application/opensearchdescription+xml"
|
||||||
|
title="namae"
|
||||||
|
href={xmlPath}
|
||||||
|
/>
|
||||||
|
</Helmet>
|
||||||
|
);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user