mirror of
https://github.com/status-im/liquid-funding.git
synced 2025-01-12 04:24:23 +00:00
Merge pull request #24 from status-im/feat/project-list-style-switcher
Add list view and favorites
This commit is contained in:
commit
1b207e4021
15
package.json
15
package.json
@ -76,6 +76,7 @@
|
|||||||
"case-sensitive-paths-webpack-plugin": "2.2.0",
|
"case-sensitive-paths-webpack-plugin": "2.2.0",
|
||||||
"chai": "^4.1.0",
|
"chai": "^4.1.0",
|
||||||
"chart.js": "^2.7.3",
|
"chart.js": "^2.7.3",
|
||||||
|
"classnames": "^2.2.6",
|
||||||
"cryptocurrency-icons": "^0.9.3",
|
"cryptocurrency-icons": "^0.9.3",
|
||||||
"css-loader": "1.0.0",
|
"css-loader": "1.0.0",
|
||||||
"cytoscape": "^3.3.0",
|
"cytoscape": "^3.3.0",
|
||||||
@ -190,8 +191,18 @@
|
|||||||
"react-app"
|
"react-app"
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
["@babel/plugin-proposal-decorators", { "legacy": true }],
|
[
|
||||||
["@babel/plugin-proposal-class-properties", { "loose": true }],
|
"@babel/plugin-proposal-decorators",
|
||||||
|
{
|
||||||
|
"legacy": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"@babel/plugin-proposal-class-properties",
|
||||||
|
{
|
||||||
|
"loose": true
|
||||||
|
}
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"@babel/plugin-transform-runtime",
|
"@babel/plugin-transform-runtime",
|
||||||
{
|
{
|
||||||
|
BIN
public/images/favorite-sprite.png
Normal file
BIN
public/images/favorite-sprite.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
@ -21,6 +21,12 @@ import InputAdornment from '@material-ui/core/InputAdornment';
|
|||||||
import SearchIcon from '@material-ui/icons/Search';
|
import SearchIcon from '@material-ui/icons/Search';
|
||||||
import ListIcon from '@material-ui/icons/Reorder';
|
import ListIcon from '@material-ui/icons/Reorder';
|
||||||
import DashboardIcon from '@material-ui/icons/Dashboard';
|
import DashboardIcon from '@material-ui/icons/Dashboard';
|
||||||
|
import Table from '@material-ui/core/Table';
|
||||||
|
import TableBody from '@material-ui/core/TableBody';
|
||||||
|
import TableCell from '@material-ui/core/TableCell';
|
||||||
|
import TableHead from '@material-ui/core/TableHead';
|
||||||
|
import TableRow from '@material-ui/core/TableRow';
|
||||||
|
import classnames from 'classnames';
|
||||||
|
|
||||||
import defaultProjectImage from '../../images/default-project-img.png';
|
import defaultProjectImage from '../../images/default-project-img.png';
|
||||||
import newProjectImage from '../../images/new-project.png';
|
import newProjectImage from '../../images/new-project.png';
|
||||||
@ -30,50 +36,91 @@ const SORT_TYPES = {
|
|||||||
name: 'name'
|
name: 'name'
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = theme => ({
|
const cardAbsolutesDistance = 26;
|
||||||
root: {
|
|
||||||
margin: '1.75rem 4.5rem',
|
const styles = theme => {
|
||||||
...theme.typography.body1
|
return ({
|
||||||
},
|
root: {
|
||||||
filters: {
|
margin: '1.75rem 4.5rem',
|
||||||
float: 'right'
|
...theme.typography.body1
|
||||||
},
|
},
|
||||||
search: {
|
filters: {
|
||||||
height: 36
|
float: 'right'
|
||||||
},
|
},
|
||||||
title: {
|
search: {
|
||||||
fontSize: '20px',
|
height: 36
|
||||||
textAlign: 'center',
|
},
|
||||||
fontWeight: 500
|
formatBtn: {
|
||||||
},
|
cursor: 'pointer',
|
||||||
media: {
|
'&:hover, &.active': {
|
||||||
height: 235,
|
color: 'black'
|
||||||
position: 'relative'
|
}
|
||||||
},
|
},
|
||||||
avatar: {
|
title: {
|
||||||
position: 'absolute',
|
fontSize: '20px',
|
||||||
top: 26,
|
textAlign: 'center',
|
||||||
left: 26
|
fontWeight: 500
|
||||||
},
|
},
|
||||||
'card-title': {
|
media: {
|
||||||
fontSize: '20px'
|
height: 235,
|
||||||
},
|
position: 'relative'
|
||||||
'card-content': {
|
},
|
||||||
fontSize: '16px'
|
avatarGrid: {
|
||||||
},
|
position: 'absolute',
|
||||||
'card-actions': {
|
top: cardAbsolutesDistance,
|
||||||
float: 'right'
|
left: cardAbsolutesDistance
|
||||||
},
|
},
|
||||||
progress: {
|
'card-title': {
|
||||||
height: 10
|
fontSize: '20px'
|
||||||
},
|
},
|
||||||
'new-project-img': {
|
'card-content': {
|
||||||
textAlign: 'center',
|
fontSize: '16px'
|
||||||
margin: 0,
|
},
|
||||||
paddingTop: 115,
|
'card-actions': {
|
||||||
paddingBottom: 43
|
float: 'right'
|
||||||
}
|
},
|
||||||
})
|
progress: {
|
||||||
|
height: 10
|
||||||
|
},
|
||||||
|
'new-project-img': {
|
||||||
|
textAlign: 'center',
|
||||||
|
margin: 0,
|
||||||
|
paddingTop: 115,
|
||||||
|
paddingBottom: 43
|
||||||
|
},
|
||||||
|
nameCell: {
|
||||||
|
fontSize: 18
|
||||||
|
},
|
||||||
|
darkRow: {
|
||||||
|
backgroundColor: theme.palette.common.grey
|
||||||
|
},
|
||||||
|
addProjectRow: {
|
||||||
|
borderTop: '0.25px solid ' + theme.palette.text.grey,
|
||||||
|
cursor: 'pointer',
|
||||||
|
'& td': {
|
||||||
|
paddingTop: 35
|
||||||
|
}
|
||||||
|
},
|
||||||
|
favorite: {
|
||||||
|
display: 'inline-block',
|
||||||
|
backgroundImage: 'url("/images/favorite-sprite.png")',
|
||||||
|
backgroundRepeat: 'no-repeat',
|
||||||
|
backgroundPosition: 'bottom',
|
||||||
|
width: 30,
|
||||||
|
height: 27,
|
||||||
|
cursor: 'pointer',
|
||||||
|
'&:hover, &.isFavorite': {
|
||||||
|
backgroundPosition: 'top'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cardFavorite: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: cardAbsolutesDistance,
|
||||||
|
right: cardAbsolutesDistance,
|
||||||
|
zIndex: 9000
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function sortByTitle(a, b) {
|
function sortByTitle(a, b) {
|
||||||
if (!a.manifest || !b.manifest) {
|
if (!a.manifest || !b.manifest) {
|
||||||
@ -90,9 +137,14 @@ function sortByDate(a, b) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ProjectCard({classes, project}) {
|
function Favorite({classes, setFavorites, favorites, projectId, className}) {
|
||||||
|
return (<span className={classnames(className, classes.favorite, {isFavorite: favorites[projectId]})}
|
||||||
|
onClick={() => setFavorites({...favorites, [projectId]: !favorites[projectId]})}/>);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ProjectCard({classes, project, favorites, setFavorites}) {
|
||||||
return (<Card className={classes.card}>
|
return (<Card className={classes.card}>
|
||||||
<CardActionArea href={`/#/project/${project.projectId}`}>
|
<CardActionArea href={`/#/project/${project.projectId}`} onClick={e => { if (e.target.className.indexOf(classes.favorite) > -1) { e.preventDefault() } }}>
|
||||||
<CardMedia
|
<CardMedia
|
||||||
className={classes.media}
|
className={classes.media}
|
||||||
image={defaultProjectImage}
|
image={defaultProjectImage}
|
||||||
@ -111,7 +163,8 @@ function ProjectCard({classes, project}) {
|
|||||||
<Typography component="p" className={classes['card-content']} color="textSecondary">
|
<Typography component="p" className={classes['card-content']} color="textSecondary">
|
||||||
Delegate: {project.manifest.creator} {/*TODO check if that really is the delegate*/}
|
Delegate: {project.manifest.creator} {/*TODO check if that really is the delegate*/}
|
||||||
</Typography>
|
</Typography>
|
||||||
{project.manifest.avatar && <img className={classes.avatar} alt="avatar" src={project.manifest.avatar} width={40} height={40}/>}
|
{project.manifest.avatar && <img className={classes.avatarGrid} alt="avatar" src={project.manifest.avatar} width={40} height={40}/>}
|
||||||
|
<Favorite className={classes.cardFavorite} classes={classes} favorites={favorites} projectId={project.projectId} setFavorites={setFavorites}/>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</CardActionArea>
|
</CardActionArea>
|
||||||
<CardActions className={classes['card-actions']}>
|
<CardActions className={classes['card-actions']}>
|
||||||
@ -122,8 +175,98 @@ function ProjectCard({classes, project}) {
|
|||||||
</Card>)
|
</Card>)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Projects({projectAddedEvents, classes}) {
|
function GridView({classes, projects, favorites, setFavorites}) {
|
||||||
|
return (<Grid container spacing={40}>
|
||||||
|
{projects.map((project, index) => {
|
||||||
|
if (!project.manifest) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return (<Grid key={'project-' + index} item xs={12} sm={6} md={4} lg={3} className={classes.card}>
|
||||||
|
<ProjectCard project={project} classes={classes} favorites={favorites} setFavorites={setFavorites}/>
|
||||||
|
</Grid>);
|
||||||
|
})}
|
||||||
|
<Grid item xs={12} sm={6} md={4} lg={3} className="project-list-item">
|
||||||
|
<Card className={classes.card}>
|
||||||
|
<CardActionArea href="/#/create-project/" style={{height: 460}}>
|
||||||
|
<p className={classes['new-project-img']}><img alt="new project" src={newProjectImage}/></p>
|
||||||
|
<Typography align="center" className={classes['card-content']}>Add your own project</Typography>
|
||||||
|
</CardActionArea>
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
</Grid>)
|
||||||
|
}
|
||||||
|
|
||||||
|
const CustomTableCell = withStyles(theme => ({
|
||||||
|
head: {
|
||||||
|
color: theme.palette.text.grey,
|
||||||
|
fontSize: 15,
|
||||||
|
border: 0
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
fontSize: 16,
|
||||||
|
border: 0,
|
||||||
|
height: 80
|
||||||
|
}
|
||||||
|
}))(TableCell);
|
||||||
|
|
||||||
|
function ListView({classes, projects, history, favorites, setFavorites}) {
|
||||||
|
let rowCounter = -1;
|
||||||
|
return (<Table className={classes.table}>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<CustomTableCell> </CustomTableCell>
|
||||||
|
<CustomTableCell>Project name</CustomTableCell>
|
||||||
|
<CustomTableCell>Description</CustomTableCell>
|
||||||
|
<CustomTableCell>Funding details</CustomTableCell>
|
||||||
|
<CustomTableCell>Delegate</CustomTableCell>
|
||||||
|
<CustomTableCell> </CustomTableCell>
|
||||||
|
<CustomTableCell> </CustomTableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{projects.map((project, index) => {
|
||||||
|
rowCounter++;
|
||||||
|
if (!project.manifest) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<TableRow className={classnames(classes.row, {[classes.darkRow]: rowCounter%2})} key={'project-' + index}>
|
||||||
|
<CustomTableCell>
|
||||||
|
{project.manifest.avatar &&
|
||||||
|
<img className={classes.avatar} alt="avatar" src={project.manifest.avatar} width={40} height={40}/>}
|
||||||
|
</CustomTableCell>
|
||||||
|
<CustomTableCell className={classes.nameCell}>{project.manifest.title}</CustomTableCell>
|
||||||
|
<CustomTableCell>{project.manifest.description}</CustomTableCell>
|
||||||
|
<CustomTableCell>76% of 2.055 ETH<br/>3 funders</CustomTableCell>
|
||||||
|
<CustomTableCell>{project.manifest.creator}</CustomTableCell>
|
||||||
|
<CustomTableCell>
|
||||||
|
<Favorite classes={classes} favorites={favorites} projectId={project.projectId} setFavorites={setFavorites}/>
|
||||||
|
</CustomTableCell>
|
||||||
|
<CustomTableCell>
|
||||||
|
<Button size="small" color="primary" href={`/#/project/${project.projectId}`}>Read more</Button>
|
||||||
|
</CustomTableCell>
|
||||||
|
</TableRow>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
<TableRow className={classnames(classes.row, classes.addProjectRow)} hover onClick={() => history.push('/create-project/')}>
|
||||||
|
<CustomTableCell>
|
||||||
|
<img alt="add project" src={newProjectImage} width={40} height={40}/>
|
||||||
|
</CustomTableCell>
|
||||||
|
<CustomTableCell>Add your own project</CustomTableCell>
|
||||||
|
<CustomTableCell/>
|
||||||
|
<CustomTableCell/>
|
||||||
|
<CustomTableCell/>
|
||||||
|
<CustomTableCell/>
|
||||||
|
<CustomTableCell/>
|
||||||
|
</TableRow>
|
||||||
|
</TableBody>
|
||||||
|
</Table>)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Projects({projectAddedEvents, classes, history}) {
|
||||||
|
const [favorites, setFavorites] = useState({});
|
||||||
const [sortType, _setSortType] = useState(SORT_TYPES.date);
|
const [sortType, _setSortType] = useState(SORT_TYPES.date);
|
||||||
|
const [isGridView, setIsGridView] = useState(true);
|
||||||
|
|
||||||
const projects = projectAddedEvents.map(event => {
|
const projects = projectAddedEvents.map(event => {
|
||||||
return Object.assign({projectId: event.returnValues.idProject}, useProjectData(event.returnValues.idProject, '', projectAddedEvents));
|
return Object.assign({projectId: event.returnValues.idProject}, useProjectData(event.returnValues.idProject, '', projectAddedEvents));
|
||||||
@ -134,7 +277,9 @@ function Projects({projectAddedEvents, classes}) {
|
|||||||
|
|
||||||
return (<div className={classes.root}>
|
return (<div className={classes.root}>
|
||||||
<Typography className={classes.title} component="h2" gutterBottom>All projects</Typography>
|
<Typography className={classes.title} component="h2" gutterBottom>All projects</Typography>
|
||||||
|
|
||||||
{projects.length === 0 && <Loading/>}
|
{projects.length === 0 && <Loading/>}
|
||||||
|
|
||||||
{projects.length > 0 &&
|
{projects.length > 0 &&
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className={classes.filters}>
|
<div className={classes.filters}>
|
||||||
@ -148,27 +293,13 @@ function Projects({projectAddedEvents, classes}) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<DashboardIcon color="disabled" fontSize="large"/>
|
|
||||||
<ListIcon color="disabled" fontSize="large"/>
|
<DashboardIcon className={classnames(classes.formatBtn, {'active': isGridView})} color="disabled" fontSize="large" onClick={() => setIsGridView(true)}/>
|
||||||
|
<ListIcon className={classnames(classes.formatBtn, {'active': !isGridView})} color="disabled" fontSize="large" onClick={() => setIsGridView(false)}/>
|
||||||
</div>
|
</div>
|
||||||
<Grid container spacing={40}>
|
|
||||||
{projects.map((project, index) => {
|
{!isGridView && ListView({classes, projects, history, favorites, setFavorites})}
|
||||||
if (!project.manifest) {
|
{isGridView && GridView({classes, projects, favorites, setFavorites})}
|
||||||
return ''
|
|
||||||
}
|
|
||||||
return (<Grid key={'project-' + index} item xs={12} sm={6} md={4} lg={3} className={classes.card}>
|
|
||||||
<ProjectCard project={project} classes={classes}/>
|
|
||||||
</Grid>);
|
|
||||||
})}
|
|
||||||
<Grid item xs={12} sm={6} md={4} lg={3} className="project-list-item">
|
|
||||||
<Card className={classes.card}>
|
|
||||||
<CardActionArea href="/#/create-project/" style={{height: 460}}>
|
|
||||||
<p className={classes['new-project-img']}><img alt="new project" src={newProjectImage}/></p>
|
|
||||||
<Typography align="center" className={classes['card-content']}>Add your own project</Typography>
|
|
||||||
</CardActionArea>
|
|
||||||
</Card>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
}
|
}
|
||||||
</div>)
|
</div>)
|
||||||
|
@ -12,6 +12,14 @@ const theme = createMuiTheme({
|
|||||||
useNextVariants: true,
|
useNextVariants: true,
|
||||||
fontFamily: ['Inter', '-apple-system', 'BlinkMacSystemFont', "Segoe UI", 'Roboto', "Helvetica Neue", 'Arial', "Noto Sans", 'sans-serif', "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"].join(','),
|
fontFamily: ['Inter', '-apple-system', 'BlinkMacSystemFont', "Segoe UI", 'Roboto', "Helvetica Neue", 'Arial', "Noto Sans", 'sans-serif', "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"].join(','),
|
||||||
},
|
},
|
||||||
|
palette: {
|
||||||
|
common: {
|
||||||
|
grey: '#F5F7F8'
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
grey: '#939BA1'
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
render(
|
render(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user