Refactor onboard gallery

This commit is contained in:
Max Wofford 2024-04-02 15:17:05 -04:00
parent 378c21aed4
commit a4459f7687
15 changed files with 466 additions and 499 deletions

View file

@ -0,0 +1,147 @@
import { useEffect, useRef } from "react"
import PaginationButtons from "./pagination-buttons"
import Meta from '@hackclub/meta'
import Head from 'next/head'
import { Box, Button, Flex, Grid, Heading, Text } from 'theme-ui'
import Item from './item'
import Nav from '../nav'
const perPage = 10
export const GalleryPage = ({currentPage, itemCount, currentProjects}) => {
const spotlightRef = useRef()
useEffect(() => {
const handler = event => {
spotlightRef.current.style.background = `radial-gradient(
circle at ${event.pageX}px ${event.pageY}px,
rgba(0, 0, 0, 0) 10px,
rgba(0, 0, 0, 0.8) 80px
)`
}
window.addEventListener('mousemove', handler)
return () => window.removeEventListener('mousemove', handler)
}, [])
return (
<>
<Meta
as={Head}
title="Gallery"
description="Check out the latest and greatest from the Onboard project."
></Meta>
<style>{`
@font-face {
font-family: 'Phantom Sans';
src: url('https://assets.hackclub.com/fonts/Phantom_Sans_0.7/Med.woff')
format('woff'),
url('https://assets.hackclub.com/fonts/Phantom_Sans_0.7/Med.woff2')
format('woff2');
font-weight: 500;
font-style: normal;
font-display: swap;
}
html {
scroll-behavior: smooth;
}
`}</style>
<Head></Head>
<Nav />
<Box
as="header"
sx={{
bg: '#000000',
backgroundImage: `
linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)),
url('https://cloud-dst3a9oz5-hack-club-bot.vercel.app/0image.png')
`,
color: '#ffffff',
position: 'relative'
}}
>
<Box
ref={spotlightRef}
sx={{
position: 'absolute',
zIndex: 2,
top: 0,
left: 0,
right: 0,
bottom: 0,
bg: '#000000',
pointerEvents: 'none'
}}
/>
<Flex
sx={{
p: 4,
flexDirection: 'column',
alignItems: 'center',
zIndex: 5,
position: 'relative'
}}
>
<Flex
sx={{
p: 4,
flexDirection: 'column',
alignItems: 'center',
zIndex: 5,
margin: '3vh auto',
position: 'relative'
}}
>
<Heading as="h1" variant="title" sx={{ textAlign: 'center' }}>
Gallery
</Heading>
<Text as="p" variant="subtitle" sx={{ textAlign: 'center' }}>
Check out the latest and greatest from the OnBoard project.
</Text>
<Flex sx={{ mt: 16, gap: 10, flexDirection: ['column', 'row'] }}>
<Button
variant="ctaLg"
as="a"
href="https://hackclub.com/onboard"
target="_blank"
sx={{
background: t => t.util.gx('#60cc38', '#113b11')
}}
>
Make your own!
</Button>
</Flex>
</Flex>
</Flex>
</Box>
<Box
sx={{
bg: 'white',
py: [4, 5],
textAlign: 'center'
}}
>
<PaginationButtons currentPage={currentPage} itemCount={itemCount} perPage={perPage} />
<Grid
gap={4}
columns={[null, 2]}
sx={{
p: 4,
maxWidth: 'copyPlus',
mx: 'auto',
mt: 4,
mb: 5,
textAlign: 'center'
}}
>
{currentProjects.map(project => (
<Item
key={project.name}
project={project}
/>
))}
</Grid>
<PaginationButtons currentPage={currentPage} itemCount={itemCount} perPage={perPage} />
</Box>
</>
)
}

View file

