mirror of
https://github.com/uetchy/namae.git
synced 2025-10-15 07:32:19 +09:00
dev: initial attempt
This commit is contained in:
40
pages/_app.tsx
Normal file
40
pages/_app.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
// https://nextjs.org/docs/advanced-features/custom-app
|
||||
|
||||
import { Global } from '@emotion/react';
|
||||
import { StoreProvider } from 'easy-peasy';
|
||||
import { appWithTranslation } from 'next-i18next';
|
||||
import { useEffect } from 'react';
|
||||
import { ToastContainer } from 'react-toastify';
|
||||
import Footer from '../components/Footer';
|
||||
import { globalStyle } from '../src/theme';
|
||||
import { initSentry } from '../src/util/analytics';
|
||||
import { initCrisp } from '../src/util/crisp';
|
||||
import { useOpenSearch } from '../src/util/hooks';
|
||||
import { FullScreenSuspense } from '../src/util/suspense';
|
||||
import { store } from '../store';
|
||||
import nextI18nConfig from '../next-i18next.config';
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
useEffect(() => {
|
||||
// Client-side-only code
|
||||
// TODO: https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
||||
initSentry();
|
||||
initCrisp();
|
||||
}, []);
|
||||
|
||||
const OpenSearch = useOpenSearch('/opensearch.xml');
|
||||
|
||||
return (
|
||||
<StoreProvider store={store}>
|
||||
<FullScreenSuspense>
|
||||
<Global styles={globalStyle} />
|
||||
<OpenSearch />
|
||||
<Component {...pageProps} />;
|
||||
<Footer />
|
||||
</FullScreenSuspense>
|
||||
<ToastContainer />
|
||||
</StoreProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default appWithTranslation(MyApp, nextI18nConfig);
|
66
pages/_document.tsx
Normal file
66
pages/_document.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
// https://nextjs.org/docs/advanced-features/custom-document
|
||||
|
||||
import { Head, Html, Main, NextScript } from 'next/document';
|
||||
import i18nextConfig from '../next-i18next.config';
|
||||
|
||||
export default function Document(props) {
|
||||
const currentLocale =
|
||||
props.__NEXT_DATA__.locale || i18nextConfig.i18n.defaultLocale;
|
||||
|
||||
return (
|
||||
<Html lang={currentLocale}>
|
||||
<Head>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
||||
<meta name="apple-mobile-web-app-title" content="namae" />
|
||||
<meta name="msapplication-TileColor" content="#5180fc" />
|
||||
<meta name="theme-color" content="#632bec" />
|
||||
<link rel="shortcut icon" href="/favicon.ico" />
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="/apple-touch-icon.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="/favicon-32x32.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="16x16"
|
||||
href="/favicon-16x16.png"
|
||||
/>
|
||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5180fc" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
|
||||
<meta property="og:title" content="namae — name new project" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Check availability of your new app name for major registries at once."
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:image" content="https://namae.dev/social.png" />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:creator" content="@uechz" />
|
||||
<meta name="twitter:image" content="https://namae.dev/social.png" />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Montserrat:600&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<script
|
||||
async
|
||||
defer
|
||||
data-website-id="a0bfb495-787b-4960-938d-c4a190aa7455"
|
||||
src="https://analytics.uechi.io/umami.js"
|
||||
></script>
|
||||
</Head>
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
);
|
||||
}
|
26
pages/index.tsx
Normal file
26
pages/index.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Form from '../components/Form';
|
||||
import Welcome from '../components/Welcome';
|
||||
import { Content, Header } from '../src/theme';
|
||||
|
||||
export default function App() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>namae — {t('title')}</title>
|
||||
</Helmet>
|
||||
|
||||
<Header>
|
||||
<Form useSuggestion={false} />
|
||||
</Header>
|
||||
|
||||
<Content>
|
||||
<Welcome />
|
||||
</Content>
|
||||
</>
|
||||
);
|
||||
}
|
117
pages/s/[query].tsx
Normal file
117
pages/s/[query].tsx
Normal file
@@ -0,0 +1,117 @@
|
||||
import { useRouter } from 'next/router';
|
||||
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 styled from '@emotion/styled';
|
||||
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 '../../src/theme';
|
||||
import { mobile } from '../../src/util/css';
|
||||
import { sanitize } from '../../src/util/text';
|
||||
|
||||
export default function Search() {
|
||||
const router = useRouter();
|
||||
const { query } = router.query;
|
||||
const currentQuery = sanitize((query as string) ?? '');
|
||||
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;
|
||||
`;
|
Reference in New Issue
Block a user