-
-
Notifications
You must be signed in to change notification settings - Fork 31.6k
/
Showcase.js
150 lines (141 loc) · 4.37 KB
/
Showcase.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { withStyles } from '@material-ui/core/styles';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import FormControl from '@material-ui/core/FormControl';
import Select from '@material-ui/core/Select';
import Card from '@material-ui/core/Card';
import CardMedia from '@material-ui/core/CardMedia';
import Typography from '@material-ui/core/Typography';
import IconButton from '@material-ui/core/IconButton';
import GithubIcon from '@material-ui/docs/svgIcons/GitHub';
import Link from 'docs/src/modules/components/Link';
import compose from 'docs/src/modules/utils/compose';
import appList from './appList';
const styles = theme => ({
root: {
backgroundColor: theme.palette.background.default,
// Hide the demo container padding
margin: -theme.spacing(3),
// Maintain alignment with the markdown text
[theme.breakpoints.down('xs')]: {
padding: 30,
},
},
formControl: {
marginBottom: theme.spacing(4),
minWidth: 120,
},
title: {
marginBottom: theme.spacing(2),
},
card: {
marginBottom: theme.spacing(1),
maxWidth: 600,
},
description: {
marginBottom: theme.spacing(6),
maxWidth: 600,
},
cardMedia: {
paddingTop: '75%', // 4:3
},
});
function stableSort(array, cmp) {
const stabilizedThis = array.map((el, index) => [el, index]);
stabilizedThis.sort((a, b) => {
const order = cmp(a[0], b[0]);
if (order !== 0) return order;
return a[1] - b[1];
});
return stabilizedThis.map(el => el[0]);
}
// Returns a function that sorts reverse numerically by value of `key`
function sortFactory(key) {
return function sortNumeric(a, b) {
if (b[key] < a[key]) {
return -1;
}
if (b[key] > a[key]) {
return 1;
}
return 0;
};
}
const sortFunctions = {
dateAdded: sortFactory('dateAdded'),
similarWebVisits: sortFactory('similarWebVisits'),
stars: sortFactory('stars'),
};
function Showcase(props) {
const { classes, t } = props;
const [sortFunctionName, setSortFunctionName] = React.useState('dateAdded');
const sortFunction = sortFunctions[sortFunctionName];
function handleChangeSort(event) {
setSortFunctionName(event.target.value);
}
return (
<div className={classes.root}>
<FormControl className={classes.formControl}>
<InputLabel htmlFor="sort">Sort by</InputLabel>
<Select value={sortFunctionName} onChange={handleChangeSort} id="sort">
<MenuItem value="dateAdded">{t('newest')}</MenuItem>
<MenuItem value="similarWebVisits">{t('traffic')}</MenuItem>
<MenuItem value="stars">{t('stars')}</MenuItem>
</Select>
</FormControl>
{stableSort(appList.filter(item => item[sortFunctionName] !== undefined), sortFunction).map(
app => (
<div key={app.title}>
<Typography component="h2" variant="h4" gutterBottom className={classes.title}>
<span>{app.title}</span>
{app.source ? (
<IconButton
href={app.source}
target="_blank"
aria-label={`${app.title} ${t('sourceCode')}`}
>
<GithubIcon />
</IconButton>
) : null}
</Typography>
{app.image ? (
<Card className={classes.card}>
<CardMedia
component="a"
href={app.link}
rel="noopener"
target="_blank"
className={classes.cardMedia}
image={`/static/images/showcase/${app.image}`}
title={app.title}
/>
</Card>
) : (
<Link
variant="body2"
target="_blank"
rel="noopener nofollow"
href={app.link}
gutterBottom
>
{t('visit')}
</Link>
)}
<Typography className={classes.description}>{app.description}</Typography>
</div>
),
)}
</div>
);
}
Showcase.propTypes = {
classes: PropTypes.object.isRequired,
t: PropTypes.func.isRequired,
};
export default compose(
connect(state => ({ t: state.options.t })),
withStyles(styles),
)(Showcase);