mirror of
https://github.com/System-End/site.git
synced 2026-04-19 16:28:21 +00:00
YSWS
This commit is contained in:
parent
619ddf67a6
commit
bbfab02a13
5 changed files with 468 additions and 4 deletions
|
|
@ -28,7 +28,7 @@ const scrolled = props =>
|
||||||
height: 56px;
|
height: 56px;
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus {
|
&:focus {
|
||||||
animation: ${waveFlagScaled} 0.5s linear infinite alternate;
|
animation: ${waveFlagScaled} 0.3s ease-in-out infinite alternate;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ const Base = styled('a')`
|
||||||
}
|
}
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus {
|
&:focus {
|
||||||
animation: ${waveFlag} 0.5s linear infinite alternate;
|
animation: ${waveFlag} 0.2s ease-in-out infinite alternate;
|
||||||
}
|
}
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
animation: none !important;
|
animation: none !important;
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ const Root = styled(Box, {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
${fixed};
|
${fixed};
|
||||||
|
transition: background 0.15s;
|
||||||
@media print {
|
@media print {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
@ -144,8 +145,8 @@ const Navigation = props => (
|
||||||
</NextLink>
|
</NextLink>
|
||||||
<Link href="/slack">Community</Link>
|
<Link href="/slack">Community</Link>
|
||||||
<Link href="https://scrapbook.hackclub.com/">Scrapbook</Link>
|
<Link href="https://scrapbook.hackclub.com/">Scrapbook</Link>
|
||||||
<NextLink href="/onboard" passHref>
|
<NextLink href="/ysws" passHref>
|
||||||
<Link>OnBoard</Link>
|
<Link>You Ship, We Ship</Link>
|
||||||
</NextLink>
|
</NextLink>
|
||||||
</NavBar>
|
</NavBar>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
98
components/ysws/countdown.js
Normal file
98
components/ysws/countdown.js
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
import styled from '@emotion/styled'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { Box, Flex, Text } from 'theme-ui'
|
||||||
|
|
||||||
|
const CountdownWrapper = styled.div`
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(8, 1fr);
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const Value = styled.span(props => ({
|
||||||
|
textAlign: 'right',
|
||||||
|
marginLeft: '10px',
|
||||||
|
fontSize: props.big ? '3rem' : 'inherit',
|
||||||
|
textShadow: '0 0 0.4em #ff000090',
|
||||||
|
color: 'red'
|
||||||
|
}))
|
||||||
|
|
||||||
|
const Label = styled.span(props => ({
|
||||||
|
textAlign: 'left',
|
||||||
|
marginLeft: '10px',
|
||||||
|
fontSize: props.big ? '3rem' : 'inherit'
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default function Countdown({ targetDate }) {
|
||||||
|
const [timeLeft, setTimeLeft] = useState({
|
||||||
|
days: 0,
|
||||||
|
hours: 0,
|
||||||
|
minutes: 0,
|
||||||
|
seconds: 0,
|
||||||
|
milliseconds: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
const now = new Date().getTime()
|
||||||
|
const distance = targetDate.getTime() - now
|
||||||
|
|
||||||
|
if (distance < 0) {
|
||||||
|
clearInterval(interval)
|
||||||
|
setTimeLeft({
|
||||||
|
days: 0,
|
||||||
|
hours: 0,
|
||||||
|
minutes: 0,
|
||||||
|
seconds: 0,
|
||||||
|
milliseconds: 0
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
setTimeLeft({
|
||||||
|
days: Math.floor(distance / (1000 * 60 * 60 * 24)),
|
||||||
|
hours: Math.floor(
|
||||||
|
(distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
|
||||||
|
),
|
||||||
|
minutes: Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)),
|
||||||
|
seconds: Math.floor((distance % (1000 * 60)) / 1000),
|
||||||
|
milliseconds: distance % 1000
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, 10)
|
||||||
|
|
||||||
|
return () => clearInterval(interval)
|
||||||
|
}, [targetDate])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
fontFamily: "'7Seg', monospace",
|
||||||
|
fontSize: '1.5rem',
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box sx={{ marginY: 3 }}>
|
||||||
|
<Label>Ends in</Label>
|
||||||
|
|
||||||
|
<Box sx={{ lineHeight: 1 }}>
|
||||||
|
<Value big={true}>{String(timeLeft.days)}</Value>
|
||||||
|
<Label big={true}>DAY{timeLeft.days === 1 ? '' : 's'}</Label>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<CountdownWrapper>
|
||||||
|
<Value>{String(timeLeft.hours)}</Value>
|
||||||
|
<Label>HOUR{timeLeft.hours === 1 ? '' : 's'}</Label>
|
||||||
|
|
||||||
|
<Value>{String(timeLeft.minutes)}</Value>
|
||||||
|
<Label>MINUTE{timeLeft.minutes === 1 ? '' : 's'}</Label>
|
||||||
|
|
||||||
|
<Value>{String(timeLeft.seconds)}</Value>
|
||||||
|
<Label>SECOND{timeLeft.seconds === 1 ? '' : 's'}</Label>
|
||||||
|
|
||||||
|
<Value>{String(timeLeft.milliseconds)}</Value>
|
||||||
|
<Label>MILLISECONDS</Label>
|
||||||
|
</CountdownWrapper>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
365
pages/ysws.js
Normal file
365
pages/ysws.js
Normal file
|
|
@ -0,0 +1,365 @@
|
||||||
|
import { useState, useEffect, useReducer } from 'react'
|
||||||
|
import styled from '@emotion/styled'
|
||||||
|
import { keyframes } from '@emotion/react'
|
||||||
|
import { Box, Text, Flex, Image, Button } from 'theme-ui'
|
||||||
|
import Meta from '@hackclub/meta'
|
||||||
|
import Head from 'next/head'
|
||||||
|
import Nav from '../components/nav'
|
||||||
|
import ForceTheme from '../components/force-theme'
|
||||||
|
import { Zoom } from 'react-reveal'
|
||||||
|
import Countdown from '../components/ysws/countdown'
|
||||||
|
|
||||||
|
const projects = [
|
||||||
|
{
|
||||||
|
name: 'Sprig',
|
||||||
|
tagline: 'Every player is a creator.',
|
||||||
|
images: [
|
||||||
|
'https://sprig.hackclub.com/stories-tiny/sprig-front.jpeg',
|
||||||
|
'https://sprig.hackclub.com/stories-tiny/sprig-back.jpeg',
|
||||||
|
'https://sprig.hackclub.com/stories-tiny/play.jpeg',
|
||||||
|
'https://sprig.hackclub.com/stories-big/develop.jpeg',
|
||||||
|
'https://sprig.hackclub.com/stories-big/orpheus.jpeg'
|
||||||
|
],
|
||||||
|
stickers: ['/stickers/sprig.svg', '/stickers/sprig_holographic.png']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Blot',
|
||||||
|
tagline: 'Drawing machine',
|
||||||
|
images: [
|
||||||
|
'https://blot.hackclub.com/assets/control-board.webp',
|
||||||
|
'https://blot.hackclub.com/assets/all-parts.jpg',
|
||||||
|
'https://blot.hackclub.com/assets/code2.webp',
|
||||||
|
'https://blot.hackclub.com/assets/editor.png',
|
||||||
|
'https://raw.githubusercontent.com/hackclub/blot/main/art/tree-leo/snapshots/tree.png'
|
||||||
|
],
|
||||||
|
stickers: ['/stickers/Blot.png']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bin',
|
||||||
|
tagline: 'Bin description.',
|
||||||
|
images: [
|
||||||
|
'https://cloud-6hdo013ly-hack-club-bot.vercel.app/0buzzer.png',
|
||||||
|
'https://hackclub.com/bin/parts/pico.png',
|
||||||
|
'https://hackclub.com/bin/parts/led.png',
|
||||||
|
'https://hackclub.com/bin/parts/humidity.png',
|
||||||
|
'https://cloud-ofybe0euz-hack-club-bot.vercel.app/00oky3527-max7219-dot-matrix-module-single-3.png'
|
||||||
|
],
|
||||||
|
stickers: ['/stickers/sprig.svg', '/stickers/sprig_holographic.png']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Boba Drops',
|
||||||
|
tagline: 'Boba drops description',
|
||||||
|
images: [
|
||||||
|
'https://sprig.hackclub.com/stories-tiny/sprig-front.jpeg',
|
||||||
|
'https://sprig.hackclub.com/stories-tiny/sprig-back.jpeg'
|
||||||
|
],
|
||||||
|
stickers: ['/stickers/sprig.svg', '/stickers/sprig_holographic.png']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Bin',
|
||||||
|
tagline: 'Bin description.',
|
||||||
|
images: ['/stickers/sprig.svg'],
|
||||||
|
stickers: ['/stickers/sprig.svg', '/stickers/sprig_holographic.png']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const StyledImageBase = styled(Image)`
|
||||||
|
width: 30rem;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5);
|
||||||
|
`
|
||||||
|
|
||||||
|
const StyledImage = styled(StyledImageBase)`
|
||||||
|
position: absolute;
|
||||||
|
`
|
||||||
|
|
||||||
|
const slideInFromLeft = keyframes`
|
||||||
|
from {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateX(25%);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const slideInFromRight = keyframes`
|
||||||
|
from {
|
||||||
|
transform: translateX(100%);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateX(-25%);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const AnimatedText = styled(Text)`
|
||||||
|
display: inline-block;
|
||||||
|
`
|
||||||
|
|
||||||
|
const YouShipText = styled(AnimatedText)`
|
||||||
|
opacity: 0;
|
||||||
|
animation: ${slideInFromRight} 0.5s ease-out forwards;
|
||||||
|
`
|
||||||
|
|
||||||
|
const WeShipText = styled(AnimatedText)`
|
||||||
|
opacity: 0;
|
||||||
|
animation: ${slideInFromLeft} 0.5s ease-out forwards 0.5s;
|
||||||
|
`
|
||||||
|
|
||||||
|
const RotatingBox = styled(Box)`
|
||||||
|
will-change: transform;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
transition: transform 0.25s ease-in-out;
|
||||||
|
`
|
||||||
|
|
||||||
|
const randRot = () => Math.random() * 60 - 30
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
currentProjectIdx: 0,
|
||||||
|
rotAngle: 0,
|
||||||
|
imageRotations: []
|
||||||
|
}
|
||||||
|
|
||||||
|
function reducer(state, action) {
|
||||||
|
switch (action.type) {
|
||||||
|
case 'PROJECT_TICK':
|
||||||
|
console.log('tick!', state.imageRotations.length, state.currentProjectIdx)
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
currentProjectIdx:
|
||||||
|
state.imageRotations.length >= 5
|
||||||
|
? (state.currentProjectIdx + 1) % projects.length
|
||||||
|
: state.currentProjectIdx,
|
||||||
|
rotAngle: (360 / projects.length) * (state.currentProjectIdx + 1 - 1),
|
||||||
|
imageRotations: [...state.imageRotations, randRot()]
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Component() {
|
||||||
|
const [state, dispatch] = useReducer(reducer, initialState)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
dispatch({ type: 'PROJECT_TICK' })
|
||||||
|
}, 1_000)
|
||||||
|
return () => clearInterval(interval)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const currentProject = projects[state.currentProjectIdx]
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Box as="main">
|
||||||
|
<Meta
|
||||||
|
as={Head}
|
||||||
|
title="You Ship, We Ship"
|
||||||
|
description="You Ship, We Ship."
|
||||||
|
/>
|
||||||
|
<style>{`
|
||||||
|
@font-face {
|
||||||
|
font-family: '7Seg';
|
||||||
|
src: url('https://cloud-6okxw4gi2-hack-club-bot.vercel.app/0seven_segment.ttf') format('truetype');
|
||||||
|
font-weight: 500;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
html { scroll-behavior: smooth }
|
||||||
|
`}</style>
|
||||||
|
<Nav light />
|
||||||
|
<ForceTheme theme={'light'} />
|
||||||
|
|
||||||
|
<Flex
|
||||||
|
as="header"
|
||||||
|
sx={{
|
||||||
|
pt: 5,
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
bg: 'blue',
|
||||||
|
height: '80vh'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text
|
||||||
|
as="h1"
|
||||||
|
sx={{
|
||||||
|
position: 'relative',
|
||||||
|
fontSize: ['4rem', '5rem'],
|
||||||
|
lineHeight: 1.2,
|
||||||
|
color: 'white'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Zoom duration={500}>
|
||||||
|
<Image
|
||||||
|
src="/arcade/o3.png"
|
||||||
|
alt=""
|
||||||
|
width={128}
|
||||||
|
sx={{ position: 'absolute', left: '-75%' }}
|
||||||
|
/>
|
||||||
|
</Zoom>
|
||||||
|
<YouShipText sx={{ position: 'relative' }}>You Ship,</YouShipText>
|
||||||
|
<br />
|
||||||
|
<WeShipText>We Ship</WeShipText>
|
||||||
|
|
||||||
|
<Zoom delay={500} duration={500}>
|
||||||
|
<Image
|
||||||
|
src="/ysws/brown_prioritymail_box.png"
|
||||||
|
alt="USPS priority mail cardboard box"
|
||||||
|
width={128}
|
||||||
|
sx={{ position: 'absolute', right: '-60%', bottom: 0 }}
|
||||||
|
/>
|
||||||
|
</Zoom>
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginX: 'auto',
|
||||||
|
width: '100%',
|
||||||
|
maxWidth: '60vw',
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
marginY: 4
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'grid',
|
||||||
|
gridTemplateColumns: '1fr 2fr',
|
||||||
|
height: '100%',
|
||||||
|
perspective: '50px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
|
color: 'white',
|
||||||
|
position: 'relative'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p className="p-3 text-red-500 z-50">
|
||||||
|
{currentProject.name} - {state.currentProjectIdx}
|
||||||
|
</p>
|
||||||
|
<RotatingBox
|
||||||
|
data-angle={state.rotAngle}
|
||||||
|
sx={{ transform: `rotate3d(1, 0, 0, ${state.rotAngle}deg)` }}
|
||||||
|
>
|
||||||
|
{projects.toReversed().map((p, idx) => {
|
||||||
|
const radius = 120
|
||||||
|
|
||||||
|
const theta = idx * ((2 * Math.PI) / projects.length)
|
||||||
|
const x = radius * Math.cos(theta)
|
||||||
|
const y = radius * Math.sin(theta)
|
||||||
|
|
||||||
|
const angle = (theta * 180) / Math.PI + 360
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
key={idx}
|
||||||
|
sx={{
|
||||||
|
backfaceVisibility: 'hidden',
|
||||||
|
position: 'absolute',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
|
color: 'white',
|
||||||
|
translate: '0 -50% 0',
|
||||||
|
transform: `translate3d(0, ${y}px, ${x}px) rotate3d(1, 0, 0, ${angle}deg)`,
|
||||||
|
width: '100%',
|
||||||
|
willChange: 'transform'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text sx={{ fontSize: '4rem', fontWeight: 'bold' }}>
|
||||||
|
{p.name}
|
||||||
|
</Text>
|
||||||
|
<Text sx={{ fontSize: '2rem' }}>{p.tagline}</Text>
|
||||||
|
</Flex>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</RotatingBox>
|
||||||
|
|
||||||
|
{/* <Image
|
||||||
|
src={currentProject.stickers[0]}
|
||||||
|
alt=""
|
||||||
|
width={64}
|
||||||
|
height={64}
|
||||||
|
sx={{ rotate: '-15deg', position: 'absoulute', top: 0 }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Image
|
||||||
|
src={currentProject.stickers[1]}
|
||||||
|
alt=""
|
||||||
|
width={64}
|
||||||
|
height={64}
|
||||||
|
sx={{ rotate: '30deg' }}
|
||||||
|
/> */}
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
flexGrow: 1,
|
||||||
|
position: 'relative',
|
||||||
|
height: '100%'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{state.imageRotations.map((rot, idx) => (
|
||||||
|
<StyledImage
|
||||||
|
key={idx}
|
||||||
|
src={
|
||||||
|
currentProject.images[idx % currentProject.images.length]
|
||||||
|
}
|
||||||
|
alt=""
|
||||||
|
sx={{
|
||||||
|
left: '50%',
|
||||||
|
top: '50%',
|
||||||
|
transform: `rotate(${rot}deg)`,
|
||||||
|
translate: '-50% -50%',
|
||||||
|
zIndex: idx,
|
||||||
|
opacity: (idx + 1) / state.imageRotations.length,
|
||||||
|
transition: 'opacity 0.5s'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
flexDirection: 'column',
|
||||||
|
maxWidth: '80ch',
|
||||||
|
marginX: 'auto',
|
||||||
|
textAlign: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
py: 4
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text as="h2" sx={{ lineHeight: 1.2 }}>
|
||||||
|
LIMITED TIME EVENT
|
||||||
|
<br />
|
||||||
|
<Text sx={{ fontSize: '1.8em' }}>LLM Workshop</Text>
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Countdown targetDate={new Date('2024-10-12T23:59:59')} />
|
||||||
|
|
||||||
|
<Flex sx={{ flexDirection: 'column', marginY: 4, gap: 3 }}>
|
||||||
|
<Button sx={{ width: '100%', fontSize: '2em' }}>Get a book</Button>
|
||||||
|
<StyledImageBase
|
||||||
|
src="https://sprig.hackclub.com/stories-tiny/sprig-front.jpeg"
|
||||||
|
width="50%"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
BIN
public/ysws/brown_prioritymail_box.png
Normal file
BIN
public/ysws/brown_prioritymail_box.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 67 KiB |
Loading…
Add table
Reference in a new issue