Skip to content
This repository was archived by the owner on Oct 15, 2021. It is now read-only.

Commit 33a044f

Browse files
authored
fix(UI): Tool list styling
* New UI for List items * Centered title and image * Fixed list item accessibility
1 parent 0e79119 commit 33a044f

File tree

5 files changed

+151
-38
lines changed

5 files changed

+151
-38
lines changed

components/Image.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React, { ReactElement } from 'react';
2+
import NextImage from 'next/image';
3+
import { Avatar, createStyles, makeStyles, Theme } from '@material-ui/core';
4+
import { Image as ImageType } from '../pages';
5+
6+
interface Props {
7+
image: ImageType | undefined;
8+
name: string;
9+
}
10+
11+
const useStyles = makeStyles((theme: Theme) =>
12+
createStyles({
13+
avatar: {
14+
color: theme.palette.common.white,
15+
backgroundColor: theme.palette.primary.main,
16+
},
17+
})
18+
);
19+
20+
export default function Image({ image, name }: Props): ReactElement {
21+
const firstLetter = name.slice(0, 1).toUpperCase();
22+
const classes = useStyles();
23+
24+
if (!image) {
25+
return <Avatar className={classes.avatar}>{firstLetter}</Avatar>;
26+
}
27+
28+
if (image.src.startsWith('/')) {
29+
return <NextImage src={image.src || firstLetter} width={50} height={50} alt={name} data-testid="image" />;
30+
}
31+
32+
return (
33+
<>
34+
{/* used for non optimizable entries (files not stored in public directory) */}
35+
<img data-testid="image" src={image.src || firstLetter} width={50} height={50} alt={name} />
36+
</>
37+
);
38+
}

components/link/Link.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React from 'react';
2+
import { Link as MUILink } from '@material-ui/core';
3+
import Link from 'next/link';
4+
5+
type Props = {
6+
href: string;
7+
as?: string;
8+
label: string;
9+
color?: 'inherit' | 'initial' | 'primary' | 'secondary' | 'textPrimary' | 'textSecondary' | 'error' | undefined;
10+
};
11+
12+
export default function CustomLink({ href, as, label, color = 'inherit' }: Props) {
13+
return (
14+
<Link passHref href={href} as={as}>
15+
<MUILink color={color}>{label}</MUILink>
16+
</Link>
17+
);
18+
}

components/list/ListItem.tsx

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import Image from '../Image';
2+
import {
3+
ListItem as MUIListItem,
4+
Divider,
5+
ListItemAvatar,
6+
Avatar,
7+
ListItemText,
8+
Grid,
9+
Hidden,
10+
ListItemSecondaryAction,
11+
Typography,
12+
makeStyles,
13+
createStyles,
14+
Theme,
15+
} from '@material-ui/core';
16+
import Link from '../link/Link';
17+
import { Maybe } from 'graphql/jsutils/Maybe';
18+
import { Image as ImageType } from '../../pages/index';
19+
20+
const useStyles = makeStyles((theme: Theme) =>
21+
createStyles({
22+
info: {
23+
justify: 'center',
24+
padding: theme.spacing(2),
25+
},
26+
avatar: {
27+
backgroundColor: theme.palette.gray.light,
28+
},
29+
})
30+
);
31+
32+
export type Link = {
33+
label: string;
34+
href: string;
35+
as?: string;
36+
};
37+
38+
type Props = {
39+
name: string;
40+
image: ImageType | undefined;
41+
link: Link;
42+
};
43+
44+
export default function ListItem({ name, image, link }: Props) {
45+
const classes = useStyles();
46+
return (
47+
<MUIListItem divider>
48+
<Grid container>
49+
<ListItemAvatar>
50+
<Avatar alt={name} className={classes.avatar}>
51+
{/* NextJS Image optimization example. Props are src(any file under the public dir), width, and height */}
52+
<Image image={image} name={name} />
53+
</Avatar>
54+
</ListItemAvatar>
55+
<ListItemText>
56+
<Typography variant="body1">{name}</Typography>
57+
</ListItemText>
58+
<Hidden smDown>
59+
<ListItemSecondaryAction className={classes.info}>
60+
<Link href={link.href} as={link?.as} label={link.label} />
61+
</ListItemSecondaryAction>
62+
</Hidden>
63+
<Hidden mdUp>
64+
<Grid container item xs={12} className={classes.info} justify="flex-end">
65+
<Link href={link.href} as={link?.as} label={link.label} />
66+
</Grid>
67+
</Hidden>
68+
</Grid>
69+
</MUIListItem>
70+
);
71+
}

