mirror of
https://github.com/System-End/site.git
synced 2026-04-19 22:05:11 +00:00
Redesign replit site
This commit is contained in:
parent
f225f59947
commit
8a6300f63c
7 changed files with 396 additions and 88 deletions
237
components/replit/form.js
Normal file
237
components/replit/form.js
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
import { useState } from 'react'
|
||||
import { Box, Button, Card, Link, Input, Text, Flex, Image } from 'theme-ui'
|
||||
import Icon from '@hackclub/icons'
|
||||
|
||||
const ReplitForm = ({ cssDark }) => {
|
||||
const [currentStep, setCurrentStep] = useState(1)
|
||||
const [isSubmitted, setIsSubmitted] = useState(false)
|
||||
const [formData, setFormData] = useState({})
|
||||
|
||||
const handleInputChange = e => {
|
||||
const { name, value } = e.target
|
||||
setFormData(prev => ({ ...prev, [name]: value }))
|
||||
}
|
||||
|
||||
const submitForm = () => {
|
||||
console.log('submitting')
|
||||
}
|
||||
|
||||
const stickers = [
|
||||
'/stickers/orpheus-having-boba.png',
|
||||
'/stickers/find out.png',
|
||||
'/stickers/hackers,_assemble!.png',
|
||||
'/stickers/mo’ parts mo’ problems.png',
|
||||
'/stickers/orphmoji_peefest.png',
|
||||
'/stickers/skullpup_boba.png',
|
||||
'/stickers/hackers,_assemble!.png',
|
||||
'/stickers/orphmoji_yippee.png',
|
||||
'/replit/replit-fire.png'
|
||||
]
|
||||
|
||||
const fieldStyle = ({ disabled }) => ({
|
||||
border: '1.5px solid #0002',
|
||||
cursor: disabled ? 'not-allowed' : 'auto',
|
||||
opacity: disabled ? 0.5 : 1
|
||||
})
|
||||
|
||||
const buttonStyle = ({ disabled }) => ({
|
||||
backgroundColor: cssDark,
|
||||
cursor: disabled ? 'not-allowed' : 'auto',
|
||||
opacity: disabled ? 0.5 : 1
|
||||
})
|
||||
|
||||
const boxStyle = {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '.5em',
|
||||
alignItems: 'flex-start',
|
||||
position: 'relative'
|
||||
}
|
||||
|
||||
const step1 = () => {
|
||||
const fieldDisabled = currentStep !== 1 || isSubmitted
|
||||
const buttonDisabled = fieldDisabled || !formData.email
|
||||
|
||||
return (
|
||||
<Box sx={boxStyle} className="step">
|
||||
<Text sx={{ fontWeight: '700', opacity: fieldDisabled ? 0.5 : 1 }}>
|
||||
Email
|
||||
</Text>
|
||||
<Input
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
disabled={fieldDisabled}
|
||||
onChange={handleInputChange}
|
||||
sx={fieldStyle({ disabled: fieldDisabled })}
|
||||
/>{' '}
|
||||
<Button
|
||||
onClick={() => setCurrentStep(2)}
|
||||
disabled={buttonDisabled}
|
||||
sx={{
|
||||
width: '100%',
|
||||
...buttonStyle({ disabled: buttonDisabled })
|
||||
}}
|
||||
>
|
||||
<Icon glyph="down-caret" />
|
||||
Next
|
||||
</Button>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
const step2 = () => {
|
||||
const fieldDisabled = currentStep !== 2 || isSubmitted
|
||||
const backButtonDisabled = fieldDisabled
|
||||
const submitButtonDisabled =
|
||||
fieldDisabled || !formData.email || !formData.token
|
||||
|
||||
return (
|
||||
<Box sx={boxStyle} className="step">
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
gap: '0.5em',
|
||||
alignItems: 'baseline',
|
||||
opacity: fieldDisabled ? 0.5 : 1
|
||||
}}
|
||||
>
|
||||
<Text sx={{ fontWeight: '700' }}>
|
||||
Replit <code>connect.sid</code> token{' '}
|
||||
</Text>
|
||||
<Link sx={{ fontSize: '0.8em' }} href="#instructions">
|
||||
How do I find this?
|
||||
</Link>
|
||||
</Box>
|
||||
<Input
|
||||
id="token"
|
||||
name="token"
|
||||
placeholder="Enter your replit token"
|
||||
required
|
||||
disabled={fieldDisabled}
|
||||
onChange={handleInputChange}
|
||||
sx={fieldStyle({ disabled: fieldDisabled })}
|
||||
/>{' '}
|
||||
<Flex
|
||||
sx={{ width: '100%', justifyContent: 'space-between', gap: '1rem' }}
|
||||
>
|
||||
<Button
|
||||
onClick={() => setCurrentStep(1)}
|
||||
disabled={backButtonDisabled}
|
||||
sx={{
|
||||
flexShrink: '0',
|
||||
...buttonStyle({ disabled: backButtonDisabled })
|
||||
}}
|
||||
>
|
||||
<Icon glyph="up-caret" /> Back
|
||||
</Button>
|
||||
<Button
|
||||
onClick={submitForm}
|
||||
disabled={submitButtonDisabled}
|
||||
sx={{
|
||||
width: '100%',
|
||||
...buttonStyle({ disabled: submitButtonDisabled })
|
||||
}}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Flex>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
const step3 = () => (
|
||||
<Box
|
||||
sx={{
|
||||
...boxStyle,
|
||||
opacity: currentStep === 3 ? 1 : 0.5
|
||||
}}
|
||||
className="step"
|
||||
>
|
||||
<Text sx={{ fontWeight: '700' }}>Stickers</Text>
|
||||
<Text>
|
||||
Get free stickers Get free stickers Get free stickers Get free stickers
|
||||
Get free stickers Get free stickers Get free stickers Get free stickers
|
||||
Get free stickers Get free stickers{' '}
|
||||
</Text>
|
||||
|
||||
<style>
|
||||
{`
|
||||
.sticker {
|
||||
scale: 1;
|
||||
filter: drop-shadow(0 0 0.2rem #0008);
|
||||
transition: scale 0.1s, filter 0.1s;
|
||||
}
|
||||
|
||||
.sticker:hover {
|
||||
scale: 1.2;
|
||||
filter: drop-shadow(0 0 0.6rem #0004);
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
{stickers.map((sticker, idx) => {
|
||||
const pos = getRandomPointOnUnitSquare()
|
||||
return (
|
||||
<Image
|
||||
src={sticker}
|
||||
width="64"
|
||||
height="64"
|
||||
alt="orpheus dinosaur labelled 'hackers assemble'"
|
||||
className="sticker"
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
rotate: `${(Math.random() - 0.5) * 80}deg`,
|
||||
left: `${pos[0] * 100}%`,
|
||||
top: `${pos[1] * 100}%`,
|
||||
translate: '-50% -50%'
|
||||
}}
|
||||
draggable="false"
|
||||
key={idx}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</Box>
|
||||
)
|
||||
|
||||
function getRandomPointOnUnitSquare() {
|
||||
const side = Math.floor(Math.random() * 4)
|
||||
const position = Math.random()
|
||||
const margin = 0.1
|
||||
|
||||
switch (side) {
|
||||
case 0:
|
||||
return [-margin, position]
|
||||
case 1:
|
||||
return [position, 1 + margin]
|
||||
case 2:
|
||||
return [1 + margin, 1 - position]
|
||||
case 3:
|
||||
return [1 - position, -margin]
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Card
|
||||
sx={{
|
||||
width: '30rem',
|
||||
marginX: 'auto',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '2rem',
|
||||
overflow: 'initial'
|
||||
}}
|
||||
>
|
||||
<Text sx={{ fontSize: '0.6rem' }}>{formData.email || 'no email'}</Text>
|
||||
<Text sx={{ fontSize: '0.6rem' }}>{formData.token || 'no token'}</Text>
|
||||
|
||||
<style>{`.step { transition: opacity 0.1s; }`}</style>
|
||||
{step1()}
|
||||
{step2()}
|
||||
{step3()}
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default ReplitForm
|
||||
238
pages/replit.js
238
pages/replit.js
|
|
@ -16,38 +16,52 @@ 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 { useState, useEffect, useRef } from 'react'
|
||||
import Submit from '../components/submit'
|
||||
import ForceTheme from '../components/force-theme'
|
||||
import ReplitForm from '../components/replit/form'
|
||||
|
||||
const ReplitPage = () => {
|
||||
const [userDetails, setUserDetails] = useState({ token: null, email: null })
|
||||
const [token, setToken] = useState('')
|
||||
const [email, setEmail] = useState('')
|
||||
|
||||
const [submitStatus, setSubmitStatus] = useState('default')
|
||||
const [responseText, setResponseText] = useState('')
|
||||
const [progressText, setProgressText] = useState(0)
|
||||
|
||||
const intervalRef = useRef(null)
|
||||
|
||||
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)
|
||||
if (token) setToken(token)
|
||||
if (email) setEmail(email)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (token) {
|
||||
intervalRef.current = setInterval(() => {
|
||||
try {
|
||||
fetch(`/api/replit/progress?token=${token}`)
|
||||
.then(res => res.text())
|
||||
.then(data => {
|
||||
const split = data.split('/')
|
||||
setProgressText(split[0] / split[1])
|
||||
})
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
}
|
||||
}, 5000)
|
||||
}
|
||||
|
||||
return () => {
|
||||
clearInterval(intervalRef.current)
|
||||
}
|
||||
}, [token])
|
||||
|
||||
const handleSubmit = async event => {
|
||||
setSubmitStatus('submitting')
|
||||
event.preventDefault()
|
||||
const formData = new FormData(event.target)
|
||||
const data = {
|
||||
|
|
@ -59,22 +73,31 @@ const ReplitPage = () => {
|
|||
const response = await fetch('/api/replit/signup', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
body: new URLSearchParams(data).toString()
|
||||
})
|
||||
|
||||
const result = await response.json()
|
||||
localStorage.setItem('token', result.token)
|
||||
localStorage.setItem('email', result.email)
|
||||
setUserDetails({ token: result.token, email: result.email })
|
||||
setResponseText('Success!')
|
||||
const result = await response.text()
|
||||
setResponseText(result)
|
||||
|
||||
// Store the email and token in localStorage
|
||||
localStorage.setItem('token', data.token)
|
||||
localStorage.setItem('email', data.email)
|
||||
setSubmitStatus('success')
|
||||
} catch (error) {
|
||||
setSubmitStatus('error')
|
||||
setResponseText('Error submitting form')
|
||||
console.error('Error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const steps = [
|
||||
'Enter your email',
|
||||
'Enter your replit token',
|
||||
'Get free stickers'
|
||||
]
|
||||
|
||||
const tokenSteps = [
|
||||
{
|
||||
image: '/replit/aarc1.gif',
|
||||
|
|
@ -90,6 +113,8 @@ const ReplitPage = () => {
|
|||
}
|
||||
]
|
||||
|
||||
const cssDark = 'hsl(23, 94%, 32%)'
|
||||
|
||||
return (
|
||||
<>
|
||||
<Meta
|
||||
|
|
@ -97,7 +122,7 @@ const ReplitPage = () => {
|
|||
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>
|
||||
<style>{`html { scroll-behavior: smooth; } body { background-color: hsl(23, 94%, 96%); }`}</style>
|
||||
<ForceTheme theme="light" />
|
||||
<Nav />
|
||||
<Box
|
||||
|
|
@ -109,97 +134,135 @@ const ReplitPage = () => {
|
|||
paddingTop: ['4rem', null, '6rem'],
|
||||
paddingBottom: '1rem',
|
||||
textAlign: 'center',
|
||||
backgroundColor: 'black',
|
||||
backgroundColor: cssDark,
|
||||
color: 'white'
|
||||
}}
|
||||
>
|
||||
<Heading
|
||||
as="h1"
|
||||
sx={{
|
||||
fontSize: '3em'
|
||||
fontSize: '4em'
|
||||
}}
|
||||
onMouseOver={() => {
|
||||
document.getElementById('og-replit').style.opacity = '0'
|
||||
document.getElementById('fire-replit').style.opacity = '1'
|
||||
}}
|
||||
onMouseOut={() => {
|
||||
document.getElementById('og-replit').style.opacity = '1'
|
||||
document.getElementById('fire-replit').style.opacity = '0'
|
||||
}}
|
||||
>
|
||||
Export your{' '}
|
||||
<Text as="span" sx={{ display: 'inline-flex' }}>
|
||||
Replit{' '}
|
||||
<Text
|
||||
as="span"
|
||||
sx={{
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
position: 'relative'
|
||||
}}
|
||||
>
|
||||
Replit <style>{`.replit-fire {transition: opacity 0.1s;`}</style>
|
||||
<Image
|
||||
src="/replit/replit.svg"
|
||||
alt="replit"
|
||||
sx={{ height: '1em' }}
|
||||
id="og-replit"
|
||||
className="replit-fire"
|
||||
/>
|
||||
<Image
|
||||
src="/replit/replit-fire-nooutline.png"
|
||||
alt="replit"
|
||||
sx={{
|
||||
height: '1.35em',
|
||||
translate: '-0.095em -0.195em',
|
||||
position: 'absolute',
|
||||
right: 0
|
||||
}}
|
||||
id="fire-replit"
|
||||
className="replit-fire"
|
||||
/>
|
||||
</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.
|
||||
On 25th August, Replit cut down its free plan - it's now unusable.
|
||||
<br />
|
||||
Previously, you got unlimited repls for free, for as long as you
|
||||
wanted.
|
||||
<br />
|
||||
Now you get three repls, for 600 minutes per month (20 mins/day).
|
||||
</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 as="main" sx={{ maxWidth: '100ch', marginX: 'auto' }}>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
marginTop: '2rem',
|
||||
position: 'relative',
|
||||
paddingX: [null, null, '6rem']
|
||||
}}
|
||||
>
|
||||
{steps.map((step, idx) => (
|
||||
<Box
|
||||
key={idx}
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
fontWeight: '600',
|
||||
paddingX: '.25em'
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: '1rem',
|
||||
width: '1.5em',
|
||||
height: '1.5em',
|
||||
backgroundColor: cssDark,
|
||||
color: 'white',
|
||||
borderRadius: '999px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '1rem',
|
||||
alignItems: 'center'
|
||||
alignItems: 'center',
|
||||
justifyContent: '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>
|
||||
<Text>{idx + 1}</Text>
|
||||
</Box>
|
||||
) : null}
|
||||
</Card>
|
||||
<Text sx={{ textAlign: 'center' }}>{step}</Text>
|
||||
</Box>
|
||||
))}
|
||||
|
||||
<Image
|
||||
src="/replit/arrow1.svg"
|
||||
alt=""
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
width: `${7 * 0.9384843737}em`,
|
||||
bottom: '-1.5em',
|
||||
left: '32.5%',
|
||||
translate: '-50% 0'
|
||||
}}
|
||||
/>
|
||||
<Image
|
||||
src="/replit/arrow2.svg"
|
||||
alt=""
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
width: '7em',
|
||||
bottom: '-2em',
|
||||
left: '67%',
|
||||
translate: '-50% 0'
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Card sx={{ background: 'smoke', marginTop: '3rem' }}>
|
||||
3: Something about free stickers
|
||||
</Card>
|
||||
|
||||
<Box sx={{ marginTop: '3rem' }}>
|
||||
<ReplitForm cssDark={cssDark} />
|
||||
</Box>
|
||||
|
||||
<Box sx={{ paddingTop: '5rem' }} id="instructions">
|
||||
<Heading as="h2" sx={{ marginBottom: '0.5em' }}>
|
||||
How to get your Replit <code>connect.sid</code> token
|
||||
</Heading>
|
||||
|
|
@ -215,8 +278,7 @@ const ReplitPage = () => {
|
|||
<Card
|
||||
key={idx}
|
||||
sx={{
|
||||
lineHeight: 0,
|
||||
background: 'smoke'
|
||||
lineHeight: 0
|
||||
}}
|
||||
>
|
||||
<Heading as="h3" sx={{ lineHeight: 1.5 }}>
|
||||
|
|
@ -236,7 +298,7 @@ const ReplitPage = () => {
|
|||
<Button
|
||||
sx={{
|
||||
width: '100%',
|
||||
backgroundColor: 'black',
|
||||
backgroundColor: cssDark,
|
||||
marginTop: '2rem'
|
||||
}}
|
||||
>
|
||||
|
|
|
|||
3
public/replit/arrow.svg
Normal file
3
public/replit/arrow.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="200" height="53" viewBox="0 0 200 53" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1.67773 13.6281C10.2959 18.1639 16.9038 25.0627 24.8551 30.5819C35.0596 37.665 46.8025 42.0558 58.6554 45.4969C84.7365 53.0688 116.698 54.3311 141.278 41.7413C159.831 32.2389 177.68 13.4214 197.612 7.72643C200.605 6.87139 190.484 2.79867 189.457 2.46861C185.044 1.05016 179.242 2.0394 174.649 2.0394C167.022 2.0394 160.354 -0.452366 168.211 7.40453C176.762 15.9554 183.119 26.0534 190.959 34.874C197.899 42.6813 194.822 26.9622 194.822 21.3538C194.822 15.5595 194.822 9.76518 194.822 3.97085" stroke="black" stroke-width="3" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 665 B |
3
public/replit/arrow1.svg
Normal file
3
public/replit/arrow1.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="118" height="26" viewBox="0 0 118 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 10.8721C7.25157 12.3704 12.0525 15.2994 17.2117 17.1005C30.6611 21.7959 46.1657 24.7985 60.408 24.3072C76.3805 23.7561 89.4938 14.8028 104.561 12.1173M93.3317 2C97.5088 2.61154 113.289 2.26156 115.319 6.16048C118.217 11.7258 107.435 19.5088 104.08 22.6393" stroke="black" stroke-width="3" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 431 B |
3
public/replit/arrow2.svg
Normal file
3
public/replit/arrow2.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="125" height="34" viewBox="0 0 125 34" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1.8374 7.50231C6.55355 8.71811 11.0298 13.0652 15.2506 15.5659C24.8783 21.2699 34.5855 25.9934 45.4744 28.8006C64.7149 33.7606 81.1698 33.4312 98.8758 23.7721C104.35 20.7856 109.846 16.4272 114.497 12.2608M103.191 4.15929C106.705 5.05753 109.703 4.1116 113.266 4.03799C115.189 3.99826 121.154 0.78357 122.62 1.64021C123.793 2.32494 122.578 19.9954 121.975 22.353" stroke="black" stroke-width="3" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 536 B |
BIN
public/replit/replit-fire-nooutline.png
Normal file
BIN
public/replit/replit-fire-nooutline.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
BIN
public/replit/replit-fire.png
Normal file
BIN
public/replit/replit-fire.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
Loading…
Add table
Reference in a new issue