Merge branch 'main' into onboard_gallery

This commit is contained in:
Max Wofford 2024-04-02 12:27:25 -04:00 committed by GitHub
commit 6ad6e66fd0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
53 changed files with 1242 additions and 772 deletions

32
.github/workflows/caniuse-update.yml vendored Normal file
View file

@ -0,0 +1,32 @@
name: Update Browserslist database
on:
workflow_dispatch:
schedule:
- cron: '0 2 1,15 * *'
permissions:
contents: write
pull-requests: write
jobs:
update-browserslist-database:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure git
run: |
git config --global user.email "action@github.com"
git config --global user.name "GitHub Action"
- name: Update Browserslist database and create PR if applies
uses: c2corg/browserslist-update-action@v2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: browserslist-update
base_branch: main
commit_message: 'build: update Browserslist db'
title: 'build: update Browserslist db'
body: Auto-generated by [browserslist-update-action](https://github.com/c2corg/browserslist-update-action/). Caniuse database has been updated. Review changes, merge this PR, and be merry.

7
.prettierrc Executable file
View file

@ -0,0 +1,7 @@
{
"singleQuote": true,
"trailingComma": "none",
"arrowParens": "avoid",
"printWidth": 80,
"semi": false
}

View file

@ -3,7 +3,8 @@ import Icon from '@hackclub/icons'
import { useState } from 'react'
export default function Bio({ popup = true, spanTwo = false, ...props }) {
let { img, name, teamRole, pronouns, text, subrole, href, video } = props
let { img, name, teamRole, pronouns, text, subrole, email, href, video } =
props
const [expand, setExpand] = useState(false)
return (
<>
@ -94,6 +95,13 @@ export default function Bio({ popup = true, spanTwo = false, ...props }) {
)}
</Text>
</Flex>
{!popup && email && (
<Text color="muted" as={'a'} href={`mailto:${email}@hackclub.com`}>
{email}@hackclub.com
<br />
</Text>
)}
{!popup && (
<>
<Text mt={2} mb={0} color="black">

View file

@ -0,0 +1,37 @@
import { useEffect, useState } from 'react'
import Icon from '../../icon'
import { useRouter } from 'next/router'
export default function Checkbox({ name, defaultChecked = false, size = 38 }) {
const [checked, setChecked] = useState(defaultChecked)
const toggle = () => setChecked(!checked)
const router = useRouter()
/* Fill in the field with the value from sessionStorage.
For other input elements, the value is set in the Field component,
but these checkboxes hold their state in useState rather than in the DOM. */
useEffect(() => {
const value = router.query[name] || sessionStorage.getItem('bank-signup-' + name)
if (value) {
const input = document.getElementById(name)
input && setChecked(!!value)
}
}, [router.query, name])
return (
<>
<input aria-hidden="true" type="hidden" value={checked} name={name} />
<Icon
glyph={checked ? 'checkmark' : 'checkbox'}
size={size}
id={name}
name={name}
aria-checked={checked}
role="checkbox"
tabindex="0"
onClick={() => toggle()}
onKeyDown={e => e.key === 'Enter' && toggle()}
/>
</>
)
}

View file

@ -1,6 +1,6 @@
import { useState, useEffect } from 'react'
import { Input, Select, Textarea } from 'theme-ui'
// import Checkbox from './checkbox'
import Checkbox from './checkbox'
import Field from './field'
// This is using country-list instead of country-list-js as it has a smaller bundle size
import { getNames } from 'country-list'
@ -54,10 +54,10 @@ export default function OrganizationInfoForm({ requiredFields }) {
))}
</Select>
</Field>
{/* <Field
<Field
name="transparent"
label="Transparency mode"
col={false}
col={true}
description={`
Transparent accounts balances and donations are public.
You choose who has access to personal details.
@ -67,7 +67,7 @@ export default function OrganizationInfoForm({ requiredFields }) {
requiredFields={requiredFields}
>
<Checkbox defaultChecked={true} name="transparent" />
</Field> */}
</Field>
<Field
name="eventDescription"
label={`Tell us about your ${org.toLowerCase()}`}

View file

@ -84,6 +84,7 @@ export default function PersonalInfoForm({ requiredFields }) {
<div />
<Field
label="Your Hack Club Slack username"
description="For teenagers only!"
name="slackUsername"
requiredFields={requiredFields}
>
@ -111,7 +112,7 @@ export default function PersonalInfoForm({ requiredFields }) {
name="userPhone"
id="userPhone"
type="tel"
placeholder="1-855-625-HACK"
placeholder="+1 (844) 237 2290"
/>
</Field>
<Field

View file

@ -0,0 +1,36 @@
import Icon from '../icon'
import { Flex, Link, Text } from 'theme-ui'
const phoneNumber = '+1 (844) 237-2290'
const phoneNumberUri = '+1-844-237-2290'
const email = 'hcb@hackclub.com'
export default function ContactBanner({ sx }) {
return (
<Flex
sx={{
bg: 'sunken',
color: 'slate',
alignItems: 'center',
p: 3,
gap: [3, 2],
...sx
}}
>
<Icon
glyph="message"
sx={{ color: 'inherit', flexShrink: 0, my: -1 }}
aria-hidden
/>
<Text
sx={{
textWrap: 'balance',
a: { color: 'inherit', mx: '0.125em', whiteSpace: 'nowrap' }
}}
>
Questions? Email <Link href={`mailto:${email}`}>{email}</Link>{' '}
or&nbsp;call <Link href={`tel:${phoneNumberUri}`}>{phoneNumber}</Link>
</Text>
</Flex>
)
}

View file

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react'
import styled from '@emotion/styled'
import { css, keyframes } from '@emotion/react'
import { Box, Container, Flex, Link, Text } from 'theme-ui'
import { Box, Container, Flex, Link } from 'theme-ui'
import theme from '../lib/theme'
import Icon from './icon'
import Flag from './flag'
@ -68,7 +68,7 @@ const hoverColor = name =>
slate: 'black',
black: 'slate',
primary: 'error'
}[name] || 'black')
})[name] || 'black'
const slide = keyframes({
from: { transform: 'translateY(-25%)', opacity: 0 },
@ -198,13 +198,13 @@ function Header({ unfixed, color, bgColor, dark, fixed, ...props }) {
const baseColor = dark
? color || 'white'
: color === 'white' && scrolled
? 'black'
: color
? 'black'
: color
const toggleColor = dark
? color || 'snow'
: toggled || (color === 'white' && scrolled)
? 'slate'
: color
? 'slate'
: color
return (
<Root

View file

@ -0,0 +1,41 @@
import { useMemo } from "react"
const YoutubeVideo = ({
'youtube-id': youtubeID = 'dQw4w9WgXcQ',
list,
title = "YouTube video player",
width,
height,
}) => {
const src = useMemo(() => {
const url = new URL(`https://www.youtube.com/embed/${youtubeID}`)
if (list) {
url.searchParams.set('list', list)
}
return url
}, [youtubeID, list])
const allowlist = [
'accelerometer',
'autoplay',
'clipboard-write',
'encrypted-media',
'gyroscope',
'picture-in-picture',
'web-share',
'fullscreen'
].join('; ')
return (
<iframe
src={src}
title={title}
{...{ width, height }}
frameborder="0"
allow={allowlist}
allowfullscreen>
</iframe>
)
}
export default YoutubeVideo

View file

@ -0,0 +1,73 @@
import { VisibilityContext } from 'react-horizontal-scrolling-menu'
import { useContext } from 'react'
import Icon from '@hackclub/icons'
import { Box, Link } from 'theme-ui'
function Arrow({ direction, disabled, onClick }) {
return (
<Link
onClick={onClick}
sx={{
borderRadius: 100,
boxShadow: 'none',
backgroundColor: 'black',
padding: '8px',
cursor: 'pointer',
placeItems: 'center',
display: 'flex',
mr: 2,
opacity: disabled ? '0.5' : '1',
pointerEvents: disabled ? 'none' : 'auto',
transition: 'opacity 0.3s ease'
}}
>
<Icon
glyph={direction === 'left' ? 'view-back' : 'view-forward'}
size={32}
color="white"
/>
</Link>
)
}
export function LeftArrow() {
const { scrollPrev } =
useContext(VisibilityContext)
const visibility = useContext(VisibilityContext)
const isVisible = visibility.useIsVisible("first", false);
return (
<Arrow direction="left" disabled={isVisible} onClick={() => scrollPrev()} />
)
}
export function RightArrow() {
const { scrollNext } =
useContext(VisibilityContext)
const visibility = useContext(VisibilityContext)
const isVisible = visibility.useIsVisible("last", false);
return (
<Arrow direction="right" disabled={isVisible} onClick={() => scrollNext()} />
)
}
export default function Arrows() {
return (
<Box
sx={{
display: 'flex',
marginBottom: 32,
position: 'relative',
// this is v janky please ignore, thank you.
ml: ['1rem', '1rem', '1rem', 'calc(50vw - 36.5rem)']
}}
>
<div style={{ display: 'flex' }}>
<LeftArrow /> <RightArrow />
</div>
</Box>
)
}

View file

@ -0,0 +1,218 @@
import { Badge, Box, Card, Flex, Grid, Heading, Image, Text } from 'theme-ui'
import Icon from '@hackclub/icons'
import NextLink from 'next/link'
import useSWR from 'swr'
import fetcher from '../../lib/fetcher'
import SlackEvents from './slack-events'
const withCommas = x => x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
export default function Channels() {
const { data: millionCount } = useSWR(
'https://jia.haas.hackclub.com/api/currentNumber',
fetcher,
{ refreshInterval: 10_000 }
)
return (
<Grid
columns={[2, 9, 15]}
gap={3}
sx={{
py: [3, 4],
h3: { my: 0 },
'> div': {
px: [2, 3],
py: 4,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
gridColumn: ['span 1', 'span 3']
},
a: {
position: 'relative',
':hover,:focus': {
svg: {
transform: 'translateX(28px) translateY(-28px)',
opacity: 0
}
}
},
svg: {
position: 'absolute',
top: 2,
right: 2,
fill: 'white',
transition: 'transform 0.25s ease-in-out, opacity 0.25s ease-in-out'
},
h3: {
variant: 'text.headline',
color: 'white',
lineHeight: 'title',
m: 0,
'+ p': {
mt: 2,
color: 'white',
opacity: 0.75,
fontSize: 2,
lineHeight: 'caption'
}
}
}}
>
<Box
as="aside"
sx={{
gridRow: [null, 'span 2'],
gridColumn: ['span 2', 'span 3'],
maxHeight: '100%',
overflow: 'hidden'
}}
>
<Heading
as="h2"
variant="subheadline"
sx={{
mt: 0,
mb: 0,
color: 'red',
textTransform: 'uppercase',
letterSpacing: 'headline'
}}
>
Live from our&nbsp;Slack <br />
</Heading>
<Text
as="p"
variant="caption"
sx={{
fontSize: 1,
fontWeight: 300,
fontStyle: 'italic',
mb: '16px'
}}
>
Waiting for more messages...
</Text>
<SlackEvents />
</Box>
<NextLink href="/ship" passHref>
<Card
as="a"
variant="interactive"
sx={{
gridColumn: ['span 2', 'span 5'],
bg: 'blue',
backgroundImage: t => t.util.gx('cyan', 'blue')
}}
>
<Icon glyph="external" size={24} />
<Heading as="h3" variant="headline">
#ship
</Heading>
<Text as="p">Launch your latest projects & get feedback</Text>
</Card>
</NextLink>
<Card
as="a"
href="https://scrapbook.hackclub.com/"
variant="interactive"
sx={{
gridColumn: ['span 2', 'span 5'],
bg: 'dark',
backgroundImage: t => t.util.gx('yellow', 'orange')
}}
>
<Icon glyph="external" size={24} />
<Heading as="h3" variant="headline">
#scrapbook
</Heading>
<Text as="p">A daily diary of project updates</Text>
</Card>
<Card
bg="red"
sx={{
gridColumn: ['span 2 !important', 'span 2 !important'],
gridRow: ['span 1 !important', 'span 3 !important'],
writingMode: ['lr-tb', 'tb-rl']
}}
>
<Heading as="h3">#counttoamillion</Heading>
<Text as="p" sx={{ display: 'flex', alignItems: 'baseline' }}>
Were at{' '}
<Badge
variant="outline"
as="span"
sx={{ ml: [2, 0], mt: [0, 2], px: [2, 0], py: [0, 2] }}
>
{millionCount ? withCommas(millionCount.number) : '???'}
</Badge>
!
</Text>
</Card>
<Card backgroundColor="green">
<h3 sx={{ color: 'black' }}>#gamedev</h3>
</Card>
<Card
sx={{
backgroundImage:
'url(https://cloud-n6i5i4zb9-hack-club-bot.vercel.app/12020-07-25_fqxym71bmqjr1d35btawn5q6ph1zt0mk.png)',
backgroundColor: '#FEC62E',
backgroundPosition: 'center center',
backgroundRepeat: 'no-repeat',
backgroundSize: '100% auto',
gridColumn: ['span 2', 'span 3 !important', 'span 4 !important'],
h3: { opacity: 0 }
}}
>
<h3>#design</h3>
</Card>
<Card
bg="dark"
sx={{ h3: { color: 'green', textShadow: '0 0 4px currentColor' } }}
>
<h3>#code</h3>
</Card>
<Card
sx={{
bg: 'dark',
backgroundImage:
'url(https://cloud-jnfb0t781-hack-club-bot.vercel.app/02020-07-25_r6thfxwv1u0c71uw0qk94juv6fxxjygf.png)',
backgroundSize: 'cover',
backgroundPosition: 'center',
textShadow: 'text',
gridColumn: ['span 2 !important', 'span 4 !important']
}}
>
<h3>#photography</h3>
</Card>
<Card bg="purple">
<Flex>
<Text as="h3" sx={{ placeSelf: 'center' }}>
#music
</Text>
<Image
src="https://cloud-jd45ga0mv-hack-club-bot.vercel.app/0music.svg"
alt="Music notes"
sx={{ height: '50px', width: '50px', ml: 2 }}
/>
</Flex>
</Card>
<Card bg="orange">
<Flex>
<Text as="h3" sx={{ placeSelf: 'center' }}>
#lounge
</Text>
</Flex>
</Card>
<Card
bg="red"
sx={{
backgroundImage: ({ colors }) =>
`linear-gradient(-184deg, ${colors.red} 0%, ${colors.red} 16.6666%, ${colors.orange} 16.6666%, ${colors.orange} 33.333%, ${colors.yellow} 33.333%, ${colors.yellow} 50%, ${colors.green} 50%, ${colors.green} 66.6666%, ${colors.blue} 66.6666%, ${colors.blue} 83.3333%, ${colors.purple} 83.3333%, ${colors.purple} 100%)`
}}
>
<h3>#lgbtq</h3>
</Card>
</Grid>
)
}

View file

@ -1,4 +1,4 @@
import { Box, Heading, Grid } from 'theme-ui'
import { Box, Grid, Heading } from 'theme-ui'
import SlideUp from '../slide-up'
import JoinForm from './join-form'
import usePrefersMotion from '../../lib/use-prefers-motion'
@ -118,7 +118,7 @@ const Slack = () => {
/>
</Box>
<Cover />
<Content />
<Content nameInputRef />
</Box>
)
} else {

View file

@ -1,14 +1,4 @@
import {
Box,
Card,
Grid,
Input,
Label,
Link,
Select,
Text,
Textarea
} from 'theme-ui'
import { Box, Card, Grid, Input, Label, Link, Select, Text, Textarea } from 'theme-ui'
import { useRouter } from 'next/router'
import useForm from '../../lib/use-form'
import Submit from '../submit'
@ -16,21 +6,21 @@ import { getCookie, hasCookie } from 'cookies-next'
const JoinForm = ({ sx = {} }) => {
const router = useRouter()
const useWaitlist = process.env.NEXT_PUBLIC_OPEN !== 'true'
const { status, formProps, useField } = useForm('/api/join/', null, {
clearOnSubmit: 60000,
method: 'POST',
initData: hasCookie('continent')
? {
continent: getCookie('continent'),
reason: router.query.reason,
event: router.query.event
}
continent: getCookie('continent'),
reason: router.query.reason,
event: router.query.event
}
: { reason: router.query.reason, event: router.query.event }
})
const eventReferrer = useField('event').value
const isAdult = useField('educationLevel').value === 'tertiary'
const useWaitlist = process.env.NEXT_PUBLIC_OPEN !== 'true'
return (
<Card sx={{ maxWidth: 'narrow', mx: 'auto', label: { mb: 3 }, ...sx }}>
@ -58,16 +48,17 @@ const JoinForm = ({ sx = {} }) => {
</Text>
</Box>
)}
<Grid columns={[1, 2]} gap={1} sx={{ columnGap: 2 }}>
<Grid columns={[1, 3]} gap={1} sx={{ columnGap: 2 }}>
<Label>
Full name
<Input
{...useField('name')}
placeholder="Fiona Hackworth"
required
id="joiner_full_name"
/>
</Label>
<Label>
<Label sx={{ width: '100%' }}>
Email address
<Input
{...useField('email')}
@ -76,39 +67,17 @@ const JoinForm = ({ sx = {} }) => {
/>
</Label>
<Label>
Your home continent
Education level
<Select
{...useField('continent')}
{...useField('year')}
required
sx={{ color: useField('continent').value === '' ? 'muted' : '' }}
>
<option value="" selected disabled hidden>
Select a continent...
</option>
<option>Africa</option>
<option>Asia</option>
<option>Europe</option>
<option>North America</option>
<option value="Australia">Oceania / Australia</option>
<option>South America</option>
</Select>
</Label>
<Label>
Current education level
<Select
{...useField('educationLevel')}
required
sx={{
color: useField('educationLevel').value === '' ? 'muted' : ''
}}
>
<option value="" selected disabled hidden>
Select a level...
</option>
<option value="middle">
Middle School (approx. 11 to 14)&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
</option>
<option value="high">High School (approx. 14 to 18)</option>
<option value="middle">Middle School</option>
<option value="high">High School</option>
<option value="tertiary">Tertiary Education (18+)</option>
</Select>
</Label>
@ -121,8 +90,7 @@ const JoinForm = ({ sx = {} }) => {
required
/>
</Label>
{isAdult && (
{/*{isAdult && (
<Text
variant="caption"
color="secondary"
@ -136,44 +104,68 @@ const JoinForm = ({ sx = {} }) => {
a email at{' '}
<Link href="mailto:team@hackclub.com">team@hackclub.com</Link>.
</Text>
)}
{!isAdult && (
<Box>
<Submit
status={status}
mt={'0px!important'}
labels={{
default: useWaitlist ? 'Join Waitlist' : 'Get Invite',
error: 'Something went wrong',
success: useWaitlist
? "We'll be in touch soon!"
: 'Check your email for invite!'
)}*/}
<Box>
<Submit
status={status}
mt={'0px!important'}
labels={{
default: useWaitlist ? 'Join Waitlist' : 'Get Invite',
error: 'Something went wrong',
success: useWaitlist
? "You're on the Waitlist!"
: 'Check your email for invite!'
}}
disabled={status === 'loading' || status === 'success'}
/>
{status === 'success' && !useWaitlist && (
<Text
variant="caption"
color="secondary"
as="div"
sx={{
maxWidth: '600px',
textAlign: 'center',
mt: 3
}}
disabled={status === 'loading' || status === 'success'}
/>
{status === 'success' && (
<Text
variant="caption"
color="secondary"
as="div"
sx={{
maxWidth: '600px',
textAlign: 'center',
mt: 3
}}
>
Search for "Slack" in your mailbox! Not there?{' '}
<Link href="mailto:slack@hackclub.com" sx={{ ml: 1 }}>
Send us an email
</Link>
</Text>
)}
</Box>
)}
>
Search for "Slack" in your mailbox! Not there?{' '}
<Link href="mailto:slack@hackclub.com" sx={{ ml: 1 }}>
Send us an email
</Link>
</Text>
)}
</Box>
</form>
</Card>
)
}
function AdultChecker() {
return (
<Label>
Birthday
<Select
required
onChange={handleYearChange}
sx={{ color: useField('continent').value === '' ? 'muted' : '' }}
>
<option value="" selected disabled hidden>
Year
</option>
<option value="middle" disabled hidden>
Hi, I'm hidden!&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
</option>
{years
.map(year => (
<option key={year} value={year}>
{year}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</option>
))
.reverse()}
</Select>
</Label>
)
}
export default JoinForm

62
components/slack/join.js Normal file
View file

@ -0,0 +1,62 @@
import { Box, Image, Link, Text } from 'theme-ui'
import Icon from '@hackclub/icons'
export default function Join() {
return (
<Box
sx={{
backgroundColor: '#F9FAFC',
mt: '2rem',
borderRadius: 12,
overflowX: 'hidden',
height: ['', '30rem'],
paddingTop: ['2rem', 0],
display: ['grid', 'grid', 'flex']
}}
>
<Box
sx={{
width: ['100%', '100%', '50%'],
paddingX: '32px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
<Box>
<Text
as="h1"
variant="title"
sx={{ mb: 3, fontSize: ['36px', '48px', '56px'] }}
>
Discover the Hack Club Slack
</Text>
<Link
href="#"
sx={{
mb: 3,
cursor: 'pointer',
textDecoration: 'none',
fontSize: '24px',
fontWeight: 500,
placeItems: 'center',
display: 'flex'
}}
>
I&apos;m ready to join <Icon glyph="view-forward" size={24} />
</Link>
</Box>
</Box>
<Image
src="https://cloud-j0p07nviw-hack-club-bot.vercel.app/0image.png"
sx={{
width: ['100%', '100%', '50%'],
height: ['100%', '100%', '30rem'],
objectFit: 'cover',
position: 'relative',
top: 0
}}
/>
</Box>
)
}

View file

@ -0,0 +1,32 @@
import { useCallback, useEffect, useState } from 'react'
const preventDefault = ev => {
if (ev.preventDefault) {
ev.preventDefault()
}
ev.returnValue = false
}
const enableBodyScroll = () => {
document && document.removeEventListener('wheel', preventDefault, false)
}
const disableBodyScroll = () => {
document &&
document.addEventListener('wheel', preventDefault, {
passive: false
})
}
export default function usePreventScroll() {
const [hidden, setHidden] = useState(false)
useEffect(() => {
hidden ? disableBodyScroll() : enableBodyScroll()
return enableBodyScroll
}, [hidden])
const disableScroll = useCallback(() => setHidden(true), [])
const enableScroll = useCallback(() => setHidden(false), [])
return { disableScroll, enableScroll }
}

View file

@ -0,0 +1,67 @@
import { Box, Grid, Image, Text } from 'theme-ui'
export default function Project({ title, description, color, img, itemId }) {
return (
<Grid
sx={{
borderRadius: 12,
gridTemplateColumns: 'auto ',
my: '2rem',
backgroundImage: t =>
`linear-gradient(to bottom, ${color[0]}, ${color[1]})`,
color: 'white',
overflow: 'clip',
width: ['100vw', '40rem', '50rem', '70rem'],
height: ['25rem', '40rem'],
transformOrigin: 'center',
mr: 16,
// this is v janky please ignore, thank you.
ml: ['1rem', '1rem', '1rem', `${itemId === 0 && 'calc(50vw - 36.5rem)'}`]
}}
itemId={itemId}
>
<Box
sx={{
paddingX: '8px',
display: 'flex',
flexDirection: 'column',
placeItems: 'center',
height: ['full', '12.5rem', '20rem'],
placeSelf: 'center',
placeContent: 'end'
}}
>
<Text
as="h1"
variant="title"
sx={{
width: ['full', 'copyUltra'],
textAlign: 'center',
fontSize: ['36px', 6]
}}
>
{title}
</Text>
<Text
as="p"
variant="subtitle"
sx={{
width: ['full', 'copyPlus'],
opacity: '75%',
textAlign: 'center'
}}
>
{description}
</Text>
</Box>
<Image
src={`/slack/${img}.png`}
sx={{
visibility: ['visible'],
height: ['100%'],
objectFit: 'cover'
}}
/>
</Grid>
)
}

View file

@ -0,0 +1,87 @@
const projects = [
{
title: 'Brainwave device for thought-based computer interaction.',
description:
'The team of teens behind BCI is building both the hardware and software for a brainwave reading device to interact with computers using thoughts',
img: 'bci',
color: ['#ec3750', '#F58695'],
itemId: 0
},
{
title: 'A free domain service.',
description:
'The teenage hackers behind Oblong are building a free domain service and non-profit to break down the barriers of entry for building a website.',
img: 'oblong',
color: ['#ff8c37', '#F2A510'],
itemId: 1
},
{
title: 'An open source VPN.',
description:
'Lead by an ex-Apple engineer, the team behind Burrow is building an open source VPN to burrow through school firewalls and keep your data safe.',
img: 'burrow',
color: ['#f1c40f', '#FAE078'],
itemId: 2
},
{
title: 'Free compute infrastructure.',
description:
"The team behind Nest is building a free compute infrastructure for high schoolers to run their code on. It's like AWS, but free and for students.",
img: 'nest',
color: ['#33d6a6', '#51F5C5'],
itemId: 3
},
{
title: 'A chat app and cell phone carrier.',
description:
'The teenage PurpleBubble team are building a private, secure and open source chat app and cell phone carrier',
img: 'purplebubble',
color: ['#5bc0de', '#88e5f8'],
itemId: 4
}
]
export default projects
/*
Here lies the horizontal scroll menu. It's not currently in use, but it's here if anyone every wants it! - Toby
const triggerRef = useRef(null)
gsap.registerPlugin(ScrollTrigger)
useEffect(() => {
const sections = gsap.utils.toArray('.project')
const projects = gsap.to(sections, {
xPercent: -100 * (sections.length - 1),
ease: 'none',
duration: 1,
scrollTrigger: {
trigger: triggerRef.current,
start: 'top top',
end: () => '+=' + document.querySelector('.container').offsetWidth,
scrub: 1.25,
pin: true,
anticipatePin: 1,
invalidateOnRefresh: true,
snap: 0.5 * (1 / (sections.length - 1))
},
onUpdate: function () {
const progress = this.progress()
if (progress < 1 / 6) {
setColors(['red', '#F58695'])
} else if (progress < 2 / 6) {
setColors(['orange', '#F2A510'])
} else if (progress < 3 / 6) {
setColors(['yellow', '#FAE078'])
} else if (progress < 4 / 6) {
setColors(['green', '#51F5C5'])
} else if (progress < 5 / 6) {
setColors(['cyan', '#88e5f8'])
} else {
setColors(['purple', '#d786ff'])
}
}
})
return () => {
projects.kill()
}
}, [])*/

24
components/slack/quote.js Normal file
View file

@ -0,0 +1,24 @@
import { Box, Flex, Image, Text } from 'theme-ui'
export default function Quote({ text, person, age, location, img }) {
return (
<Box
sx={{
p: '32px',
borderRadius: 12,
backgroundColor: '#F9FAFC',
width: 'full'
}}
>
<Text as="h3" variant="title" sx={{ mb: 3, fontSize: ['36px', 4, 5] }}>
"{text}"
</Text>
<Flex sx={{ gap: '8px' }}>
<Image src={img} sx={{ height: 24, width: 24, borderRadius: 100 }} />
<Text as="h3" sx={{ fontWeight: 400 }}>
{person}, {age} from {location}
</Text>
</Flex>
</Box>
)
}

View file

@ -41,7 +41,7 @@ const Submit = ({
}) => (
<Button
as="button"
type="submit"
type={'submit' || props.type}
sx={{
py: 2,
px: 3,

View file

@ -12,7 +12,7 @@
"format": "prettier --write ."
},
"dependencies": {
"@apollo/client": "^3.9.5",
"@apollo/client": "^3.9.9",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.0",
"@github/time-elements": "^4.0.0",
@ -31,6 +31,7 @@
"@tracespace/plotter": "^5.0.0-alpha.0",
"@tracespace/renderer": "^5.0.0-alpha.0",
"@tracespace/xml-id": "^4.2.7",
"@sendgrid/mail": "^8.1.1",
"add": "^2.0.6",
"airtable-plus": "^1.0.4",
"animated-value": "^0.2.4",
@ -60,6 +61,7 @@
"react-before-after-slider-component": "^1.1.8",
"react-datepicker": "^4.24.0",
"react-dom": "^17.0.2",
"react-horizontal-scrolling-menu": "^6.0.2",
"react-konami-code": "^2.3.0",
"react-marquee-slider": "^1.1.5",
"react-masonry-css": "^1.0.16",

12
pages/api/channels/get.js Normal file
View file

@ -0,0 +1,12 @@
export default async function handler(req, res) {
const channelDataReq = await fetch(
`https://slack.com/api/conversations.info?channel=${req.body.id}`,
{
headers: {
Authorization: `Bearer ${process.env.SLACK_BOT_TOKEN}`
}
}
)
console.log(channelDataReq)
return res.status(200).send(channelDataReq)
}

View file

@ -1,4 +1,5 @@
import AirtablePlus from 'airtable-plus'
import { getCode } from 'country-list'
const applicationsTable = new AirtablePlus({
baseID: 'apppALh5FEOKkhjLR',
@ -14,8 +15,8 @@ export default async function handler(req, res) {
body: JSON.stringify({
email: data.userEmail,
name: data.eventName,
transparent: data.transparent
// country: data.eventCountryCode,
country: getCode(data.eventLocation) || '',
transparent: data.transparent,
}),
method: 'POST',
headers: {

View file

@ -19,7 +19,7 @@ const getMessage = (type, payload, repo) => {
const getUrl = (type, payload, repo) => {
switch (type) {
case 'PushEvent':
return payload.commits?.[0].url
return payload.commits?.[0]?.url
? normalizeGitHubCommitUrl(payload.commits[0].url)
: 'https://github.com/hackclub'
case 'PullRequestEvent':

View file

@ -1,5 +1,9 @@
import AirtablePlus from 'airtable-plus'
const sgMail = require('@sendgrid/mail')
sgMail.setApiKey(process.env.SENDGRID_API_KEY)
const joinTable = new AirtablePlus({
apiKey: process.env.AIRTABLE_API_KEY,
baseID: 'appaqcJtn33vb59Au',
@ -36,15 +40,29 @@ export default async function handler(req, res) {
error: '*PUT that request away!* (Method not allowed, use POST)'
})
case 'POST':
console.log('POST request received. WOO!')
break
default:
return res.status(405).json({ error: 'Method not allowed, use POST' })
}
const data = req.body || {}
let data = req.body || {}
const open = process.env.NEXT_PUBLIC_OPEN === 'true'
const waitlist = !open
const isAdult = data.educationLevel === 'tertiary'
const isAdult = data.year === 'tertiary'
if (isAdult) {
const mail = {
to: data.email,
from: 'Hack Club Slack <team@hackclub.com>',
subject: 'Slack Waiting List update',
text: 'Hello world',
html: "Hey! Thanks for your interest in the Hack Club Slack. <br/> Our online community is for minors, and thus only pre-approved adults are permitted.\nTo find out more about what all we do, check out our <a href='https://github.com/hackclub'>Github</a>. If you're a parent or educator & want to talk to a member of our team, send us a email at <a href='mailto:team@hackclub.com'>team@hackclub.com</a>.",
imageUrl: 'https://assets.hackclub.com/icon-rounded.png'
}
sgMail.send(mail)
}
const secrets = (process.env.NAUGHTY || '').split(',')
@ -58,7 +76,7 @@ export default async function handler(req, res) {
const airtablePromise = joinTable.create({
'Full Name': data.name,
'Email Address': data.email,
Student: !isAdult,
Minor: !isAdult,
Reason: data.reason,
Invited: !waitlist,
Club: data.club ? data.club : '',
@ -76,7 +94,7 @@ export default async function handler(req, res) {
const slackPromise = postData(
'https://toriel.hackclub.com/slack-invite',
{
email: data.email,
email: !isAdult ? data.email : null,
ip: req.headers['x-forwarded-for'] || req.socket.remoteAddress,
continent: data.continent,
teen: !isAdult,
@ -93,6 +111,7 @@ export default async function handler(req, res) {
res.json({ status: 'success', message: 'Youve been invited to Slack!' })
)
.catch(error => {
console.error(error)
res.status(500).json({ error })
})
}

View file

@ -0,0 +1,16 @@
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

@ -135,7 +135,7 @@ const Page = () => (
pb: 3
}}
>
Dont run your coding&nbsp;club alone.
Dont run your coding&nbsp;club alone.{' '}
</Text>
Make it a{' '}
<Text
@ -258,11 +258,12 @@ const Page = () => (
showAlt
/>*/}
<iframe
width={660}
height={515}
width="100%"
height="500px"
src="https://www.youtube.com/embed/xXIxwV7bQTw?si=gmhvvHTcUxKTVMjt"
title="YouTube video player"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowFullScreen
style={{ borderRadius: 12, border: 'hidden' }}
/>
<Grid

View file

@ -1,5 +1,5 @@
import { Box, Card, Container, Flex, Link, Text } from 'theme-ui'
import { useEffect, useRef, useState } from 'react'
import { Box, Container, Flex, Link, Text } from 'theme-ui'
import { useEffect, useRef } from 'react'
import { keyframes } from '@emotion/react'
import FlexCol from '../../components/flex-col'
import Meta from '@hackclub/meta'

View file

@ -1,17 +1,18 @@
import { useState, useRef } from 'react'
import { useRouter } from 'next/router'
import { Box, Text, Flex, Heading, Grid, Alert, Button } from 'theme-ui'
import ForceTheme from '../../../components/force-theme'
import { useRef, useState } from 'react'
import { Alert, Box, Button, Flex, Grid, Heading, Text } from 'theme-ui'
import Head from 'next/head'
import Link from 'next/link'
import Icon from '@hackclub/icons'
import Meta from '@hackclub/meta'
import { onSubmit } from '../../../components/fiscal-sponsorship/apply/submit'
import Watermark from '../../../components/fiscal-sponsorship/apply/watermark'
import ForceTheme from '../../../components/force-theme'
import FormContainer from '../../../components/fiscal-sponsorship/apply/form-container'
import HCBInfo from '../../../components/fiscal-sponsorship/apply/hcb-info'
import OrganizationInfoForm from '../../../components/fiscal-sponsorship/apply/org-form'
import PersonalInfoForm from '../../../components/fiscal-sponsorship/apply/personal-form'
import Icon from '@hackclub/icons'
import Link from 'next/link'
import { onSubmit } from '../../../components/fiscal-sponsorship/apply/submit'
import Watermark from '../../../components/fiscal-sponsorship/apply/watermark'
import ContactBanner from '../../../components/fiscal-sponsorship/contact'
export default function Apply() {
const router = useRouter()
@ -47,10 +48,9 @@ export default function Apply() {
<Flex
sx={{
flexDirection: 'column',
justifyContent: 'space-between',
px: [3, 5],
py: 5,
gap: [4, 5],
py: 4,
gap: 4,
height: [null, '100svh'],
position: [null, null, 'sticky'],
top: 0,
@ -58,7 +58,7 @@ export default function Apply() {
}}
>
{/* vertically align h1 to top of form */}
<Box as="header" sx={{ mt: [null, null, -24] }}>
<Box as="header" sx={{ mt: [null, 3], mb: 'auto' }}>
<Link href="/fiscal-sponsorship" passHref legacyBehavior>
<Text
as="a"
@ -101,6 +101,7 @@ export default function Apply() {
</Heading>
</Box>
<HCBInfo />
<ContactBanner sx={{ borderRadius: 'default', bg: 'snow', width: 'fit-content' }} />
</Flex>
<FormContainer
ref={formContainer}

View file

@ -1,7 +1,6 @@
import { useEffect } from 'react'
import { Box, Container, Text, Link, Flex, Image } from 'theme-ui'
import { Container, Text, Link, Image } from 'theme-ui'
import JSConfetti from 'js-confetti'
import Icon from '../../../components/icon'
import { Balancer } from 'react-wrap-balancer'
function fireConfetti() {

View file

@ -5,8 +5,7 @@ import {
Flex,
Grid,
Heading,
Input,
Select
Input
} from 'theme-ui'
import Meta from '@hackclub/meta'
import Head from 'next/head'
@ -16,10 +15,10 @@ import Footer from '../../../components/footer'
import MSparkles from '../../../components/sparkles/money'
import { Text, Button, Card } from 'theme-ui'
import Icon from '@hackclub/icons'
import OrganizationCard, { Badge } from '../../../components/fiscal-sponsorship/directory/card'
import Zoom from 'react-reveal/Zoom'
import OrganizationCard, {
Badge
} from '../../../components/fiscal-sponsorship/directory/card'
import fuzzysort from 'fuzzysort'
import ScrollHint from '../../../components/scroll-hint'
import { useEffect, useState } from 'react'
/** @jsxImportSource theme-ui */
import NextLink from 'next/link'
@ -93,8 +92,7 @@ export const regions = [
icon: 'photo',
image:
'https://cloud-cberabu5z-hack-club-bot.vercel.app/3north_america.png',
ogImage:
'https://cloud-p9tu92fwx-hack-club-bot.vercel.app/3northamerica.png'
ogImage: '/fiscal-sponsorship/climate/NorthAmerica.png'
},
{
label: 'South America',
@ -103,8 +101,7 @@ export const regions = [
icon: 'photo',
image:
'https://cloud-cberabu5z-hack-club-bot.vercel.app/4south_america.png',
ogImage:
'https://cloud-p9tu92fwx-hack-club-bot.vercel.app/4southamerica.png'
ogImage: '/fiscal-sponsorship/climate/SouthAmerica.png'
},
{
label: 'Africa',
@ -112,7 +109,7 @@ export const regions = [
iconColor: 'purple',
icon: 'explore',
image: 'https://cloud-cberabu5z-hack-club-bot.vercel.app/0africa.png',
ogImage: 'https://cloud-p9tu92fwx-hack-club-bot.vercel.app/0africa.png'
ogImage: '/fiscal-sponsorship/climate/Africa.png'
},
{
label: 'Europe',
@ -120,7 +117,7 @@ export const regions = [
iconColor: 'blue',
icon: 'explore',
image: 'https://cloud-oax3m4v0t-hack-club-bot.vercel.app/1europe.png',
ogImage: 'https://cloud-p9tu92fwx-hack-club-bot.vercel.app/2europe.png'
ogImage: '/fiscal-sponsorship/climate/Europe.png'
},
{
label: 'Asia & Oceania',
@ -129,8 +126,7 @@ export const regions = [
icon: 'explore',
image:
'https://cloud-oax3m4v0t-hack-club-bot.vercel.app/0asia___oceania.png',
ogImage:
'https://cloud-p9tu92fwx-hack-club-bot.vercel.app/1asia_oceania.png'
ogImage: '/fiscal-sponsorship/climate/Asia+Oceania.png'
}
]
@ -153,8 +149,8 @@ const FilterPanel = ({ filter, mobile }) => {
cursor: mobile ? 'pointer' : 'default',
':hover': mobile
? {
color: 'blue'
}
color: 'blue'
}
: {}
}}
onClick={() => setHiddenOnMobile(!hiddenOnMobile)}
@ -245,7 +241,7 @@ const FilterPanel = ({ filter, mobile }) => {
textDecoration: 'none',
color:
currentSelections.length === baseData.length ||
!currentSelections.includes(item.id)
!currentSelections.includes(item.id)
? 'black'
: 'primary',
transition: 'color 0.2s',
@ -325,8 +321,8 @@ const RegionPanel = ({ currentRegion, mobile }) => {
cursor: mobile ? 'pointer' : 'default',
':hover': mobile
? {
color: 'blue'
}
color: 'blue'
}
: {}
}}
onClick={() => setHiddenOnMobile(!hiddenOnMobile)}
@ -403,7 +399,9 @@ const RegionPanel = ({ currentRegion, mobile }) => {
<NextLink
key={idx}
scroll={false}
href={`/fiscal-sponsorship/climate/organizations-in-${kebabCase(item.label)}`}
href={`/fiscal-sponsorship/climate/organizations-in-${kebabCase(
item.label
)}`}
>
<Flex
sx={{
@ -535,8 +533,7 @@ export default function ClimatePage({ rawOrganizations, pageRegion }) {
" with HCB's fiscal sponsorship and financial tools. Explore the climate efforts running on HCB."
}
image={
region?.ogImage ??
'https://cloud-gv8bzwz6z-hack-club-bot.vercel.app/0frame_14__1_.png'
region?.ogImage ?? '/fiscal-sponsorship/climate/social-preview.png'
}
/>
<style>{styles}</style>
@ -965,7 +962,7 @@ export default function ClimatePage({ rawOrganizations, pageRegion }) {
viewBox="0 0 512 512"
>
<img
src="/fiscal-sponsorship/climate/earth-on-hcb.svg"
src="/fiscal-sponsorship/climate/earth-on-hcb.png"
alt=""
height="82px"
/>
@ -1135,7 +1132,7 @@ export default function ClimatePage({ rawOrganizations, pageRegion }) {
return (
currentBadges.length === badges.length ||
intersection(organizationBadgeIds, currentBadges).length ===
currentBadges.length
currentBadges.length
)
})
.map(organization => (
@ -1214,7 +1211,7 @@ export default function ClimatePage({ rawOrganizations, pageRegion }) {
</Box>
</Box>
</Box>
<Footer light key="footer" />
<Footer />
</div>
)
}
@ -1401,7 +1398,7 @@ export async function fetchRawClimateOrganizations() {
while (lastLength >= 100) {
const json = await fetch(
'https://hcb.hackclub.com/api/v3/directory/organizations?per_page=100&page=' +
page
page
).then(res => res.json())
lastLength = json.length
page++

View file

@ -1,13 +1,4 @@
import {
Box,
Heading,
Container,
Card,
Text,
Flex,
Button,
Badge
} from 'theme-ui'
import { Box, Heading, Container, Text, Button, Badge } from 'theme-ui'
import Meta from '@hackclub/meta'
import Head from 'next/head'
@ -186,7 +177,7 @@ export default function First({ stats }) {
<Start stats={stats} />
</Box>
</Box>
<Footer dark key="footer" />
<Footer dark />
</>
)
}

View file

@ -1,28 +1,29 @@
import Meta from '@hackclub/meta'
import Head from 'next/head'
import Image from 'next/image'
import Link from 'next/link'
import { Balancer } from 'react-wrap-balancer'
import {
Box,
Button,
Card,
Container,
Flex,
Link as UILink,
Heading,
Text,
Grid,
Button
Heading,
Link as UILink,
Text
} from 'theme-ui'
import { Balancer } from 'react-wrap-balancer'
import Meta from '@hackclub/meta'
import Head from 'next/head'
import ForceTheme from '../../components/force-theme'
import Nav from '../../components/nav'
import Footer from '../../components/footer'
import Photo from '../../components/photo'
import Stat from '../../components/stat'
import Tilt from '../../components/tilt'
import Photo from '../../components/photo'
import Image from 'next/image'
import Link from 'next/link'
import OuternetImgFile from '../../public/home/outernet-110.jpg'
import ContactBanner from '../../components/fiscal-sponsorship/contact'
import Features from '../../components/fiscal-sponsorship/features'
import OuternetImgFile from '../../public/home/outernet-110.jpg'
const organizations = [
{
@ -375,8 +376,11 @@ export default function Page() {
color="slate"
sx={{ maxWidth: '52ch' }}
>
This fee goes directly to Hack Club's operations staff, including teen interns working under mentors. This allows us to deliver
best-in-class software and support, grow sustainably, while also providing paid career training for young people from diverse backgrounds.
This fee goes directly to Hack Club's operations staff,
including teen interns working under mentors. This allows us to
deliver best-in-class software and support, grow sustainably,
while also providing paid career training for young people from
diverse backgrounds.
</Text>
</div>
<Text
@ -393,10 +397,10 @@ export default function Page() {
'linear-gradient(to right, #f06844 0%, #ee4c54 25%, #d45e95 50%, #9c6ca6 75%, #6583c1 100%) !important'
},
'@supports (-webkit-background-clip: text) and (background: linear-gradient(to right in oklch, white, black)':
{
backgroundImage:
'linear-gradient(to right in oklch, #f06844 0%, #ee4c54 25%, #d45e95 50%, #9c6ca6 75%, #6583c1 100%) !important'
}
{
backgroundImage:
'linear-gradient(to right in oklch, #f06844 0%, #ee4c54 25%, #d45e95 50%, #9c6ca6 75%, #6583c1 100%) !important'
}
}}
style={{ margin: 0 }}
>
@ -498,10 +502,11 @@ export default function Page() {
src={OuternetImgFile}
alt="Each year, 1000s of teenagers attend Hack Club events like this"
showAlt
sx={{ height: '100%' }}
/>
</Link>
<div>
<Heading as="h2" variant="headline">
<Heading as="h2" variant="headline" sx={{ mt: [0, 0] }}>
Built by Hack Club
</Heading>
<p>
@ -514,11 +519,44 @@ export default function Page() {
clubs around the world.
</p>
<p>
We started HCB in 2018 to support teen-led clubs and hackathons. After
showing it to our educational partners, we knew we had tapped into
something much larger. Today, HCB removes financial and
legal barriers for thousands doing good in their community.
We started HCB in 2018 to support teen-led clubs and hackathons.
After showing it to our educational partners, we knew we had
tapped into something much larger. Today, HCB removes financial
and legal barriers for thousands doing good in their community.
</p>
<Flex
as="footer"
sx={{
alignItems: 'center',
gap: 3,
color: 'slate',
borderRadius: 'default',
lineHeight: 'caption',
textWrap: 'balance',
svg: { flexShrink: 0, fill: 'blue' }
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width={32}
height={32}
viewBox="0 0 16 16"
aria-hidden
>
<path d="M8 0a8 8 0 1 0 0 16A8 8 0 0 0 8 0M2.04 4.326c.325 1.329 2.532 2.54 3.717 3.19.48.263.793.434.743.484q-.121.12-.242.234c-.416.396-.787.749-.758 1.266.035.634.618.824 1.214 1.017.577.188 1.168.38 1.286.983.082.417-.075.988-.22 1.52-.215.782-.406 1.48.22 1.48 1.5-.5 3.798-3.186 4-5 .138-1.243-2-2-3.5-2.5-.478-.16-.755.081-.99.284-.172.15-.322.279-.51.216-.445-.148-2.5-2-1.5-2.5.78-.39.952-.171 1.227.182.078.099.163.208.273.318.609.304.662-.132.723-.633.039-.322.081-.671.277-.867.434-.434 1.265-.791 2.028-1.12.712-.306 1.365-.587 1.579-.88A7 7 0 1 1 2.04 4.327Z" />
</svg>
<span>
As part of our commitment to climate justice, funding for HCBs
operations&nbsp;and staff will never come from the{' '}
<UILink
href="https://www.ffisolutions.com/the-carbon-underground-200-500/"
color="blue"
>
fossil fuel industry
</UILink>
.
</span>
</Flex>
</div>
</Grid>
</Container>
@ -576,11 +614,12 @@ export default function Page() {
Apply now
</Button>
</Link>
<Text as="p" variant="lead" sx={{ color: 'white' }}>
<Text as="p" variant="lead" sx={{ color: 'white', mb: [0, 0] }}>
<Balancer>No startup fees, no&nbsp;minimum balance.</Balancer>
</Text>
</Flex>
</Box>
<ContactBanner sx={{ justifyContent: 'center' }} />
<Footer />
</>
)

View file

@ -203,12 +203,11 @@ function Page({
priority
gradient="linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.45))"
/>
<Announcement
<Announcement
copy="Hop OnBoard and create your first PCB"
caption="Join 1,000 others to create your first circuit board."
href="https://hackclub.com/onboard/"
iconLeft="idea"
color="primary"
/>
<Box
sx={{

View file

@ -12,6 +12,8 @@ import usePrefersReducedMotion from '../../lib/use-prefers-reduced-motion'
import { useEffect, useRef, useState } from 'react'
import sleep from '../../lib/sleep'
import Announcement from '../../components/announcement'
import YoutubeVideo from '../../components/onboard/youtube-video'
import Icon from '@hackclub/icons'
/**
* @type {import('theme-ui').ThemeUIStyleObject}
@ -202,7 +204,7 @@ const ShipPage = () => {
<Box sx={{ pt: [3, 6]}}>
<Announcement
copy="Steve Wozniak, Apple co-founder, about OnBoard"
caption="Im so glad young people can create PCBs online."
caption="Im so glad young people can create PCBs online. May your creativity change the world! Mine did."
imgSrc="https://cloud-iddh16j0r-hack-club-bot.vercel.app/0stevew.png"
imgAlt="A picture of Steve Wozniak who is a co-founder of Apple."
color="primary"
@ -324,48 +326,6 @@ const ShipPage = () => {
</Flex>
</Grid>
<Flex
as="div"
sx={{
flexDirection: 'row',
gap: 3,
alignItems: 'end',
justifyContent: 'center',
margin: '0 auto',
padding: '0.8rem 1rem',
borderRadius: 'default',
border: '1px dashed white',
background: '#000000',
}}
>
<Image
src="https://cloud-iddh16j0r-hack-club-bot.vercel.app/0stevew.png"
alt="A picture of Steve Wozniak who is a co-founder of Apple."
sx={{
width: 50,
height: 50
}}
/>
<Flex
as="div"
sx={{ flexDirection: 'column', gap: 1, width: '90%' }}
>
<Text as="p" sx={{ fontSize: 20 }}>
<Balancer>
"Im so glad young people can create PCBs online. May your
creativity change the world! Mine did.
</Balancer>
</Text>
<Text
as="p"
sx={{ fontSize: 20, fontStyle: 'italic' }}
>
<Balancer>
-<span style={{ textDecoration: 'underline' }}>Steve Wozniak "Woz"</span>, Apple co-founder, on Hack Club OnBoard
</Balancer>
</Text>
</Flex>
</Flex>
</Flex>
</Box>
@ -402,6 +362,16 @@ const ShipPage = () => {
Never made a circuit board before? No problem.
</Balancer>
</Heading>
<Flex sx={{flexDirection:"column"}}>
<YoutubeVideo youtube-id="LrSKs35nR8k" list="PLbNbddgD-XxECO7C2z-FAlSoJ57VqcJA3" height="300px" />
<Text sx={{ fontSize: 2, color: 'muted' }}>
See the{' '}
<Link href="https://www.youtube.com/watch?v=LrSKs35nR8k&list=PLbNbddgD-XxECO7C2z-FAlSoJ57VqcJA3" target="_blank">
full playlist
<Icon glyph="external" size={18} />
</Link>
</Text>
</Flex>
<Text sx={{ fontSize: 3 }}>
Learn how to design your own circuit boards from scratch with our{' '}
<strong>official tutorials</strong> and jams, like Maggies{' '}

View file

@ -769,29 +769,23 @@ const PizzaPage = () => {
}}
>
p.s. if you already lead a club, you can still get pizza! draw a
pizza in
<Link
style={{ marginLeft: '8px' }}
href="https://hackclub.slack.com/archives/C05RZ6K7RS5"
>
pizza in{' '}
<Link href="https://hackclub.slack.com/archives/C05RZ6K7RS5">
#pizza-party
</Link>
</Text>
</Box>
<Text
as="p"
style={{
textAlign: 'center',
width: '100%',
fontSize: 18,
display: 'flex',
justifyContent: 'center',
marginBottom: '32px'
}}
>
Need help getting your Pizza Grant? Email{' '}
<Link href="mailto:thomas@hackclub.com" style={{ marginLeft: 6 }}>
thomas@hackclub.com
</Link>
<Link href="mailto:thomas@hackclub.com">thomas@hackclub.com</Link>
</Text>
</Container>
<Footer

View file

@ -1,35 +1,42 @@
import { keyframes } from '@emotion/react'
import Meta from '@hackclub/meta'
import Head from 'next/head'
import NextLink from 'next/link'
import useSWR from 'swr'
import { Badge, Box, Card, Container, Grid, Heading, Text } from 'theme-ui'
import { Box, Container, Heading, Text } from 'theme-ui'
import { useRef } from 'react'
import { ScrollMenu } from 'react-horizontal-scrolling-menu'
import 'react-horizontal-scrolling-menu/dist/styles.css'
import { thousands } from '../lib/members'
import projects from '../components/slack/projects'
import Channels from '../components/slack/channels'
import Join from '../components/slack/join'
import Footer from '../components/footer'
import ForceTheme from '../components/force-theme'
import Icon from '../components/icon'
import Nav from '../components/nav'
import Header from '../components/slack/header'
import SlackEvents from '../components/slack/slack-events'
import Stat from '../components/stat'
import fetcher from '../lib/fetcher'
import { formatted, thousands } from '../lib/members'
const zoomSlide = keyframes({
from: { backgroundPosition: '-32px bottom' },
to: { backgroundPosition: '32px bottom' }
})
const withCommas = x => x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
import Project from '../components/slack/project'
import Quote from '../components/slack/quote'
import Arrows from '../components/slack/arrows'
const SlackPage = () => {
const { data: millionCount } = useSWR(
'https://jia.haas.hackclub.com/api/currentNumber',
fetcher,
{ refreshInterval: 10_000 }
)
const nameInputRef = useRef(null)
return (
<>
<style css>
{/*this hides the horizontal scrollbar in the projects gallery*/}
{`
::-webkit-scrollbar {
width:0px;
}
::-webkit-scrollbar-track {
background:transparent;
}
::-webkit-scrollbar-thumb {
background:transparent;
}`}
</style>
<Meta
as={Head}
name="Join our Slack"
@ -37,373 +44,126 @@ const SlackPage = () => {
image="https://cloud-n6i5i4zb9-hack-club-bot.vercel.app/02020-07-25_d2dd4egb1th5k71w4uj0abbfkvvtnc01.jpeg"
/>
<ForceTheme theme="light" />
<Nav />
<Header />
<Container sx={{ py: [4, 5] }}>
<Grid
columns={[2, 5]}
gap={2}
sx={{ maxWidth: 'copyPlus', alignItems: 'end' }}
>
<Stat
value={`${thousands}k+`}
label="total members"
color="red"
lg
sx={{ gridColumn: 'span 2' }}
/>
<Stat value={6} label="continents" />
<Stat value="1M+" label="messages/yr" />
</Grid>
<Text
variant="subtitle"
as="p"
sx={{ maxWidth: 'copy', fontSize: [2, 3], mt: 3, mb: [3, 4] }}
>
Have a coding question? Looking for project feedback? Youll find some
fabulous people to talk to in our global Slack (Discord-style online
groupchat) with {formatted}+ members, active at all hours.
</Text>
<Nav slack={true} />
{/* <Box sx={{ position: 'fixed', mt: 5, maxWidth: '1024px', backgroundColor: 'red', zIndex: 100 }}>
<Text>Hack Club Slack</Text>
</Box>*/}
<Header nameInputRef={nameInputRef} />
<Container sx={{ pt: [4, 5], pb: 4 }}>
<Heading
as="h2"
variant="title"
sx={{ mt: [4, 5], color: 'black', maxWidth: 'copyUltra' }}
>
Channels for every interest.
No commitments, just exploration...
</Heading>
<Text
as="p"
variant="subtitle"
sx={{ maxWidth: 'copy', fontSize: [2, 3], mt: 3 }}
>
<Text as="p" variant="subtitle" sx={{ fontSize: [2, 3], mt: 3 }}>
Across 2,000 public channels, find the community for your favorite
programming language, ask for advice, or just hang out.
programming language, ask for advice, or just hang out. Find the
worlds that suit you.
</Text>
<Grid
columns={[2, 9, 15]}
gap={3}
<Channels />
{/*<Flex
sx={{
py: [3, 4],
h3: { my: 0 },
'> div': {
px: [2, 3],
py: 4,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
gridColumn: ['span 1', 'span 3']
},
a: {
position: 'relative',
':hover,:focus': {
svg: {
transform: 'translateX(28px) translateY(-28px)',
opacity: 0
}
}
},
svg: {
position: 'absolute',
top: 2,
right: 2,
fill: 'white',
transition:
'transform 0.25s ease-in-out, opacity 0.25s ease-in-out'
},
h3: {
variant: 'text.headline',
color: 'white',
lineHeight: 'title',
m: 0,
'+ p': {
mt: 2,
color: 'white',
opacity: 0.75,
fontSize: 2,
lineHeight: 'caption'
}
}
gridRow: [null, 'span 2'],
gridColumn: ['span 2', 'span 3'],
maxHeight: '100%',
overflow: 'hidden'
}}
>
<Box
as="aside"
<Heading
as="h2"
variant="subheadline"
sx={{
gridRow: [null, 'span 2'],
gridColumn: ['span 2', 'span 3'],
maxHeight: '100%',
overflow: 'hidden'
textTransform: 'uppercase',
letterSpacing: 'headline',
width: '400px'
}}
>
<Heading
as="h2"
variant="subheadline"
sx={{
mt: 0,
mb: 0,
color: 'red',
textTransform: 'uppercase',
letterSpacing: 'headline'
}}
>
Live from our&nbsp;Slack <br />
</Heading>
<Text
as="p"
variant="caption"
sx={{
fontSize: 1,
fontWeight: 300,
fontStyle: 'italic',
mb: '16px'
}}
>
Waiting for more messages...
</Text>
<SlackEvents />
</Box>
<NextLink href="/ship" passHref>
<Card
as="a"
variant="interactive"
sx={{
gridColumn: ['span 2', 'span 5'],
bg: 'blue',
backgroundImage: t => t.util.gx('cyan', 'blue')
}}
>
<Icon glyph="external" size={24} />
<Heading as="h3" variant="headline">
#ship
</Heading>
<Text as="p">Launch your latest projects & get feedback</Text>
</Card>
</NextLink>
<Card
as="a"
href="https://scrapbook.hackclub.com/"
variant="interactive"
sx={{
gridColumn: ['span 2', 'span 5'],
bg: 'dark',
backgroundImage: t => t.util.gx('yellow', 'orange')
}}
>
<Icon glyph="external" size={24} />
<Heading as="h3" variant="headline">
#scrapbook
</Heading>
<Text as="p">A daily diary of project updates</Text>
</Card>
<Card
bg="red"
sx={{
gridColumn: ['span 2 !important', 'span 2 !important'],
gridRow: ['span 1 !important', 'span 3 !important'],
writingMode: ['lr-tb', 'tb-rl']
}}
>
<Heading as="h3">#counttoamillion</Heading>
<Text as="p" sx={{ display: 'flex', alignItems: 'baseline' }}>
Were at{' '}
<Badge
variant="outline"
as="span"
sx={{ ml: [2, 0], mt: [0, 2], px: [2, 0], py: [0, 2] }}
>
{millionCount ? withCommas(millionCount.number) : '???'}
</Badge>
!
</Text>
</Card>
<Card bg="cyan">
<h3>#lounge</h3>
</Card>
<Card
sx={{
backgroundImage:
'url(https://cloud-n6i5i4zb9-hack-club-bot.vercel.app/12020-07-25_fqxym71bmqjr1d35btawn5q6ph1zt0mk.png)',
backgroundColor: '#FEC62E',
backgroundPosition: 'center center',
backgroundRepeat: 'no-repeat',
backgroundSize: '100% auto',
gridColumn: ['span 2', 'span 3 !important', 'span 4 !important'],
h3: { opacity: 0 }
}}
>
<h3>#design</h3>
</Card>
<Card
bg="dark"
sx={{ h3: { color: 'green', textShadow: '0 0 4px currentColor' } }}
>
<h3>#code</h3>
</Card>
<Card
bg="yellow"
sx={{
backgroundImage:
'url(https://assets.hackclub.com/log/2020-06-29_dog.jpg)',
backgroundSize: '100%',
backgroundPosition: 'center',
textShadow: 'text',
gridColumn: ['span 2', 'span 3 !important']
}}
>
<h3>#dogs</h3>
</Card>
<Card bg="purple">
<h3>#music</h3>
</Card>
<Card
bg="red"
sx={{
backgroundImage: ({ colors }) =>
`linear-gradient(-184deg, ${colors.red} 0%, ${colors.red} 16.6666%, ${colors.orange} 16.6666%, ${colors.orange} 33.333%, ${colors.yellow} 33.333%, ${colors.yellow} 50%, ${colors.green} 50%, ${colors.green} 66.6666%, ${colors.blue} 66.6666%, ${colors.blue} 83.3333%, ${colors.purple} 83.3333%, ${colors.purple} 100%)`
}}
>
<h3>#lgbtq</h3>
</Card>
<Card
sx={{
bg: 'dark',
backgroundImage:
'url(https://cloud-jnfb0t781-hack-club-bot.vercel.app/02020-07-25_r6thfxwv1u0c71uw0qk94juv6fxxjygf.png)',
backgroundSize: 'cover',
backgroundPosition: 'center',
textShadow: 'text',
gridColumn: ['span 2 !important', 'span 4 !important']
}}
>
<h3>#photography</h3>
</Card>
</Grid>
<Heading
as="h2"
variant="title"
sx={{ mt: [4, 5], color: 'black', maxWidth: 'copyUltra' }}
>
Events on Zoom that dont suck.
</Heading>
<Grid
columns={[null, 2]}
gap={[3, 4]}
Live from our&nbsp;Slack...
</Heading>
<SlackEvents />
</Flex>*/}
<Text as="h1" variant="title" sx={{ mt: [4, 5], mb: 3 }}>
Where the makers hang out...
</Text>
<Text as="p" variant="subtitle" sx={{ fontSize: [2, 3], mt: 3 }}>
These projects were built by Hack Clubbers all around the world on the
Hack Club Slack.
</Text>
</Container>
<Box
sx={{
backgroundColor: '#F9FAFC',
paddingT: '1rem',
overflow: 'hidden'
}}
>
<Box
onMouseEnter={disableScroll}
onMouseLeave={enableScroll}
sx={{
py: [3, 4],
mx: [null, null, null, -4],
h3: {
variant: 'text.title',
color: 'white',
my: 0
},
p: {
color: 'white',
opacity: 0.875,
fontSize: [2, 3],
lineHeight: 'caption',
mt: 2
},
a: {
position: 'relative',
pb: [4, 5],
':hover,:focus': {
svg: {
transform: 'translateX(28px) translateY(-28px)',
opacity: 0
}
}
},
svg: {
position: 'absolute',
top: 2,
right: 2,
fill: 'white',
transition:
'transform 0.25s ease-in-out, opacity 0.25s ease-in-out'
}
msScrollbarTrackColor: 'transparent',
'::-webkit-scrollbar-track': 'background: transparent',
'::-webkit-scrollbar-thumb': 'background: transparent'
}}
>
<NextLink href="/amas" passHref>
<Card
as="a"
variant="interactive"
sx={{
bg: '#000',
backgroundImage:
'linear-gradient(rgba(0,0,0,0.25),rgba(0,0,0,0.375)), url(https://cloud-n6i5i4zb9-hack-club-bot.vercel.app/22020-07-25_hz5hy2bw5x70ped8akzwtrj4hzuex3vw.jpeg)',
backgroundSize: '100% auto',
textShadow: 'text'
}}
>
<Icon glyph="external" size={24} />
<h3>AMAs</h3>
<p>Zoom with someone remarkable</p>
</Card>
</NextLink>
<NextLink href="/night" passHref>
<Card
as="a"
variant="interactive"
sx={{
bg: 'dark',
backgroundImage:
'url(https://cloud-n6i5i4zb9-hack-club-bot.vercel.app/32020-07-25_pp7t4h8738hdm46r2xxrd8tz3kjc5x0t.png)',
backgroundPosition: 'bottom center',
backgroundSize: 'cover',
h3: {
textTransform: 'uppercase',
WebkitTextStroke: 'white',
WebkitTextStrokeWidth: '2px',
WebkitTextFillColor: 'transparent',
filter: `drop-shadow(0 0 1px #50E3C2) drop-shadow(0 0 4px #50E3C2)`
}
}}
>
<Icon glyph="external" size={24} />
<h3>Hack Night</h3>
<p>Weekly live coding & hangout on Zoom</p>
</Card>
</NextLink>
<NextLink href="/minecraft" passHref>
<Card
as="a"
variant="interactive"
sx={{
bg: '#759B40',
backgroundImage:
'url(https://cloud-n6i5i4zb9-hack-club-bot.vercel.app/42020-07-25_56ygmzej7r9kjrrudmnb0t0cmg0m3gtg.jpeg)',
backgroundSize: 'cover',
textShadow: 'text'
}}
>
<Icon glyph="external" size={24} />
<h3>Minecraft</h3>
<p>Play on our server, build OSS plugins, compete</p>
</Card>
</NextLink>
<Card
as="a"
href="https://events.hackclub.com/"
variant="interactive"
sx={{
bg: '#3b6fce',
backgroundImage:
'url(https://cloud-n6i5i4zb9-hack-club-bot.vercel.app/52020-07-25_zoomus-icon.svg)',
backgroundRepeat: 'repeat-x',
backgroundPosition: '0 bottom',
'@media (prefers-reduced-motion: no-preference)': {
animation: `${zoomSlide} 2s linear infinite`
}
}}
<ScrollMenu
Footer={Arrows}
transitionDuration={900}
style={{ scrollbar: 'hidden' }}
>
<Icon glyph="external" size={24} />
<h3>Community fun</h3>
<p>Members run their own eventsall with Zoom Pro</p>
</Card>
</Grid>
{projects.map((project, i) => (
<Project
title={project.title}
description={project.description}
img={project.img}
color={project.color}
itemId={project.itemId}
key={project.itemId}
/>
))}
</ScrollMenu>
</Box>
</Box>
<Container sx={{ py: [4, 5] }}>
<Box sx={{ gap: '2rem', display: ['grid', 'grid', 'flex'] }}>
<Quote
text="I knew it's where I wanted to be"
person="Shawn"
img="https://cloud-8u876lgxi-hack-club-bot.vercel.app/0shawn.png"
age={18}
location="MD"
/>
<Quote
text="I felt so free- there were no expectations"
person="JC"
img="https://ca.slack-edge.com/T0266FRGM-U03MNFDRSGJ-e6fb939acfd8-512"
age={17}
location="CT"
/>
<Quote
text="Finally, I found my people!"
person="Cheru"
img="https://ca.slack-edge.com/T0266FRGM-U02UYFZQ0G0-eb4e3c7fb0cf-512"
age={16}
location="VT"
/>
</Box>
<Join />
</Container>
<Footer />
</>
)
}
function disableScroll() {
document.body.style.overflowAnchor = 'hidden'
}
function enableScroll() {
document.body.style.overflowAnchor = 'scroll'
}
export default SlackPage

View file

@ -87,6 +87,7 @@ export default function Team({ team }) {
teamRole="Founder"
text="Zach dropped out of high school after his freshman year to work in the technology industry and had over 5 million people using his software by the time he turned 17. He founded Hack Club to build the program he wish he had in high school and has been awarded the Thiel Fellowship and Forbes 30 Under 30 for his work."
pronouns="he/him"
email="zach"
/>
<Bio
img="/team/christina.jpg"
@ -94,6 +95,7 @@ export default function Team({ team }) {
teamRole="Co-founder and COO"
text="With more than a decade of experience in starting and leading organizations, Christina has built global teams and raised millions of dollars. She has 20 years experience as a journalist, including reporting for The New York Times from Iraq. She has an MA in education, and taught as a public school teacher in 2000, which inspired her book “The Emergency Teacher.”"
pronouns="she/her"
email="christina"
/>
</Grid>
<Grid columns={[1, null, 3]} gap={2}>
@ -142,18 +144,21 @@ export default function Team({ team }) {
>
Hacker Resources Team
</Text>
<Grid columns={[1, null, 2]} gap={2}>
{ team.current?.filter(member => member.department === "HQ").map(member => (
<Bio
img={member.avatar}
name={member.name}
teamRole={member.role}
text={member.bio}
pronouns={member.pronouns}
key={member.name}
/>
))}
</Grid>
<Grid columns={[1, null, 2]} gap={2}>
{team.current
?.filter(member => member.department === 'HQ')
.map(member => (
<Bio
img={member.avatar}
name={member.name}
teamRole={member.role}
text={member.bio}
pronouns={member.pronouns}
email={member.email}
key={member.name}
/>
))}
</Grid>
</Box>
</Box>
<Box>
@ -174,17 +179,20 @@ export default function Team({ team }) {
HCB Team
</Text>
<Grid columns={[1, null, 2]} gap={2}>
{ team.current?.filter(member => member.department === "HCB").map(member => (
<Bio
img={member.avatar}
name={member.name}
teamRole={member.role}
text={member.bio}
pronouns={member.pronouns}
key={member.name}
/>
))}
</Grid>
{team.current
?.filter(member => member.department === 'HCB')
.map(member => (
<Bio
img={member.avatar}
name={member.name}
teamRole={member.role}
text={member.bio}
pronouns={member.pronouns}
email={member.email}
key={member.name}
/>
))}
</Grid>
</Box>
</Box>
</Grid>
@ -205,18 +213,21 @@ export default function Team({ team }) {
>
Community Team
</Text>
<Grid columns={[1, 2, null, 4]} gap={2}>
{ team.current?.filter(member => member.department === "Community").map(member => (
<Bio
<Grid columns={[1, 2, null, 4]} gap={2}>
{team.current
?.filter(member => member.department === 'Community')
.map(member => (
<Bio
img={member.avatar}
name={member.name}
teamRole={member.role}
text={member.bio}
pronouns={member.pronouns}
key={member.name}
email={member.email}
key={member.name}
/>
))}
</Grid>
))}
</Grid>
</Box>
<br />
<Box sx={{ textAlign: 'center', mt: 2, mb: [3, 4] }}>
@ -247,6 +258,13 @@ export default function Team({ team }) {
</Text>
</Box>
<Grid columns={[1, null, 2, 4]} gap={2}>
<Bio
name="Lexi Mattick"
teamRole="Clubs Engineering"
text="Always driven by curiosity for how things work, Lexi fell in love with Hack Club in 2019 after joining a Hack Night call and discovering like-minded individuals. She spends her time programming, making music, and studying for her private pilot license; at Hack Club, she spends her time working on whatever fantastic project is happening in the present moment."
img="/team/bean-man.jpg"
pronouns="she/her"
/>
<Bio
name="Holly Delisle"
teamRole="Clubs Operations Lead"
@ -460,10 +478,12 @@ When not busy juggling different tasks he takes up, he enjoys tinkering & buildi
}
export const getServerSideProps = async () => {
try {
const team = await fetch("https://internal.hackclub.com/team").then((res) => res.json())
return { props: { team } }
} catch (e) {
return { props: { team: [] }}
}
try {
const team = await fetch('https://internal.hackclub.com/team').then(res =>
res.json()
)
return { props: { team } }
} catch (e) {
return { props: { team: [] } }
}
}

View file

@ -1,7 +0,0 @@
module.exports = {
singleQuote: true,
trailingComma: 'none',
arrowParens: 'avoid',
printWidth: 80,
semi: false
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 997 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
public/slack/bci.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
public/slack/burrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
public/slack/nest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 KiB

BIN
public/slack/oblong.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 654 KiB

BIN
public/team/bean-man.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 KiB

View file

@ -15,10 +15,10 @@
"@jridgewell/gen-mapping" "^0.3.0"
"@jridgewell/trace-mapping" "^0.3.9"
"@apollo/client@^3.9.5":
version "3.9.5"
resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.9.5.tgz#502ec191756a7f44788b5f08cbe7b8de594a7656"
integrity sha512-7y+c8MTPU+hhTwvcGVtMMGIgWduzrvG1mz5yJMRyqYbheBkkky3Lki6ADWVSBXG1lZoOtPYvB2zDgVfKb2HSsw==
"@apollo/client@^3.9.9":
version "3.9.9"
resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.9.9.tgz#38f983a1ad24e2687abfced0a9c1c3bef8d32616"
integrity sha512-/sMecU/M0WK9knrguts1lSLV8xFKzIgOMVb4mi6MOxgJXjliDB8PvOtmXhTqh2cVMMR4TzXgOnb+af/690zlQw==
dependencies:
"@graphql-typed-document-node/core" "^3.1.1"
"@wry/caches" "^1.0.0"
@ -28,7 +28,7 @@
hoist-non-react-statics "^3.3.2"
optimism "^0.18.0"
prop-types "^15.7.2"
rehackt "0.0.5"
rehackt "0.0.6"
response-iterator "^0.2.6"
symbol-observable "^4.0.0"
ts-invariant "^0.10.3"
@ -2065,6 +2065,29 @@
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.5.1.tgz#5f1b518ec5fa54437c0b7c4a821546c64fed6922"
integrity sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==
"@sendgrid/client@^8.1.1":
version "8.1.1"
resolved "https://registry.yarnpkg.com/@sendgrid/client/-/client-8.1.1.tgz#5c15b59973da3e108257883e408c4afd74844248"
integrity sha512-pg0gYhAdyQil3Aga7/xHVcZFpvDAjAQMNBgMy5njTSkjACoWHmpSi1nWBZM7nIH/ptcRNMpnBbm9B5EvQ8fX2w==
dependencies:
"@sendgrid/helpers" "^8.0.0"
axios "^1.6.4"
"@sendgrid/helpers@^8.0.0":
version "8.0.0"
resolved "https://registry.yarnpkg.com/@sendgrid/helpers/-/helpers-8.0.0.tgz#f74bf9743bacafe4c8573be46166130c604c0fc1"
integrity sha512-Ze7WuW2Xzy5GT5WRx+yEv89fsg/pgy3T1E3FS0QEx0/VvRmigMZ5qyVGhJz4SxomegDkzXv/i0aFPpHKN8qdAA==
dependencies:
deepmerge "^4.2.2"
"@sendgrid/mail@^8.1.1":
version "8.1.1"
resolved "https://registry.yarnpkg.com/@sendgrid/mail/-/mail-8.1.1.tgz#506bc02c3a884d5c979278d6966f118afce37f93"
integrity sha512-tNtmgWLtBA7ZxKtPuEGOaIdEZP1vZSXsj5zg9iuoDBPVj/fNz+7LWzndvTcKumHk5eaDrS0UPXJqBm61m3+H1A==
dependencies:
"@sendgrid/client" "^8.1.1"
"@sendgrid/helpers" "^8.0.0"
"@styled-system/background@^5.1.2":
version "5.1.2"
resolved "https://registry.npmjs.org/@styled-system/background/-/background-5.1.2.tgz"
@ -2853,7 +2876,7 @@ axe-core@^4.6.2:
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.8.2.tgz#2f6f3cde40935825cf4465e3c1c9e77b240ff6ae"
integrity sha512-/dlp0fxyM3R8YW7MFzaHWXrf4zzbr0vaYb23VBFCl83R7nWNPg/yaQw2Dc8jzCMmDVLhSdzH8MjrsuIUuvX+6g==
axios@^1.6.7:
axios@^1.6.4, axios@^1.6.7:
version "1.6.7"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.7.tgz#7b48c2e27c96f9c68a2f8f31e2ab19f59b06b0a7"
integrity sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==
@ -3198,20 +3221,10 @@ camelize@^1.0.0:
resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3"
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.30001541:
version "1.0.30001554"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001554.tgz#ba80d88dff9acbc0cd4b7535fc30e0191c5e2e2a"
integrity sha512-A2E3U//MBwbJVzebddm1YfNp7Nud5Ip+IPn4BozBmn4KqVX7AvluoIDFWjsv5OkGnKUXQVmMSoMKLa3ScCblcQ==
caniuse-lite@^1.0.30001406:
version "1.0.30001474"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001474.tgz"
integrity sha512-iaIZ8gVrWfemh5DG3T9/YqarVZoYf0r188IjaGwx68j4Pf0SGY6CQkmJUIE+NZHkkecQGohzXmBGEwWDr9aM3Q==
caniuse-lite@^1.0.30001517:
version "1.0.30001520"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001520.tgz#62e2b7a1c7b35269594cf296a80bdf8cb9565006"
integrity sha512-tahF5O9EiiTzwTUqAeFjIZbn4Dnqxzz7ktrgGlMYNLH43Ul26IgTMH/zvL3DG0lZxBYnlT04axvInszUsZULdA==
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.30001517, caniuse-lite@^1.0.30001541:
version "1.0.30001600"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz"
integrity sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==
caseless@~0.12.0:
version "0.12.0"
@ -3410,6 +3423,11 @@ commondir@^1.0.1:
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==
compute-scroll-into-view@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz#753f11d972596558d8fe7c6bcbc8497690ab4c87"
integrity sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
@ -4497,9 +4515,9 @@ flatted@^3.1.0:
integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==
follow-redirects@^1.15.4:
version "1.15.5"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020"
integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==
version "1.15.6"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
for-each@^0.3.3:
version "0.3.3"
@ -7345,6 +7363,13 @@ react-fast-compare@^3.2.0:
resolved "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz"
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
react-horizontal-scrolling-menu@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/react-horizontal-scrolling-menu/-/react-horizontal-scrolling-menu-6.0.2.tgz#9b34ce979880e60803e24f53db122ab6ef6a714c"
integrity sha512-TuM9QunJ6ykA5OUjScBvB+e0IM60wXGSTmbzs5zoLwaCX3rnSoJejj8ScQ3wP/MWr88OeSEh1RN4TCa3fTGuqA==
dependencies:
smooth-scroll-into-view-if-needed "^2.0.2"
react-is@16.13.1, react-is@^16.10.2, react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
@ -7632,10 +7657,10 @@ regjsparser@^0.9.1:
dependencies:
jsesc "~0.5.0"
rehackt@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/rehackt/-/rehackt-0.0.5.tgz#184c82ea369d5b0b989ede0593ebea8b2bcfb1d6"
integrity sha512-BI1rV+miEkaHj8zd2n+gaMgzu/fKz7BGlb4zZ6HAiY9adDmJMkaDcmuXlJFv0eyKUob+oszs3/2gdnXUrzx2Tg==
rehackt@0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/rehackt/-/rehackt-0.0.6.tgz#7a0a2247f2295e7548915417e44fbbf03bf004f4"
integrity sha512-l3WEzkt4ntlEc/IB3/mF6SRgNHA6zfQR7BlGOgBTOmx7IJJXojDASav+NsgXHFjHn+6RmwqsGPFgZpabWpeOdw==
rehype-parse@^8.0.0:
version "8.0.5"
@ -7955,6 +7980,13 @@ scheduler@^0.20.2:
loose-envify "^1.1.0"
object-assign "^4.1.1"
scroll-into-view-if-needed@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz#fa9524518c799b45a2ef6bbffb92bcad0296d01f"
integrity sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==
dependencies:
compute-scroll-into-view "^3.0.2"
semver@^5.4.1:
version "5.7.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
@ -8067,6 +8099,13 @@ slash@^4.0.0:
resolved "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz"
integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==
smooth-scroll-into-view-if-needed@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/smooth-scroll-into-view-if-needed/-/smooth-scroll-into-view-if-needed-2.0.2.tgz#5bd4ebef668474d6618ce8704650082e93068371"
integrity sha512-z54WzUSlM+xHHvJu3lMIsh+1d1kA4vaakcAtQvqzeGJ5Ffau7EKjpRrMHh1/OBo5zyU2h30ZYEt77vWmPHqg7Q==
dependencies:
scroll-into-view-if-needed "^3.1.0"
source-map-js@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
@ -8196,7 +8235,6 @@ string-hash@1.1.3:
integrity sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
name string-width-cjs
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==