@ -1,76 +1,70 @@
import {Box, Divider, Flex, Heading, Image, Paragraph} from "theme-ui";
import {Link} from "theme-ui";
import React, {useContext} from "react";
import {OBJECT} from "swr/_internal";
import { Box, Flex, Heading, Paragraph } from "theme-ui";
import { Link } from "theme-ui";
function trim(str) {
return str.substring(1, str.length - 1)
}
// const onboardContext = React.createContext({})
const onboardContext = React.createContext({})
const Item = ({ title, author_name, author_slack, image, project }) => {
//const { projectCtx, setProjectCtx } = React.useContext(onboardContext)
return (
<Box
sx={{
bg: '#ffffff',
color: 'black',
borderRadius: 8,
boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)',
p: 4,
mt: 4,
position: 'relative'
}}
const Item = ({ project }) => {
const { name, imageTop, galleryURL } = project
// console.log({p: props})
return (
<Box
sx={{
bg: '#ffffff',
color: 'black',
borderRadius: 8,
boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)',
p: 4,
mt: 4,
position: 'relative'
}}
>
<Flex
sx={{
flexDirection: 'column',
alignItems: 'center'
}}
>
<object
data={imageTop}
type={'image/svg+xml'}
style={{
width: '100%',
borderRadius: '8px'
}}
></object>
<Link
href={galleryURL}
sx={{
textDecoration: 'none',
color: 'black',
':hover': {
color: 'primary'
}
}}
>
<Flex
sx={{
flexDirection: 'column',
alignItems: 'center'
}}
>
<object
data={image}
type={'image/svg+xml'}
style={{
width: '100%',
borderRadius: '8px'
}}
></object>
<Link
href={`/onboard/board/${project.project_name}`}
sx={{
textDecoration: 'none',
color: 'black',
':hover': {
color: 'primary'
}
}}
>
<Heading
as="h2"
//variant="title"
sx={{
textAlign: 'center',
mt: 3
}}
>
{title}
</Heading>
</Link>
<Paragraph
sx={{
textAlign: 'center',
mt: 2,
wordBreak: 'break-word'
}}
>
{`${author_name ? `by ${trim(author_name)}` : ""} ${author_slack ? `(${trim(author_slack)})` : ""}`}
</Paragraph>
</Flex>
</Box>
)
<Heading
as="h2"
sx={{
textAlign: 'center',
mt: 3
}}
>
{name}
</Heading>
</Link>
<Paragraph
sx={{
textAlign: 'center',
mt: 2,
wordBreak: 'break-word'
}}
>
{/* {`${author_name ? `by ${trim(author_name)}` : ""} ${author_slack ? `(${trim(author_slack)})` : ""}`} */}
</Paragraph>
</Flex>
</Box>
)
}
export default Item;
export { onboardContext };
// export { onboardContext };

View file

@ -0,0 +1,59 @@
import { Box, Button, Text } from "theme-ui"
const PaginationButtons = ({ currentPage, itemCount, perPage }) => {
const showPreviousPage = currentPage > 1
const showNextPage = itemCount > (currentPage * perPage)
return (
<Box
sx={{
mt: 5,
textAlign: 'center'
}}
>
{showPreviousPage && (
<Button
as="a"
href={`/onboard/gallery/${parseInt(currentPage) - 1}`}
sx={{
bg: 'black',
color: 'white',
':hover': {
bg: 'white',
color: 'black'
}
}}
>
{'<'}
</Button>
)}
<Text
as="span"
sx={{
mx: 3,
color: 'black'
}}
>
{currentPage}
</Text>
{showNextPage && (
<Button
as="a"
href={`/onboard/gallery/${parseInt(currentPage) + 1}`}
sx={{
bg: 'black',
color: 'white',
':hover': {
bg: 'white',
color: 'black'
}
}}
>
{'>'}
</Button>
)}
</Box>
)
}
export default PaginationButtons

View file

