This commit is contained in:
Malted 2024-10-15 12:56:59 -04:00
parent 619ddf67a6
commit bbfab02a13
No known key found for this signature in database
5 changed files with 468 additions and 4 deletions

View file

@ -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;

View file

@ -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>
) )

View 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
View 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>
</>
)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB