/* eslint-disable */ import React, { Suspense, useMemo, useState, useEffect, lazy } from 'react' import { makeStyles } from '@mui/styles' import { Link, IconButton, InputLabel, MenuItem, Select } from '@mui/material' import { Publish } from '@mui/icons-material' import { NumberParam, StringParam, useQueryParam } from 'use-query-params' //locals import { myfetchjson, getCaption, shuffle, DixieFile } from './util' import { PAGE_SIZE, API_ENDPOINT } from './constants' import Media from './Media' // lazy const PictureDialog = lazy(() => import('./PictureDialog')) const UploadDialog = lazy(() => import('./UploadDialog')) // generated with ls | jq -R -s -c 'split("\n")[:-1]' > gifs.json import gifs from './gifs.json' // generated with ls | jq -R -s -c 'split("\n")[:-1]' > borders.json import borders from './borders.json' const myimages = shuffle(gifs) const myborders = shuffle(borders) const useStyles = makeStyles(() => ({ app: { color: 'white', textAlign: 'center', padding: '0.5em', }, gallery: { textAlign: 'center', borderRadius: 25, border: '1px solid black', }, space: { padding: '2em', }, error: { color: 'red', }, rainbow: { backgroundImage: 'linear-gradient(to left, violet, indigo, blue, green, yellow, orange, red); -webkit-background-clip: text', color: 'transparent', }, })) function Gallery() { const [files, setFiles] = useState<DixieFile[]>() const [error, setError] = useState<unknown>() const [uploading, setUploading] = useState(false) const [initialStart, setParamStart] = useQueryParam('start', NumberParam) const [initialSort, setSortParam] = useQueryParam('sort', StringParam) const [initialFilter, setFilterParam] = useQueryParam('filter', StringParam) const [password] = useQueryParam('password', StringParam) const [counter, setCounter] = useState(0) const [filter, setFilter] = useState(initialFilter || 'all') const [sort, setSort] = useState(initialSort || 'date_uploaded_dec') const [start, setStart] = useState(initialStart || 0) const [dialogFile, setDialogFile] = useState<DixieFile>() const classes = useStyles() useEffect(() => { ;(async () => { try { const result = await myfetchjson(API_ENDPOINT + '/getDixieFiles') setFiles(result.Items) } catch (e) { setError(e) } })() }, [counter]) const filteredFiles = useMemo(() => { if (files) { if (filter === 'videos') { return files.filter(f => f.contentType.startsWith('video')) } else if (filter === 'no_videos') { return files.filter(f => !f.contentType.startsWith('video')) } else if (filter === 'commented_on') { return files.filter( f => f.comments !== undefined && f.comments.length > 0, ) } else return files } }, [files, filter]) const fileList = useMemo(() => { const future = +new Date('3000') const past = +new Date('1960') function getTimestamp(t: { exifTimestamp?: number }, repl: number) { return !t.exifTimestamp || t.exifTimestamp === past ? repl : t.exifTimestamp } if (filteredFiles) { if (sort === 'date_uploaded_asc') { return filteredFiles.sort((a, b) => a.timestamp - b.timestamp) } if (sort === 'date_uploaded_dec') { return filteredFiles.sort((a, b) => b.timestamp - a.timestamp) } if (sort === 'date_exif_asc') { return filteredFiles.sort( (a, b) => getTimestamp(a, future) - getTimestamp(b, future), ) } if (sort === 'date_exif_dec') { return filteredFiles.sort( (a, b) => getTimestamp(b, past) - getTimestamp(a, past), ) } if (sort === 'random') { return shuffle(filteredFiles) } } }, [filteredFiles, sort]) return ( <div className={classes.gallery}> <div> <h2>Dixies</h2> <p>Click image to open full size</p> <InputLabel id="demo-simple-select-label">Filter</InputLabel> <Select value={filter} onChange={event => { setFilter(event.target.value) setFilterParam(event.target.value) setStart(0) setParamStart(0) }} > <MenuItem value={'all'}>all</MenuItem> <MenuItem value={'commented_on'}>has been commented on</MenuItem> <MenuItem value={'videos'}>videos only</MenuItem> <MenuItem value={'no_videos'}>no videos</MenuItem> </Select> <InputLabel>Sort</InputLabel> <Select value={sort} onChange={event => { setSort(event.target.value) setSortParam(event.target.value) }} > <MenuItem value={'random'}>random</MenuItem> <MenuItem value={'date_exif_asc'}>exif date (asc)</MenuItem> <MenuItem value={'date_exif_dec'}>exif date (dec)</MenuItem> <MenuItem value={'date_uploaded_asc'}>date uploaded (asc)</MenuItem> <MenuItem value={'date_uploaded_dec'}>date uploaded (dec)</MenuItem> </Select> <br /> {password ? ( <IconButton color="primary" size="small" onClick={() => setUploading(true)} > add a dixie pic/video <Publish /> </IconButton> ) : null} </div> <UploadDialog open={uploading} onClose={() => { setUploading(false) setCounter(counter + 1) }} /> <Suspense fallback={<div />}> <PictureDialog file={dialogFile} onClose={() => { setDialogFile(undefined) }} /> </Suspense> {error ? ( <div className={classes.error}>{`${error}`}</div> ) : fileList ? ( fileList.slice(start, start + PAGE_SIZE).map(file => { const { comments = [] } = file const token = myimages[Math.floor(Math.random() * myimages.length)] const border = myborders[Math.floor(Math.random() * myborders.length)] const mod = 4 const useBorder = Math.floor(Math.random() * mod) === 0 const useImage = Math.floor(Math.random() * mod) === 0 const style: React.CSSProperties = { maxWidth: '90%', maxHeight: 400, boxSizing: 'border-box', border: useBorder ? '30px solid' : undefined, borderImage: useBorder ? `url(borders/${border}) 30 round` : undefined, } return ( <React.Fragment key={JSON.stringify(file)}> <Media file={{ ...file, filename: (file.contentType.startsWith('image') ? 'thumbnail-' : '') + file.filename, }} onClick={() => { setDialogFile(file) }} style={style} > {getCaption(file)} <Link href="#" onClick={() => { setDialogFile(file) }} > {' '} ({comments.length} comments) </Link> </Media> {useImage ? ( <img style={{ maxWidth: '20%', maxHeight: 100 + Math.random() * 50, padding: 20, }} src={`img/${token}`} /> ) : null} </React.Fragment> ) }) ) : null} {filteredFiles ? ( <div> <button onClick={() => { setStart(0) setParamStart(0) }} disabled={start === 0} > << First </button> <button onClick={() => { setStart(start - PAGE_SIZE) setParamStart(start - PAGE_SIZE) }} disabled={start - PAGE_SIZE < 0} > < Previous </button> <div style={{ display: 'inline' }}> {Math.floor(start / PAGE_SIZE)} /{' '} {Math.floor(filteredFiles.length / PAGE_SIZE)} </div> <button onClick={() => { setStart(start + PAGE_SIZE) setParamStart(start + PAGE_SIZE) }} disabled={start + PAGE_SIZE >= filteredFiles.length} > Next > </button> <button onClick={() => { setStart( filteredFiles.length - (filteredFiles.length % PAGE_SIZE), ) setParamStart( filteredFiles.length - (filteredFiles.length % PAGE_SIZE), ) }} disabled={start + PAGE_SIZE >= filteredFiles.length} > >> Last </button> </div> ) : null} </div> ) } function Header() { const classes = useStyles() return ( <div> <div className={classes.space}> <h1> <a style={{ color: 'white' }} href="/"> dixie </a> <img src="img/animated-candle-image-0093.gif.webp" style={{ height: '1em' }} /> </h1> <p>a pig that u never forget</p> <h3>2008-2020</h3> </div> </div> ) } function App() { const classes = useStyles() return ( <div className={classes.app}> <Header /> <div> <Gallery /> </div> <div style={{ margin: '0 auto', padding: '1em', width: '25%', minWidth: 300, }} > <p className={classes.rainbow}> created with love for the beautiful pig who touched our hearts </p> <img src="img/unnamed.gif.webp" width={20} /> <a href="mailto:[email protected]">contact</a> </div> </div> ) } export default App