@ -290,7 +290,7 @@ const nextConfig = {
]
},
{
source: '/api/board/svg/(.+)',
source: '/api/onboard/svg/(.+)',
headers: [
{
key: 'content-type',

View file

@ -1,51 +0,0 @@
import {gerberToSvg} from "./svg/[board_url]";
export const FetchProject = async (name) => {
const readme = await fetch(`https://raw.githubusercontent.com/hackclub/OnBoard/main/projects/${name}/README.md`)
const text = await readme.text()
// parse YAML frontmatter
const lines = text.split('\n')
const frontmatter = {}
let i = 0
for (; i < lines.length; i++) {
if (lines[i].startsWith('---')) {
break
}
}
for (i++; i < lines.length; i++) {
if (lines[i].startsWith('---')) {
break
}
const [key, value] = lines[i].split(': ')
frontmatter[key] = value
}
// check for a "thumbnail.png" file in the project directory
//console.log(`https://github.com/snoglobe/OnBoard/raw/main/projects/${name}/thumbnail.png`)
/*const thumbnail = await fetch(`https://github.com/snoglobe/OnBoard/raw/main/projects/${name}/thumbnail.png`, {mode: 'no-cors'})*/
/*console.log(thumbnail)*/
const image = /*thumbnail.ok ? `https://github.com/snoglobe/OnBoard/raw/main/projects/${name}/thumbnail.png`
:*/ /*`data:image/svg+xml;base64,${btoa((await gerberToSvg(`https://github.com/snoglobe/OnBoard/raw/main/projects/${name}/gerber.zip`)).top)}`*/
`/api/board/svg/${encodeURIComponent(`https://github.com/snoglobe/OnBoard/raw/main/projects/${name}/gerber.zip`)}/top`
console.log("done")
return({
project_name: name ?? null,
maker_name: frontmatter.name ?? null,
slack_handle: frontmatter.slack_handle ?? null,
github_handle: frontmatter.github_handle ?? null,
tutorial: frontmatter.tutorial ?? null,
description: lines.slice(i + 1).join('\n') ?? null,
image: image ?? null
})
}
export default async function handler(req, res) {
const { name } = req.query
if (!name) {
return res.status(400).json({ status: 400, error: 'Must provide name' })
}
const project = await FetchProject(name)
if (!project) {
return res.status(404).json({ status: 404, error: 'Project not found' })
}
return res.status(200).json(project)
}

View file

@ -0,0 +1,52 @@
// return a project's metadata
import { getAllOnboardProjects } from ".."
async function getReadmeData(url) {
const readme = await fetch(url)
const text = await readme.text()
// parse YAML frontmatter
const lines = text.split('\n')
const frontmatter = {}
let i = 0
for (; i < lines.length; i++) {
if (lines[i].startsWith('---')) {
break
}
}
for (i++; i < lines.length; i++) {
if (lines[i].startsWith('---')) {
break
}
const [key, value] = lines[i].split(': ')
frontmatter[key] = value || null
}
const description = lines.slice(i + 1).join('\n')
return {
frontmatter,
description
}
}
export const getOnboardProject = async (name) => {
// this is not performant to call all projects every time, but we're doing it for now while things load quickly enough
// TODO: Speed this up
const project = (await getAllOnboardProjects()).find(p => p.name === name)
const readmeData = await getReadmeData(project.readmeURL)
const result = { ...project, readmeData }
return result
}
export default async function handler(req, res) {
const { name } = req.query
if (!name) {
return res.status(400).json({ status: 400, error: 'Must provide name' })
}
const project = await getOnboardProject(name)
if (!project) {
return res.status(404).json({ status: 404, error: 'Project not found' })
}
return res.status(200).json(project)
}

View file

@ -0,0 +1,12 @@
import { getAllOnboardProjects } from "."
export async function onboardProjectCount() {
const projects = await getAllOnboardProjects()
return projects.length
}
export default async function handler(req, res) {
const count = await onboardProjectCount()
res.json({ count })
}

View file

@ -0,0 +1,47 @@
// returns a list of all projects
export const getAllOnboardProjects = async () => {
const url = 'https://api.github.com/repos/hackclub/onboard/contents/projects'
const fetchOptions = {}
if (process.env.GITHUB_TOKEN) {
// this field is optional because we do heavy caching in production, but nice to have for local development
fetchOptions.headers = {Authorization: `Bearer ${process.env.GITHUB_TOKEN}`}
}
const res = await fetch(url, fetchOptions).then(r => r.json())
if (res.message && res.message.startsWith('API rate limit exceeded')) {
console.error('GitHub API rate limit exceeded')
}
const projects = []
res.forEach(p => {
if (p.type !== 'dir') { return }
if (p.name[0] === '.') { return }
if (p.name[0] === '!') { return }
const projectData = {
name: p.name,
url: `https://github.com/hackclub/OnBoard/tree/main/projects/${p.name}/README.md`,
galleryURL: `/onboard/gallery/${p.name}`,
githubURL: p.html_url,
readmeURL: `https://raw.githubusercontent.com/hackclub/OnBoard/main/projects/${p.name}/README.md`,
schematicURL: `https://raw.githubusercontent.com/hackclub/OnBoard/main/projects/${p.name}/schematic.pdf`,
gerberURL: `https://raw.githubusercontent.com/hackclub/OnBoard/main/projects/${p.name}/gerber.zip`
}
projectData.imageTop = `/api/onboard/svg/${encodeURIComponent(projectData.gerberURL)}/top`
projectData.imageBottom = `/api/onboard/svg/${encodeURIComponent(projectData.gerberURL)}/bottom`
projects.push(projectData)
})
return projects
}
export default async function handler(req, res) {
const projects = await getAllOnboardProjects()
res.json(projects)
}

View file

@ -1,16 +0,0 @@
async function onboardProjectCount() {
const url = 'https://api.github.com/repos/hackclub/onboard/contents/projects'
const response = await fetch(url).then(r => r.json())
const countedProjects = response.filter(
folder =>
folder.type === 'dir' && folder.name[0] !== '.' && folder.name[0] !== '!'
)
return countedProjects.length
}
export default async function handler(req, res) {
const count = await onboardProjectCount()
res.json({ count })
}

View file

@ -1,33 +1,14 @@
import { Box, Button, Flex, Grid, Heading, Image, Link, Text } from 'theme-ui'
import { Box, Button, Flex, Heading, Image, Link, Text } from 'theme-ui'
import Head from 'next/head'
import Meta from '@hackclub/meta'
import Nav from '../../../components/nav'
import usePrefersReducedMotion from '../../../lib/use-prefers-reduced-motion'
import { useEffect, useRef, useState } from 'react'
import { remark } from 'remark'
import html from 'remark-html'
import { useRouter } from 'next/router'
import { FetchProject } from '../../api/board/[name]'
// example projects
const curated = [
'Touch Capacitive Piano',
'Small Stepper Motor Breakout',
'ShawnsMultipurposeMacropad',
'Hall-Effect Sensor Plate',
'Gas_Smoke_Detector',
'GPS Tracker for GOKART',
"Ewoud's Desktop Clock PCB",
'Connor Ender 3 Bed Leveler'
]
const BoardPage = ({ projectObj }) => {
const prefersReducedMotion = usePrefersReducedMotion()
// const router = useRouter()
// get slug
// const name = router.query.slug
import { getOnboardProject } from '../../api/onboard/p/[project]'
import { getAllOnboardProjects } from '../../api/onboard/p'
const BoardPage = ({ project }) => {
const spotlightRef = useRef()
useEffect(() => {
const handler = event => {
@ -41,18 +22,6 @@ const BoardPage = ({ projectObj }) => {
return () => window.removeEventListener('mousemove', handler)
}, [])
console.log(projectObj)
const [project, setProject] = useState({})
useEffect(() => {
/*(async () => {
const project = await (await fetch(`/api/board/${name}`)).json()
console.log(project)
setProject(project)
})()*/
setProject(projectObj)
}, [projectObj])
return (
<>
<Meta
@ -123,9 +92,11 @@ const BoardPage = ({ projectObj }) => {
position: 'relative'
}}
>
<Heading as="h1" variant="title" sx={{ textAlign: 'center' }}>
Gallery
</Heading>
<Link as="a" href="/onboard/gallery" sx={{ color: 'white' }}>
<Heading as="h1" variant="title" sx={{ textAlign: 'center' }}>
Gallery
</Heading>
</Link>
<Text as="p" variant="subtitle" sx={{ textAlign: 'center' }}>
Check out the latest and greatest from the OnBoard project.
</Text>
@ -171,8 +142,8 @@ const BoardPage = ({ projectObj }) => {
}}
>
<Image
src={project.image}
alt={project.project_name}
src={project.imageTop}
alt={project.name}
sx={{
borderRadius: 8,
boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)'
@ -185,15 +156,22 @@ const BoardPage = ({ projectObj }) => {
justifyContent: 'center'
}}
>
{process.env.NODE_ENV !== 'production' && (
<>
<pre>
{JSON.stringify(project, null, 2)}
</pre>
</>
)}
<Heading as="h2" variant="title" sx={{ textAlign: 'left' }}>
{project.project_name}
{project.name}
</Heading>
<Text as="p" variant="subtitle" sx={{ textAlign: 'left' }}>
{project.maker_name ? `by ${project.maker_name}` : ''}{' '}
{project.slack_handle ? `(${project.slack_handle})` : ''}
{project?.readmeData?.frontmatter?.github_handle ? `by ${project?.readmeData?.frontmatter?.github_handle}` : ''}
</Text>
<Link
href={`https://github.com/hackclub/OnBoard/blob/main/projects/${project.project_name}/`}
target="_blank"
href={`https://github.com/hackclub/OnBoard/blob/main/projects/${project.name}/`}
sx={{
textDecoration: 'none',
color: 'black',
@ -205,7 +183,6 @@ const BoardPage = ({ projectObj }) => {
>
View on GitHub
</Link>
{/* custom innerHTML */}
<Box
sx={{
textAlign: 'left'
@ -215,7 +192,7 @@ const BoardPage = ({ projectObj }) => {
// render with remark to parse markdown
remark()
.use(html)
.processSync(project.description)
.processSync(project?.readmeData?.description)
.toString()
.replaceAll('h4', 'p')
}}
@ -228,19 +205,15 @@ const BoardPage = ({ projectObj }) => {
)
}
export async function getStaticPaths(context) {
const res = await fetch(
'https://api.github.com/repos/hackclub/OnBoard/contents/projects'
)
const data =
await res.json() /*.filter(project => curated.includes(project.name))*/
//console.log(data)
const projects = data.map(project => project.name)
const paths = projects.map(name => ({
params: {
slug: name
}
}))
export async function getStaticPaths(_context) {
const projects = await getAllOnboardProjects()
const paths = projects.map(project => {
return ({
params: {
slug: encodeURIComponent(project.name)
}
})
})
return {
paths,
fallback: 'blocking'
@ -248,12 +221,13 @@ export async function getStaticPaths(context) {
}
export async function getStaticProps(context) {
let name = context.params.slug
let project = await FetchProject(name)
const name = context.params.slug
const project = await getOnboardProject(name)
return {
props: {
projectObj: project
}
project
},
revalidate: 120
}
}

View file

@ -1,318 +1,41 @@
import { Box, Button, Flex, Grid, Heading, Text } from 'theme-ui'
import Head from 'next/head'
import Meta from '@hackclub/meta'
import Nav from '../../../components/nav'
import usePrefersReducedMotion from '../../../lib/use-prefers-reduced-motion'
import { useEffect, useRef, useState } from 'react'
import Item from '../../../components/onboard/item'
import { getUrl } from 'nextjs-current-url/server'
import { getURL } from 'next/dist/shared/lib/utils'
import { FetchProject } from '../../api/board/[name]'
import { useRouter } from 'next/router'
import { GalleryPage } from "../../../components/onboard/gallery-paginated";
/*import pcbStackup from "pcb-stackup";
import JSZip from "jszip";
import JSZipUtils from "jszip-utils";*/
import { getAllOnboardProjects } from "../../api/onboard/p"
import { getOnboardProject } from "../../api/onboard/p/[project]"
import { onboardProjectCount } from "../../api/onboard/p/count"
async function get_fallback_image(project) {
/*const fileNamesBlobs = {}
// load the zip file
const zip = new JSZip();
await JSZipUtils.getBinaryContent(project, async (err, data) => {
if (err) {
console.error(err)
}
try {
const zipData = await zip.loadAsync(data)
// get the file names and blobs
for (const [fileName, file] of Object.entries(zipData.files)) {
fileNamesBlobs[fileName] = await file.async('blob')
}
} catch (e) {
console.error(e)
}
})
const layers = []
for (const [fileName, blob] of Object.entries(fileNamesBlobs)) {
if (!fileName.includes('.txt')) { // filter out the text files
layers.push({
fileName,
gerber: blob.stream()
})
}
}
return (await pcbStackup(layers)).top.svg*/
return 'https://cloud-2jz3jz3jz-hack-club-bot.vercel.app/0image.png'
}
// example projects
const curated = [
'Touch Capacitive Piano',
'Small Stepper Motor Breakout',
'ShawnsMultipurposeMacropad',
'Hall-Effect Sensor Plate',
'Gas_Smoke_Detector',
'GPS Tracker for GOKART',
"Ewoud's Desktop Clock PCB",
'Connor Ender 3 Bed Leveler'
]
const GalleryPage = ({ projects }) => {
const prefersReducedMotion = usePrefersReducedMotion()
const router = useRouter()
const page = router.query.page
const spotlightRef = useRef()
useEffect(() => {
const handler = event => {
spotlightRef.current.style.background = `radial-gradient(
circle at ${event.pageX}px ${event.pageY}px,
rgba(0, 0, 0, 0) 10px,
rgba(0, 0, 0, 0.8) 80px
)`
}
window.addEventListener('mousemove', handler)
return () => window.removeEventListener('mousemove', handler)
}, [])
// fetch all folders in the https://github.com/hackclub/OnBoard/tree/main/projects directory
/*const [projects, setProjects] = useState([])
useEffect(() => {
const fetchProjects = async () => {
const res = await fetch(
'https://api.github.com/repos/hackclub/OnBoard/contents/projects'
)
const data = (await res.json()).filter(project => curated.includes(project.name))
console.log(data)
const projectData = data.map(async project => {
return await (await fetch(`/api/board/${project.name}`)).json()
})
let projects = await Promise.all(projectData)
//console.log(projects)
setProjects(projects)
}
fetchProjects()
}, [])*/
export default function Page({projects, itemCount, currentPage}) {
return (
<>
<Meta
as={Head}
title="Gallery"
description="Check out the latest and greatest from the Onboard project."
></Meta>
<style>{`
@font-face {
font-family: 'Phantom Sans';
src: url('https://assets.hackclub.com/fonts/Phantom_Sans_0.7/Med.woff')
format('woff'),
url('https://assets.hackclub.com/fonts/Phantom_Sans_0.7/Med.woff2')
format('woff2');
font-weight: 500;
font-style: normal;
font-display: swap;
}
html {
scroll-behavior: smooth;
}
`}</style>
<Head></Head>
<Nav />
<Box
as="header"
sx={{
bg: '#000000',
backgroundImage: `
linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7)),
url('https://cloud-dst3a9oz5-hack-club-bot.vercel.app/0image.png')
`,
color: '#ffffff',
position: 'relative'
}}
>
<Box
ref={spotlightRef}
sx={{
position: 'absolute',
zIndex: 2,
top: 0,
left: 0,
right: 0,
bottom: 0,
bg: '#000000',
pointerEvents: 'none'
}}
/>
<Flex
sx={{
p: 4,
flexDirection: 'column',
alignItems: 'center',
zIndex: 5,
position: 'relative'
}}
>
<Flex
sx={{
p: 4,
flexDirection: 'column',
alignItems: 'center',
zIndex: 5,
margin: '3vh auto',
position: 'relative'
}}
>
<Heading as="h1" variant="title" sx={{ textAlign: 'center' }}>
Gallery
</Heading>
<Text as="p" variant="subtitle" sx={{ textAlign: 'center' }}>
Check out the latest and greatest from the OnBoard project.
</Text>
<Flex sx={{ mt: 16, gap: 10, flexDirection: ['column', 'row'] }}>
<Button
variant="ctaLg"
as="a"
href="https://hackclub.com/onboard"
target="_blank"
sx={{
background: t => t.util.gx('#60cc38', '#113b11')
}}
>
Make your own!
</Button>
</Flex>
</Flex>
</Flex>
</Box>
<Box
sx={{
bg: 'white',
py: [4, 5],
textAlign: 'center'
}}
>
<Grid
gap={4}
columns={[null, 2]}
sx={{
p: 4,
maxWidth: 'copyPlus',
mx: 'auto',
mt: 4,
mb: 5,
textAlign: 'center'
}}
>
{projects.map(project => (
<Item
key={project.project_name}
title={project.project_name}
author_name={project.maker_name}
author_slack={project.slack_handle}
image={project.image}
project={project}
/>
))}
</Grid>
<Box
sx={{
mt: 5,
textAlign: 'center'
}}
>
<Button
as="a"
href={`/onboard/gallery/${parseInt(page) - 1}`}
sx={{
bg: 'black',
color: 'white',
':hover': {
bg: 'white',
color: 'black'
}
}}
>
{'<'}
</Button>
<Text
as="span"
sx={{
mx: 3,
color: 'black'
}}
>
{page}
</Text>
<Button
as="a"
href={`/onboard/gallery/${parseInt(page) + 1}`}
sx={{
bg: 'black',
color: 'white',
':hover': {
bg: 'white',
color: 'black'
}
}}
>
{'>'}
</Button>
</Box>
</Box>
</>
<GalleryPage currentPage={currentPage} itemCount={itemCount} currentProjects={projects} />
)
}
/*export async function getServerSideProps(context) {
const res = await fetch(
'https://api.github.com/repos/hackclub/OnBoard/contents/projects'
)
const data = (await res.json())/*.filter(project => curated.includes(project.name))
console.log(data)
const projectData = data.map(async project => {
const url = getUrl({ req: context.req })
console.log(url)
return await (await fetch(encodeURI(`${url.origin}/api/board/${project.name}`))).json()
})
let projects = await Promise.all(projectData)
return {
props: {
projects
}
}
}*/
export async function getStaticProps(context) {
const res = await fetch(
'https://api.github.com/repos/hackclub/OnBoard/contents/projects'
const currentPage = parseInt(context.params.page)
const allProjects = await getAllOnboardProjects()
const data = (allProjects).slice(
(currentPage - 1) * 10,
currentPage * 10
)
const data = (await res.json()).slice(
(parseInt(context.params.page) - 1) * 10,
parseInt(context.params.page) * 10
)
//console.log(data)
const projects = []
for (const project of data) {
projects.push(await FetchProject(project.name))
projects.push(await getOnboardProject(project.name))
}
return {
props: {
projects
}
projects,
itemCount: allProjects.length,
currentPage,
},
revalidate: 120 // 2 minutes
}
}
export async function getStaticPaths(context) {
// divide the projects into chunks of 10
const res = await fetch(
'https://api.github.com/repos/hackclub/OnBoard/contents/projects'
)
const data = await res.json()
const pages = Math.ceil(data.length / 10)
export async function getStaticPaths(_context) {
const projectCount = await onboardProjectCount()
const pages = Math.min(5, Math.ceil( projectCount / 10 ))
const paths = Array(pages)
.fill()
.map((_, i) => ({ params: { page: (i + 1).toString() } }))
return { paths, fallback: false }
}
export default GalleryPage
}

View file

@ -0,0 +1,26 @@
import { GalleryPage } from "../../../components/onboard/gallery-paginated";
import { getAllOnboardProjects } from "../../api/onboard/p";
import { getOnboardProject } from "../../api/onboard/p/[project]";
export default function Index({projects, itemCount}) {
return (
<GalleryPage currentPage={1} itemCount={itemCount} currentProjects={projects} />
)
}
export async function getStaticProps(_context) {
const allProjects = await getAllOnboardProjects()
const data = (allProjects).slice(0, 10)
const projects = []
for (const project of data) {
projects.push(await getOnboardProject(project.name))
}
return {
props: {
projects,
itemCount: allProjects.length,
},
revalidate: 120 // 2 minutes
}
}