add Footer, add a link to TWHelp in the header, add info about the last data update to the server card

This commit is contained in:
Dawid Wysokiński 2020-11-04 06:24:05 +01:00
parent 5f19ccc035
commit cde80bd092
15 changed files with 119 additions and 31 deletions

View File

@ -5,10 +5,12 @@
{
"@": ["./src"],
"alias": {
"@": "./src",
"@common": "./src/common",
"@config": "./src/config",
"@features": "./src/features",
"@libs": "./src/libs",
"@theme": "./src/theme",
"@utils": "./src/utils"
}
}

View File

@ -15,6 +15,7 @@
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.

View File

@ -4,3 +4,7 @@ export const SERVER_STATUS = {
CLOSED: 'closed',
OPEN: 'open',
};
export const TWHELP = process.env.TWHelp ?? 'https://tribalwarshelp.com';
export const AUTHOR = 'Dawid Wysokiński';

View File

@ -5,6 +5,7 @@ import { Container, Toolbar } from '@material-ui/core';
import Header from './components/Header/Header';
import ServerSelection from './components/ServerSelection/ServerSelection';
import Footer from './components/Footer/Footer';
export default function IndexPage() {
const classes = useStyles();
@ -18,6 +19,7 @@ export default function IndexPage() {
<ServerSelection />
</Container>
</main>
<Footer />
</div>
);
}

View File

@ -0,0 +1,21 @@
import React from 'react';
import { AUTHOR } from '@config/app';
import useStyles from './styles';
import { AppBar, Toolbar, Container, Typography } from '@material-ui/core';
export default function Header() {
const classes = useStyles();
return (
<AppBar position="static" component="footer">
<Container>
<Toolbar disableGutters className={classes.toolbar}>
<Typography align="center" className={classes.copyright}>
&copy; {new Date().getFullYear()} {AUTHOR}
</Typography>
</Toolbar>
</Container>
</AppBar>
);
}

View File

@ -0,0 +1,12 @@
import { makeStyles } from '@material-ui/core/styles';
const useStyles = makeStyles(theme => ({
toolbar: {
textAlign: 'center',
},
copyright: {
width: '100%',
},
}));
export default useStyles;

View File

