App-Open-Source-per-iPhone-.../gatsby/src/components/ProjectCard.tsx

210 lines
5.6 KiB
TypeScript

import {
Card,
CardContent,
createStyles,
Divider,
GridList,
GridListTile,
makeStyles,
Theme,
Typography,
} from '@material-ui/core'
import Star from '@material-ui/icons/Star'
import { graphql, Link } from 'gatsby'
import React, { useState } from 'react'
import Lightbox from 'react-image-lightbox'
import 'react-image-lightbox/style.css'
import { Project } from '../types'
const useStyles = makeStyles((theme: Theme) =>
createStyles({
description: {
marginTop: theme.spacing(1),
marginBottom: theme.spacing(1),
fontSize: '1.2em',
},
tag: {
marginRight: theme.spacing(1),
},
}),
)
const urlToReaddable = (url: string) => {
if (url.indexOf('https://github.com/') === 0) {
return `@${url.substr('https://github.com/'.length)}`
} else if (url.indexOf('http://github.com/') === 0) {
return `@${url.substr('http://github.com/'.length)}`
} else return url
}
const starCountToIconCount = (githubStars: number): number => {
if (githubStars > 2000) {
return 5
} else if (githubStars > 1000) {
return 4
} else if (githubStars > 500) {
return 3
} else if (githubStars > 200) {
return 2
} else if (githubStars > 100) {
return 1
} else return 0
}
const RepeatingStars = ({ count }: { count: number }) => {
return (
<span>
{Array.from({ length: count }).map((_, i) => (
<Star key={i} />
))}
</span>
)
}
const ProjectCard = ({ project }: { project: Project }) => {
const classes = useStyles()
const [isLightboxOpen, setIsLightboxOpen] = useState(false)
const [lightboxSlide, setLightboxSlide] = useState(0)
const showStarCount = starCountToIconCount(project.stars)
const screenshotSources = project.screenshots || []
const tags = project.tags || []
return (
<Card>
<CardContent>
<Typography variant="h4" component="h2">
{project.title}
</Typography>
{showStarCount > 0 ? <RepeatingStars count={showStarCount} /> : null}
<Typography className={classes.description}>
{project.description}
</Typography>
<Divider />
<Typography>Lang: {project.lang || 'en'}</Typography>
<Typography>Added: {project.date_added}</Typography>
<Typography>GitHub Stars: {project.stars}</Typography>
<Typography>
Code:{' '}
{project.source ? (
<a href={project.source} target="_blank" rel="noreferrer">
{urlToReaddable(project.source)}
</a>
) : (
'n/a'
)}
</Typography>
<Typography>
License:{' '}
{project.license ? (
<a
href={`https://choosealicense.com/licenses/${project.license}/`}
target="_blank"
rel="noreferrer"
>
{project.license}
</a>
) : (
'n/a'
)}
</Typography>
<Typography>
iTunes:{' '}
{project.itunes ? (
<a href={project.itunes} target="_blank" rel="noreferrer">
{project.itunes}
</a>
) : (
'n/a'
)}
</Typography>
<Typography>
Homepage:{' '}
{project.homepage ? (
<a href={project.homepage} target="_blank" rel="noreferrer">
{project.homepage}
</a>
) : (
'n/a'
)}
</Typography>
<Typography>
Tags:{' '}
{tags.map(tag => {
return (
<Link key={tag} to={`/tag/${tag}/`} className={classes.tag}>
#{tag}
</Link>
)
})}
</Typography>
{screenshotSources.length === 0 ? null : (
<>
<GridList cellHeight={160} cols={4}>
{screenshotSources.map((url, i) => {
return (
<GridListTile key={i} cols={1}>
<a
href={url}
target="_blank"
rel="noreferrer"
onClick={event => {
event.preventDefault()
setLightboxSlide(i)
setIsLightboxOpen(true)
}}
>
<img src={url} width="120" height="160" />
</a>
</GridListTile>
)
})}
</GridList>
{!isLightboxOpen ? null : (
<Lightbox
mainSrc={screenshotSources[lightboxSlide]}
nextSrc={screenshotSources[lightboxSlide + 1]}
prevSrc={screenshotSources[lightboxSlide - 1]}
onCloseRequest={() => setIsLightboxOpen(false)}
onMoveNextRequest={() => {
setLightboxSlide(
(lightboxSlide + screenshotSources.length + 1) %
screenshotSources.length,
)
}}
onMovePrevRequest={() => {
setLightboxSlide(
(lightboxSlide + screenshotSources.length - 1) %
screenshotSources.length,
)
}}
/>
)}
</>
)}
</CardContent>
</Card>
)
}
export default ProjectCard
export const projectCardFragment = graphql`
fragment ProjectCardFields on AppProject {
category_ids
date_added
description
homepage
id
itunes
lang
license
screenshots
source
stars
suggested_by
tags
title
}
`