pages/index.tsx

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import { GetServerSideProps } from 'next';
2-
import Link from 'next/link';
3-
import Image from 'next/image';
4-
import { makeStyles, createStyles, Typography, Theme, Paper, ListItem, List, Grid, Button } from '@material-ui/core';
2+
import { makeStyles, createStyles, Typography, Theme, Paper, List, Grid } from '@material-ui/core';
53
import Layout from '../components/layout';
4+
import ListItem, { Link } from '../components/list/ListItem';
65

76
import { tools } from '../lib/tools';
87

98
const useStyles = makeStyles((theme: Theme) =>
109
createStyles({
11-
paper: {
12-
background: theme.palette.gray.light,
13-
boxShadow: `0 0.125em 0.25em 0 ${theme.palette.shadow.main}, 0 0.1875em 0.625em 0 ${theme.palette.shadow.main}`,
14-
padding: '2em',
10+
list: {
11+
minWidth: theme.breakpoints.values.sm,
12+
[theme.breakpoints.down('xs')]: {
13+
width: '100%',
14+
minWidth: 100,
15+
},
1516
},
1617
root: {
1718
padding: '2em',
@@ -22,8 +23,9 @@ const useStyles = makeStyles((theme: Theme) =>
2223
})
2324
);
2425

26+
export type Image = { src: string; width: number; height: number };
2527
interface Props {
26-
tools: { name: string; image?: { src: string; width: number; height: number } }[];
28+
tools: { name: string; image?: Image }[];
2729
}
2830

2931
export default function Home({ tools }: Props) {
@@ -39,32 +41,17 @@ export default function Home({ tools }: Props) {
3941
Tools
4042
</Typography>
4143
</Grid>
42-
<Grid item>
43-
<Paper className={classes.paper}>
44-
<List aria-label={tools.join(', ')}>
45-
{tools.map(({ name, image }) => (
46-
<ListItem key={name}>
47-
<Grid container alignItems="center" justify="space-between">
48-
{/* NextJS Image optimization example. Props are src(any file under the public dir), width, and height */}
49-
{image && <Image {...image} aria-hidden="true" />}
50-
<Typography variant="body1" aria-hidden="true">
51-
{name}
52-
</Typography>
53-
<Link href="/tool/[name]" as={`/tool/${name}`} passHref>
54-
<Button
55-
variant="contained"
56-
color="primary"
57-
className={classes.linkButton}
58-
aria-label={`Learn more about ${name}`}
59-
>
60-
<span aria-hidden="true">Learn more</span>
61-
</Button>
62-
</Link>
63-
</Grid>
64-
</ListItem>
65-
))}
66-
</List>
67-
</Paper>
44+
<Grid item container justify="center">
45+
<List aria-label={tools.join(', ')} className={classes.list}>
46+
{tools.map(({ name, image }) => {
47+
const link: Link = {
48+
href: '/tool/[name]',
49+
as: `/tool/${name}`,
50+
label: 'Learn More',
51+
};
52+
return <ListItem key={name} name={name} image={image} link={link} />;
53+
})}
54+
</List>
6855
</Grid>
6956
</Grid>
7057
</Grid>

pages/tool/[name].tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import Layout from '../../components/layout';
1010
const useStyles = makeStyles((theme: Theme) => ({
1111
description: {
1212
maxWidth: '80ch',
13-
paddingLeft: 100,
1413
},
1514
root: {
1615
padding: '.5em 2em',
@@ -58,19 +57,19 @@ export default function ToolInfo({ tool }: Props): ReactElement {
5857
<Typography color="textPrimary">{tool.name}</Typography>
5958
</Breadcrumbs>
6059
</Grid>
61-
<Grid item xs={12} container>
60+
<Grid item xs={12} container justify="center" alignItems="center">
6261
{/* NextJS Image optimization example. Props are src(any file under the public dir), width, and height */}
6362
{tool.image && <Image {...tool.image} data-testid="image" aria-hidden="true" />}
6463
<Typography variant="h2" className={classes.title}>
6564
{tool.name}
6665
</Typography>
6766
</Grid>
68-
<Grid item xs={12}>
67+
<Grid item xs={12} container justify="center">
6968
<Typography variant="body1" className={classes.description}>
7069
{tool.description}
7170
</Typography>
7271
</Grid>
73-
<Grid item xs={12}>
72+
<Grid item xs={12} container justify="center">
7473
<Button variant="contained" href={tool.link} color="primary">
7574
Visit {tool.name} documentation
7675
</Button>

0 commit comments

Comments
 (0)