@ -1,6 +1,7 @@
import React from 'react';
import { useQueryParams, StringParam, withDefault } from 'use-query-params';
import { useDebouncedCallback } from 'use-debounce';
import { TWHELP } from '@config/app';
import useStyles from './styles';
import {
@ -9,6 +10,9 @@ import {
TextField,
InputAdornment,
Container,
Button,
Hidden,
Link,
} from '@material-ui/core';
import { Search as SearchIcon } from '@material-ui/icons';
import VersionSelector from '@common/VersionSelector/VersionSelector';
@ -31,7 +35,7 @@ export default function Header() {
<TextField
fullWidth
variant="outlined"
placeholder="Search server"
placeholder="Search"
defaultValue={query.q}
size="small"
onChange={e => {
@ -50,6 +54,11 @@ export default function Header() {
<div>
<VersionSelector />
</div>
<Hidden xsDown implementation="css">
<Link href={TWHELP} underline="none">
<Button>TWHelp</Button>
</Link>
</Hidden>
</Toolbar>
</Container>
</AppBar>

View File

@ -6,6 +6,9 @@ import {
NumberParam,
withDefault,
} from 'use-query-params';
import formatDistanceToNow from '@libs/date/formatDistanceToNow';
import { Locale } from '@libs/date/locales';
import useLanguage from '@libs/i18n/useLanguage';
import { SERVER_STATUS } from '@config/app';
import { ServerList } from './types';
import { SERVERS } from './queries';
@ -18,12 +21,14 @@ import Pagination, {
} from '@common/Pagination/Pagination';
const PER_PAGE = 30;
const arr = new Array(PER_PAGE).fill(0);
export default function ServerSelection() {
const [query, setQuery] = useQueryParams({
page: withDefault(NumberParam, 1),
q: withDefault(StringParam, ''),
});
const lang = useLanguage();
const { data, loading: loadingServers } = useQuery<ServerList>(SERVERS, {
fetchPolicy: 'cache-and-network',
variables: {
@ -67,12 +72,13 @@ export default function ServerSelection() {
</Box>
);
};
return (
<div>
{renderPagination(true)}
<Grid container spacing={3}>
{loading
? new Array(PER_PAGE).fill(0).map((_, index) => {
? arr.map((_, index) => {
return (
<Grid key={index} item xs={12} sm={6} md={4}>
<Card>
@ -101,6 +107,13 @@ export default function ServerSelection() {
{server.numberOfTribes.toLocaleString()} tribes
<br />
{server.numberOfVillages.toLocaleString()} villages
<br />
Updated{' '}
{formatDistanceToNow(new Date(server.dataUpdatedAt), {
locale: lang as Locale,
addSuffix: true,
})}
.
</span>
}
/>

View File

@ -9,6 +9,7 @@ export const SERVERS = gql`
numberOfPlayers
numberOfTribes
numberOfVillages
dataUpdatedAt
}
total
}

View File

@ -6,6 +6,7 @@ export type Server = {
numberOfPlayers: number;
numberOfTribes: number;
numberOfVillages: number;
dataUpdatedAt: string | Date;
};
export type ServerList = {

View File

@ -1,9 +1,17 @@
import { makeStyles } from '@material-ui/core/styles';
import { heights } from '@theme/toolbar';
const useStyles = makeStyles(theme => {
return {
main: {
padding: theme.spacing(3, 0),
minHeight: `calc(100vh - ${heights.tabletDesktop * 2}px)`,
[`${theme.breakpoints.down('xs')} and (orientation: landscape)`]: {
minHeight: `calc(100vh - ${heights.mobileLandscape * 2}px)`,
},
[theme.breakpoints.down('xs')]: {
minHeight: `calc(100vh - ${heights.mobilePortrait * 2}px)`,
},
},
};
});

View File

@ -0,0 +1,17 @@
import { formatDistanceToNow } from 'date-fns';
import locales, { Locale } from './locales';
export type Options = {
includeSeconds?: boolean;
addSuffix?: boolean;
locale: Locale;
};
const _formatDistanceToNow = (date: Date | number, opts: Options) => {
return formatDistanceToNow(date, {
...opts,
locale: locales[opts.locale] ?? locales.en,
});
};
export default _formatDistanceToNow;

11
src/libs/date/locales.ts Normal file
View File

@ -0,0 +1,11 @@
import pl from 'date-fns/locale/pl';
import enGB from 'date-fns/locale/en-GB';
export type Locale = 'pl' | 'en';
const locales = {
pl,
en: enGB,
};
export default locales;

5
src/theme/toolbar.ts Normal file
View File

@ -0,0 +1,5 @@
export const heights = {
mobilePortrait: 56,
mobileLandscape: 48,
tabletDesktop: 64,
};

View File

@ -2,31 +2,16 @@
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": [
"src/*"
],
"@common/*": [
"src/common/*"
],
"@config/*": [
"src/config/*"
],
"@features/*": [
"src/features/*"
],
"@libs/*": [
"src/libs/*"
],
"@utils/*": [
"src/utils/*"
]
"@/*": ["src/*"],
"@common/*": ["src/common/*"],
"@config/*": ["src/config/*"],
"@features/*": ["src/features/*"],
"@libs/*": ["src/libs/*"],
"@theme/*": ["src/theme/*"],
"@utils/*": ["src/utils/*"]
},
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
@ -41,10 +26,6 @@
"noEmit": true,
"jsx": "react"
},
"exclude": [
"node_modules"
],
"include": [
"src"
]
"exclude": ["node_modules"],
"include": ["src"]
}