Merge branch 'main' of github.com:hackclub/site into pr/1324

This commit is contained in:
Max Wofford 2024-08-27 17:41:48 -04:00
commit 27ca656caa
16 changed files with 432 additions and 77 deletions

View file

@ -23,6 +23,7 @@
object-fit: cover;
aspect-ratio: 1 / 1;
border-radius: 5px;
object-fit: contain;
}
.card_img_container {

View file

@ -113,12 +113,16 @@ const ProjectView = ({
>
<style>
{`
* {
--color: ${color};
--dark-color: ${darkColor};
--text-color: ${textColor};
}
`}
* {
--color: ${color};
--dark-color: ${darkColor};
--text-color: ${textColor};
}
body {
background-color: var(--color);
}
`}
</style>
<div
sx={{

View file

@ -1,68 +1,68 @@
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
font-family: Arial, sans-serif;
}
.title {
font-size: 2.5rem;
margin-bottom: 20px;
text-align: center;
color: #333;
}
.image {
max-width: 24em;
max-height: 100%;
width: 100%;
height: auto;
border-radius: 8px;
margin: 0 auto;
max-width: 800px;
margin: 0 auto;
padding: 20px;
font-family: Arial, sans-serif;
}
.description {
font-size: 1.2rem;
/* color: #363636; */
margin-bottom: 30px;
line-height: 1.6;
font-weight: 500;
}
.title {
font-size: 2.5rem;
margin-bottom: 20px;
text-align: center;
color: #333;
}
.image {
max-width: 24em;
max-height: 100%;
width: 100%;
height: auto;
border-radius: 8px;
margin: 0 auto;
}
.description {
font-size: 1.2rem;
/* color: #363636; */
margin-bottom: 30px;
line-height: 1.6;
font-weight: 500;
}
.buttonGroup {
display: flex;
justify-content: center;
gap: 20px;
}
.button {
padding: 10px 20px;
background-color: #0070f3;
color: #fff;
text-decoration: none;
border-radius: 5px;
transition: background-color 0.3s ease;
}
.button:hover {
background-color: #005bb5;
}
.min{
min-height: 800px;
text-align: center;
}
.loading{
font-size: 2.5rem;
font-weight: 800px;
margin-bottom: 20px;
padding-top: 100px;
}
@media screen and (max-width: 500px) {
.buttonGroup {
display: flex;
justify-content: center;
gap: 20px;
flex-direction: column;
}
.button {
padding: 10px 20px;
background-color: #0070f3;
color: #fff;
text-decoration: none;
border-radius: 5px;
transition: background-color 0.3s ease;
}
.button:hover {
background-color: #005bb5;
}
.min{
min-height: 800px;
text-align: center;
}
.loading{
font-size: 2.5rem;
font-weight: 800px;
margin-bottom: 20px;
padding-top: 100px;
}
@media screen and (max-width: 500px) {
.buttonGroup {
flex-direction: column;
}
}
}

View file

@ -75,6 +75,7 @@
"react-masonry-css": "^1.0.16",
"react-page-visibility": "^7.0.0",
"react-relative-time": "^0.0.9",
"react-responsive-carousel": "^3.2.23",
"react-reveal": "^1.2.2",
"react-router-dom": "^6.22.3",
"react-scrolllock": "^5.0.1",

View file

@ -0,0 +1,30 @@
export default async function handler(req, res) {
if (req.method === 'GET') {
const { token } = req.query
if (!token) return res.status(400).json({ error: 'Token is required' })
try {
const url = new URL('http://takeout.hackclub.com/progress')
url.searchParams.append('token', token)
const response = await fetch(url)
if (!response.ok)
throw new Error(`HTTP error! status: ${response.status}`)
const data = await response.text()
console.info(data)
res.status(200).send(data)
} catch (error) {
console.error('Error fetching progress:', error)
res
.status(500)
.json({ error: 'Error fetching progress', message: error.message })
}
} else {
// Handle any non-GET requests
res.setHeader('Allow', ['GET'])
res.status(405).end(`Method ${req.method} Not Allowed`)
}
}

View file

@ -0,0 +1,31 @@
export default async function handler(req, res) {
if (req.method === 'POST') {
try {
const { token, email } = req.body
const url = new URL('http://takeout.hackclub.com/signup')
url.searchParams.append('token', token)
url.searchParams.append('email', email)
const response = await fetch(url, { method: 'POST' })
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const data = await response.text()
// Send the response from the replit-takeout service back to the client
res.status(200).json(data)
} catch (error) {
console.error('Error processing signup:', error)
res
.status(500)
.json({ message: 'Error processing signup', error: error.message })
}
} else {
// Handle any non-POST requests
res.setHeader('Allow', ['POST'])
res.status(405).end(`Method ${req.method} Not Allowed`)
}
}

View file

@ -84,6 +84,7 @@ export default function Shop({
description="Check out the prizes at the Arcade Shop!"
image="https://cloud-luaw423i2-hack-club-bot.vercel.app/0frame_33__1_.png"
/>
<meta name="darkreader-lock"/>
<style>
{`
._title-container {

254
pages/replit.js Normal file
View file

@ -0,0 +1,254 @@
import {
Box,
Link,
Grid,
Image,
Container,
Button,
Heading,
Text,
Label,
Input,
Card,
Progress
} from 'theme-ui'
import Head from 'next/head'
import Meta from '@hackclub/meta'
import Footer from '../components/footer'
import Nav from '../components/nav'
import { useState, useEffect } from 'react'
import useForm from '../lib/use-form'
import Submit from '../components/submit'
import ForceTheme from '../components/force-theme'
const ReplitPage = () => {
const [userDetails, setUserDetails] = useState({ token: null, email: null })
const [responseText, setResponseText] = useState('')
const [progressText, setProgressText] = useState(0)
useEffect(() => {
const token = localStorage.getItem('token')
const email = localStorage.getItem('email')
setUserDetails({ token, email })
setInterval(() => {
try {
fetch(`/api/replit/progress?token=${localStorage.getItem('token')}`)
.then(res => res.text())
.then(data => {
const split = data.split('/')
console.log(data, split)
setProgressText(split[0] / split[1])
})
} catch (e) {
console.warn(e)
}
}, 5_000)
}, [])
const handleSubmit = async event => {
event.preventDefault()
const formData = new FormData(event.target)
const data = {
email: formData.get('email'),
token: formData.get('token')
}
try {
const response = await fetch('/api/replit/signup', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
const result = await response.json()
localStorage.setItem('token', result.token)
localStorage.setItem('email', result.email)
setUserDetails({ token: result.token, email: result.email })
setResponseText('Success!')
} catch (error) {
setResponseText('Error submitting form')
console.error('Error:', error)
}
}
const tokenSteps = [
{
image: '/replit/aarc1.gif',
desc: "Open your browser's developer tools. You can do this by right-clicking on the page and selecting 'Inspect' or by pressing F12 on your keyboard."
},
{
image: '/replit/aarc2.gif',
desc: 'Select the application tab in the devtools'
},
{
image: '/replit/aarc3.gif',
desc: "Make sure replit.com cookies are selected, then scroll down to find 'connect.sid'. Copy the entire token & paste it in the form at the top of this page."
}
]
return (
<>
<Meta
as={Head}
title="Export your Repls"
description="Replit free has shut down. Export with Hack Club to GitHub Education's new free codespaces offering"
/>
<style>{`html { scroll-behavior: smooth; }`}</style>
<ForceTheme theme="light" />
<Nav />
<Box
as="header"
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
paddingTop: ['4rem', null, '6rem'],
paddingBottom: '1rem',
textAlign: 'center',
backgroundColor: 'black',
color: 'white'
}}
>
<Heading
as="h1"
sx={{
fontSize: '3em'
}}
>
Export your{' '}
<Text as="span" sx={{ display: 'inline-flex' }}>
Replit{' '}
<Image
src="/replit/replit.svg"
alt="replit"
sx={{ height: '1em' }}
/>
</Text>{' '}
repls
</Heading>
<Text sx={{ maxWidth: '80ch', fontSize: '1.2em', marginY: '1em' }}>
Replit has discontinued its free plan. Previously free features like
unlimited & private repls now cost $10 per month. GitHub Education is
offering free{' '}
<Link href="https://github.com/features/codespaces">Codespaces</Link>{' '}
to all students.
</Text>
</Box>
<Text sx={{ fontSize: '0.1rem' }}>{JSON.stringify(userDetails)}</Text>
<Box sx={{ maxWidth: '100ch', marginX: 'auto' }}>
<Box sx={{ marginTop: '3rem' }}>
<Heading as="h2" sx={{ marginBottom: '0.5em' }}>
Export your repls
</Heading>
<Card sx={{ background: 'smoke' }}>
<form onSubmit={handleSubmit}>
<Label sx={{ fontSize: 1 }} htmlFor="email">
Email
</Label>
<Input
name="email"
type="email"
defaultValue={userDetails.email}
/>
<Label sx={{ fontSize: 1, pt: 2 }} htmlFor="token">
Replit connect.sid token
</Label>
<Input name="token" defaultValue={userDetails.token} />
<Input
type="submit"
sx={{ backgroundColor: 'black', mt: '0.5rem', color: 'white' }}
text="Submit"
/>
</form>
<Text>{responseText}</Text>
{progressText ? (
<Box
sx={{
marginTop: '1rem',
display: 'flex',
flexDirection: 'column',
gap: '1rem',
alignItems: 'center'
}}
>
<Progress max={1} value={progressText}>
{progressText * 100}%
</Progress>
<Text sx={{ flexShrink: 0 }}>
{progressText * 100}% of your repls have processed.
{progressText <= 0 ? ' Please wait!' : null}
{progressText <= 1 ? ' Check your email!' : null}
</Text>
</Box>
) : null}
</Card>
</Box>
<Card sx={{ background: 'smoke', marginTop: '3rem' }}>
3: Something about free stickers
</Card>
<Box sx={{ marginTop: '3rem' }}>
<Heading as="h2" sx={{ marginBottom: '0.5em' }}>
How to get your Replit <code>connect.sid</code> token
</Heading>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
gap: '1rem'
}}
>
{tokenSteps.map((step, idx) => (
<Card
key={idx}
sx={{
lineHeight: 0,
background: 'smoke'
}}
>
<Heading as="h3" sx={{ lineHeight: 1.5 }}>
Step {idx + 1}
</Heading>
<Text sx={{ lineHeight: 1.5 }}>{step.desc}</Text>
<Image
src={step.image}
alt=""
sx={{ borderRadius: '0.25rem', marginTop: '1em' }}
/>
</Card>
))}
</Box>
<Link href="#">
<Button
sx={{
width: '100%',
backgroundColor: 'black',
marginTop: '2rem'
}}
>
Back to top
</Button>
</Link>
</Box>
</Box>
<Footer dark sx={{ marginTop: '3rem' }} />
</>
)
}
export default ReplitPage

BIN
public/replit/aarc1.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
public/replit/aarc2.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 MiB

BIN
public/replit/aarc3.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

1
public/replit/replit.svg Normal file
View file

@ -0,0 +1 @@
<svg width="24" height="24" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7 5.5C7 4.67157 7.67157 4 8.5 4H15.5C16.3284 4 17 4.67157 17 5.5V12H8.5C7.67157 12 7 11.3284 7 10.5V5.5Z" fill="#F26207"></path><path d="M17 12H25.5C26.3284 12 27 12.6716 27 13.5V18.5C27 19.3284 26.3284 20 25.5 20H17V12Z" fill="#F26207"></path><path d="M7 21.5C7 20.6716 7.67157 20 8.5 20H17V26.5C17 27.3284 16.3284 28 15.5 28H8.5C7.67157 28 7 27.3284 7 26.5V21.5Z" fill="#F26207"></path></svg>

After

Width:  |  Height:  |  Size: 500 B

BIN
public/replit/step one.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
public/replit/step two.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 935 KiB

View file

@ -2976,9 +2976,9 @@ camelize@^1.0.0:
integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==
caniuse-lite@^1.0.30001202, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001228, caniuse-lite@^1.0.30001282, caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001646:
version "1.0.30001651"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz#52de59529e8b02b1aedcaaf5c05d9e23c0c28138"
integrity sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==
version "1.0.30001653"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz#b8af452f8f33b1c77f122780a4aecebea0caca56"
integrity sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==
caseless@~0.12.0:
version "0.12.0"
@ -3098,7 +3098,7 @@ classnames@2.2.6:
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
classnames@^2.2.1, classnames@^2.2.6, classnames@^2.3.2:
classnames@^2.2.1, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.2:
version "2.5.1"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b"
integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==
@ -7346,7 +7346,7 @@ prop-types@15.7.2:
object-assign "^4.1.1"
react-is "^16.8.1"
prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@ -7535,6 +7535,13 @@ react-dom@^17.0.2:
object-assign "^4.1.1"
scheduler "^0.20.2"
react-easy-swipe@^0.0.21:
version "0.0.21"
resolved "https://registry.yarnpkg.com/react-easy-swipe/-/react-easy-swipe-0.0.21.tgz#ce9384d576f7a8529dc2ca377c1bf03920bac8eb"
integrity sha512-OeR2jAxdoqUMHIn/nS9fgreI5hSpgGoL5ezdal4+oO7YSSgJR8ga+PkYGJrSrJ9MKlPcQjMQXnketrD7WNmNsg==
dependencies:
prop-types "^15.5.8"
react-fast-compare@^3.0.1, react-fast-compare@^3.2.0:
version "3.2.2"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49"
@ -7647,6 +7654,15 @@ react-relative-time@^0.0.9:
resolved "https://registry.yarnpkg.com/react-relative-time/-/react-relative-time-0.0.9.tgz#2fcbd7e9a74ee82ff0eac24bfbd26a7dc2998ccc"
integrity sha512-Vf59erCwSaJaYp/IhoEtq7dtt1y4YNDqNegmOY8sK2P6oHHe3sLOXjz9VTCr0yvL2Y7W6uwufrxU4jOX8fS/dA==
react-responsive-carousel@^3.2.23:
version "3.2.23"
resolved "https://registry.yarnpkg.com/react-responsive-carousel/-/react-responsive-carousel-3.2.23.tgz#4c0016ff54603e604bb5c1f9e7ef2d1eda133f1d"
integrity sha512-pqJLsBaKHWJhw/ItODgbVoziR2z4lpcJg+YwmRlSk4rKH32VE633mAtZZ9kDXjy4wFO+pgUZmDKPsPe1fPmHCg==
dependencies:
classnames "^2.2.5"
prop-types "^15.5.8"
react-easy-swipe "^0.0.21"
react-reveal@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/react-reveal/-/react-reveal-1.2.2.tgz#f47fbc44debc4c185ae2163a215a9e822c7adfef"
@ -8515,7 +8531,16 @@ string-hash@1.1.3:
resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b"
integrity sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
string-width@^4.1.0:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@ -8626,7 +8651,7 @@ stringify-entities@^4.0.0:
character-entities-html4 "^2.0.0"
character-entities-legacy "^3.0.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@ -8640,6 +8665,13 @@ strip-ansi@6.0.0:
dependencies:
ansi-regex "^5.0.0"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^7.0.1:
version "7.1.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"