Full Code of hackclub/site for AI

main 63b1a0792795 cached
274 files
1.3 MB
358.9k tokens
287 symbols
1 requests
Download .txt
Showing preview only (1,413K chars total). Download the full file or copy to clipboard to get everything.
Repository: hackclub/site
Branch: main
Commit: 63b1a0792795
Files: 274
Total size: 1.3 MB

Directory structure:
gitextract_sca6vlk2/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── attachment-warn.yml
│       ├── caniuse-update.yml
│       ├── ci.yml
│       └── validate-team-json.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── AGENT.md
├── LICENSE.md
├── README.md
├── components/
│   ├── AButton.ts
│   ├── analytics.tsx
│   ├── announcement.tsx
│   ├── announcements/
│   │   ├── amount.tsx
│   │   ├── cta.tsx
│   │   ├── elon.mdx
│   │   ├── hcb-mobile.mdx
│   │   ├── hcb-open-source.mdx
│   │   ├── hcb_cta.tsx
│   │   ├── holder.tsx
│   │   ├── pills.tsx
│   │   ├── preston-werner-2022.mdx
│   │   ├── preston-werner.mdx
│   │   └── relon.mdx
│   ├── arcade/
│   │   ├── footer.tsx
│   │   └── projects.tsx
│   ├── background-image.tsx
│   ├── bin/
│   │   ├── GalleryPosts.tsx
│   │   ├── PartTag.module.css
│   │   ├── PartTag.tsx
│   │   ├── nav.tsx
│   │   └── rsvp-form.tsx
│   ├── bio.tsx
│   ├── boardbio.tsx
│   ├── color-switcher.tsx
│   ├── comma.ts
│   ├── directoryModal.tsx
│   ├── donate/
│   │   ├── donors.json
│   │   └── sponsors.tsx
│   ├── dot.tsx
│   ├── elon.mdx
│   ├── fade-in.tsx
│   ├── fiscal-sponsorship/
│   │   ├── contact.tsx
│   │   ├── directory/
│   │   │   └── card.tsx
│   │   ├── features.tsx
│   │   ├── first/
│   │   │   ├── apply-button.tsx
│   │   │   ├── features.tsx
│   │   │   ├── start.tsx
│   │   │   ├── stats.tsx
│   │   │   └── testimonials.tsx
│   │   ├── open-source.tsx
│   │   ├── organization-spotlight.tsx
│   │   ├── sign-in.tsx
│   │   └── tooltip.tsx
│   ├── flag.tsx
│   ├── flex-col.tsx
│   ├── footer.tsx
│   ├── force-theme.ts
│   ├── hackathons/
│   │   ├── features/
│   │   │   ├── marketing.tsx
│   │   │   └── slack.tsx
│   │   ├── keep-exploring.tsx
│   │   ├── landing.tsx
│   │   ├── overview.tsx
│   │   ├── recap.tsx
│   │   └── scrolling-hackathons.tsx
│   ├── icon.tsx
│   ├── index/
│   │   ├── cards/
│   │   │   ├── beest.tsx
│   │   │   ├── button.tsx
│   │   │   ├── card-model.tsx
│   │   │   ├── clubs.tsx
│   │   │   ├── fallout.tsx
│   │   │   ├── flavortown.tsx
│   │   │   ├── hackathons.tsx
│   │   │   ├── haxidraw.tsx
│   │   │   ├── hcb.tsx
│   │   │   ├── hctg.tsx
│   │   │   ├── horizons.tsx
│   │   │   ├── jackpot.tsx
│   │   │   ├── macondo.tsx
│   │   │   ├── mailing-list.tsx
│   │   │   ├── sinerider.tsx
│   │   │   ├── slack.tsx
│   │   │   ├── sleepover.tsx
│   │   │   ├── sprig-console.tsx
│   │   │   ├── sprig.tsx
│   │   │   ├── stasis.tsx
│   │   │   └── workshops.tsx
│   │   ├── carousel-cards.tsx
│   │   ├── carousel.tsx
│   │   ├── ctas.tsx
│   │   ├── events.tsx
│   │   └── github.tsx
│   ├── letterhead.tsx
│   ├── mail-card.tsx
│   ├── marquee.tsx
│   ├── mention.tsx
│   ├── nav.tsx
│   ├── onboard/
│   │   ├── gallery-paginated.tsx
│   │   ├── item.tsx
│   │   ├── pagination-buttons.tsx
│   │   ├── recap.tsx
│   │   └── youtube-video.tsx
│   ├── particles.tsx
│   ├── photo.tsx
│   ├── posts/
│   │   ├── emoji.tsx
│   │   ├── index.tsx
│   │   └── mention.tsx
│   ├── press.mdx
│   ├── react-reveal-compat.tsx
│   ├── react-tooltip.ts
│   ├── replit/
│   │   ├── scale-up.tsx
│   │   └── token-instructions.tsx
│   ├── scroll-hint.tsx
│   ├── secret.tsx
│   ├── ship/
│   │   └── why.mdx
│   ├── signature.tsx
│   ├── signatures.tsx
│   ├── slack.tsx
│   ├── slide-down.tsx
│   ├── slide-up.tsx
│   ├── sparkles/
│   │   ├── index.tsx
│   │   └── money.tsx
│   ├── stage.tsx
│   ├── stat.tsx
│   ├── submit.tsx
│   ├── tilt.tsx
│   └── winter/
│       ├── breakdown-box.tsx
│       ├── breakdown.tsx
│       ├── footer.tsx
│       ├── info.tsx
│       ├── landing.tsx
│       ├── projects.tsx
│       ├── recap.tsx
│       └── timeline.tsx
├── eslint.config.mts
├── lib/
│   ├── cached-hcb-orgs.ts
│   ├── countries.json
│   ├── cta.json
│   ├── dates.ts
│   ├── fetcher.ts
│   ├── git-info.ts
│   ├── helpers.ts
│   ├── members.ts
│   ├── organization.ts
│   ├── slackData.ts
│   ├── sleep.ts
│   ├── theme.ts
│   ├── use-form.ts
│   ├── use-has-mounted.ts
│   ├── use-media.ts
│   ├── use-prefers-motion.ts
│   ├── use-prefers-reduced-motion.ts
│   └── use-random-interval.ts
├── next.config.ts
├── package.json
├── pages/
│   ├── 404.tsx
│   ├── _app.tsx
│   ├── _document.tsx
│   ├── acknowledged.tsx
│   ├── amas/
│   │   ├── geohot.tsx
│   │   ├── index.tsx
│   │   ├── sal.tsx
│   │   └── vitalik.tsx
│   ├── api/
│   │   ├── arcade/
│   │   │   ├── hack-hour/
│   │   │   │   └── inventory.ts
│   │   │   └── shop.ts
│   │   ├── bin/
│   │   │   ├── gallery/
│   │   │   │   ├── posts.ts
│   │   │   │   └── tags.ts
│   │   │   ├── rsvp.ts
│   │   │   └── wokwi/
│   │   │       ├── new/
│   │   │       │   ├── [parts].ts
│   │   │       │   └── index.ts
│   │   │       └── parts.ts
│   │   ├── bucky.ts
│   │   ├── channels/
│   │   │   └── resolve.ts
│   │   ├── contribute.ts
│   │   ├── first-team.ts
│   │   ├── games.ts
│   │   ├── github.ts
│   │   ├── join.ts
│   │   ├── mailing-list.ts
│   │   ├── onboard/
│   │   │   ├── p/
│   │   │   │   ├── [project]/
│   │   │   │   │   └── index.ts
│   │   │   │   ├── count.ts
│   │   │   │   └── index.ts
│   │   │   └── svg/
│   │   │       └── [board_url]/
│   │   │           ├── bottom.ts
│   │   │           ├── index.ts
│   │   │           └── top.ts
│   │   ├── replit/
│   │   │   └── signup.ts
│   │   ├── sprig-console.ts
│   │   ├── stars.ts
│   │   ├── steve.ts
│   │   ├── stickers.ts
│   │   ├── stuff.ts
│   │   ├── team.ts
│   │   └── winter-rsvp.ts
│   ├── arcade/
│   │   └── index.tsx
│   ├── bin/
│   │   ├── gallery.tsx
│   │   └── prelaunch.tsx
│   ├── brand.tsx
│   ├── clubs.tsx
│   ├── content/
│   │   ├── covid19.mdx
│   │   ├── it-admins.mdx
│   │   ├── sponsorship.mdx
│   │   ├── sunsetting-som.mdx
│   │   └── transparency/
│   │       └── may-2020.mdx
│   ├── deprecated/
│   │   └── [deprecated].tsx
│   ├── elon.tsx
│   ├── events.tsx
│   ├── fiscal-sponsorship/
│   │   ├── about.tsx
│   │   ├── climate/
│   │   │   ├── [region].tsx
│   │   │   └── index.tsx
│   │   ├── directory/
│   │   │   ├── [category]/
│   │   │   │   ├── [region].tsx
│   │   │   │   └── index.tsx
│   │   │   └── index.tsx
│   │   ├── first.tsx
│   │   ├── index.tsx
│   │   ├── mobile/
│   │   │   └── index.tsx
│   │   └── open-source.tsx
│   ├── hackathons/
│   │   ├── grant.tsx
│   │   └── index.tsx
│   ├── imprint.tsx
│   ├── index.tsx
│   ├── jobs/
│   │   └── index.tsx
│   ├── minecraft.tsx
│   ├── night.tsx
│   ├── onboard/
│   │   ├── board/
│   │   │   └── [slug].tsx
│   │   ├── first.tsx
│   │   ├── gallery/
│   │   │   └── index.tsx
│   │   └── index.tsx
│   ├── opensource.tsx
│   ├── philanthropy/
│   │   ├── index.tsx
│   │   └── supporters.tsx
│   ├── philosophy.tsx
│   ├── pizza.tsx
│   ├── press.tsx
│   ├── preston-werner-2022.tsx
│   ├── preston-werner.tsx
│   ├── relon.tsx
│   ├── replit.tsx
│   ├── santa.tsx
│   ├── sharkbank/
│   │   └── index.tsx
│   ├── ship.tsx
│   ├── sitemap.xml.tsx
│   ├── steve.tsx
│   ├── stickers.tsx
│   ├── team.tsx
│   └── winter.tsx
├── public/
│   ├── .well-known/
│   │   └── security.txt
│   ├── acknowledged.json
│   ├── bin/
│   │   ├── data-loading.js
│   │   ├── index.html
│   │   ├── landing/
│   │   │   ├── index.html
│   │   │   ├── script.js
│   │   │   └── style.css
│   │   ├── landing-new/
│   │   │   ├── ascii-art.txt
│   │   │   ├── gambling.js
│   │   │   ├── script.js
│   │   │   └── style.css
│   │   ├── memes.js
│   │   ├── orph/
│   │   │   ├── orph.css
│   │   │   └── orph.js
│   │   ├── selector/
│   │   │   ├── index.html
│   │   │   ├── script.js
│   │   │   └── style.css
│   │   └── style/
│   │       ├── common.css
│   │       ├── footer.css
│   │       └── gallery.module.css
│   ├── carousel.json
│   ├── horizons/
│   │   └── Hypebuzz.otf
│   ├── robots.txt
│   ├── stickers-in-stock.html
│   └── team.json
├── tsconfig.json
├── types/
│   └── mdx.d.ts
└── vercel.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
  - package-ecosystem: 'bun'
    directory: '/'
    schedule:
      interval: 'weekly'

  - package-ecosystem: 'github-actions'
    directory: '/'
    schedule:
      interval: 'weekly'


================================================
FILE: .github/workflows/attachment-warn.yml
================================================
name: Perhaps You Should Upload To CDN Instead?

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  warn:
    runs-on: ubuntu-slim
    permissions:
      pull-requests: write
    steps:
      - uses: actions/github-script@v9
        continue-on-error: true
        with:
          # this checks via the octokit, because just using pull_requests.paths would warn on every single commit, regardless of the files changed if the PR has at least 1 attachment in it
          script: |
            // dont comment again if already commented
            const comments = await github.rest.issues.listComments({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.issue.number
            });

            const existingComment = comments.data.find(c =>
              c.body.includes("Heyo, maybe upload these to a CDN instead")
            );

            // unallowed file extensions
            const EXTENSIONS = [
              'png','jpg','jpeg','gif','webp',
              'webm','pdf','mp4','mov','zip',
            ];

            // paginate cause what if there's 100+ changed files, better safe than sorry
            const files = await github.paginate(
              github.rest.pulls.listFiles,
              {
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  pull_number: context.issue.number,
                  per_page: 100
              }
            );

            // check if any of the changed files have unallowed extension, and are not removed
            // only exclude removed files, since modifying/copying/etc has the same hit to the repo size as a new file
            const blobs = files.filter(f => {
              if (!f.filename.includes('.')) return false;
              const ext = f.filename.split('.').pop().toLowerCase();
              return EXTENSIONS.includes(ext) && f.status !== 'removed';
            });

            if (blobs.length === 0) {
              // if we already commented, but the files were removed, edit the comment to kinda mark as resolved
              if (existingComment) {
                await github.rest.issues.updateComment({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  comment_id: existingComment.id,
                  body: `## ~~Heyo, maybe upload these to a CDN instead~~\n\nThis has been resolved now.`
                });
                return;
              }
              return
            };

            const prefix = `## Heyo, maybe upload these to a CDN instead\n\nImages, videos or any attachments can unnecessarily bloat the repository size. Consider uploading these files to [Hack Club CDN](https://cdn.hackclub.com/) instead, and using the CDN links instead.\n\n---\n\n### Files Detected:\n\n`;

            if (existingComment) {
              // Update existing comment with new file list
              await github.rest.issues.updateComment({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  comment_id: existingComment.id,
                  body: `${prefix}${blobs.map(b => `- \`${b.filename}\``).join('\n')}`
              });
              return;
            }

            // create comment if there are any attachments
            await github.rest.issues.createComment({ 
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: `${prefix}${blobs.map(b => `- \`${b.filename}\``).join('\n')}`
            });


================================================
FILE: .github/workflows/caniuse-update.yml
================================================
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@v6
        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.


================================================
FILE: .github/workflows/ci.yml
================================================
name: CI
on:
  - push
  - pull_request

jobs:
  lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v6
      - uses: oven-sh/setup-bun@v2
      - run: bun install
      - run: bun run lint

  format:
    name: Format
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-node@v6
      - uses: oven-sh/setup-bun@v2
      - run: bun install
      - run: bun run format:check


================================================
FILE: .github/workflows/validate-team-json.yml
================================================
name: Validate Team JSON

on:
  push:
    paths:
      - 'public/team.json'
  pull_request:
    paths:
      - 'public/team.json'

jobs:
  validate:
    name: Validate team.json
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - name: Validate JSON format
        run: |
          if ! jq empty public/team.json 2>/dev/null; then
            echo "Error: team.json is not valid JSON"
            exit 1
          fi
          echo "✓ team.json is valid JSON"


================================================
FILE: .gitignore
================================================
.now
.env*
.next
node_modules
.DS_Store
public/sitemap.xml
.vercel
.vscode
yarn-error.log
bun.lockb
.idea
.yarn
.yarnrc.yml
.env*.local
tsconfig.tsbuildinfo
next-env.d.ts

================================================
FILE: .prettierignore
================================================
.next

================================================
FILE: .prettierrc
================================================
{
  "singleQuote": true,
  "trailingComma": "none",
  "arrowParens": "avoid",
  "printWidth": 80,
  "semi": false
}


================================================
FILE: AGENT.md
================================================
# AGENT.md - Hack Club Site Development Guide

## Commands

- **Dev**: `bun run dev` (start development server)
- **Build**: `bun run build` (production build)
- **Lint**: `bun run lint` (Next.js ESLint)
- **Format**: `bun run format` (Prettier formatting)
- **Start**: `bun run start` (production server)
- **Test**: No test framework configured

## Code Style

- **Imports**: Use relative imports (`../components/nav`), Theme UI components (`{ Box, Text }`)
- **Formatting**: Single quotes, no semicolons, no trailing commas, 80 char width
- **Components**: Functional components with destructured props, default exports
- **Styling**: Theme UI `sx` prop for styling, styled components with @emotion/styled
- **Types**: TypeScript enabled but strict mode off, prefer implicit typing
- **Naming**: camelCase for variables/functions, PascalCase for components

## Architecture

- Next.js app with pages/ directory structure
- MDX support for content pages
- Theme UI for consistent styling with Hack Club theme
- Components in components/ directory, modular cards in components/index/cards/
- Static assets in public/
- Configuration in next.config.mjs includes essential redirects/rewrites


================================================
FILE: LICENSE.md
================================================
_Code under MIT License, assets may not be re-used or re-distributed._

### MIT License

Copyright 2026 The Hack Foundation

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: README.md
================================================
<p align="center"><img width="192" alt="Hack Club logo" src="https://assets.hackclub.com/flag-standalone.svg"></p>
<h1 align="center"><a href="https://hackclub.com/">Hack Club's Site (v3)</a></h1>
<p align="center"><i>The source code for hackclub.com</i></p>

Hack Club's new website. This codebase is what runs on [hackclub.com](https://hackclub.com). For new developers getting started, run the following in your terminal:

1. Download the code to your computer:

   ```bash
   git clone https://github.com/hackclub/site && cd site
   ```

2. Install dependencies:

   ```bash
   bun install
   ```

3. Start running the website on your computer:

   ```bash
   bun run dev
   ```

4. Open up your web browser and go to [localhost:3000](http://localhost:3000)

> [!NOTE]
> There are a number of redirects and rewrites essential to the website's functionality, which you can see in [next.config.ts](./next.config.ts).

Powered by [Next.js] with [MDX], [Theme UI], & [Hack Club Theme].

Code under MIT License, assets may not be re-used or re-distributed.

---

<h1 align="center">Building <a href="https://hackclub.com/">hackclub.com</a></h1>

Join us in building Hack Club's homepage and show new hackers what Hack Club could be for them 💖.

See something that could be better? Make a PR! Have an easter egg idea? Make a PR! Is the site missing something? Make a PR! _(Do you see a trend? :))_

If you need to add content to the site, here's how you can:

<details> <summary>Create a new card</summary>
<img width="600" alt="Screenshot of the Sprig card" src="https://github.com/hackclub/site/assets/65808924/fed45800-c834-4e4c-ad87-a21e01414fa9">

Most things on the homepage are cards, modular components that can easily be added and removed according to relevancy to Hack Clubbers. There are 3 main sections: connection, open-source, and IRL community. Most new cards will likely fall within the first two sections!

First, you can create a new file under [components/index/cards](components/index/cards/) with the name of your new event/project. Next add `import CardModel from './card-model'` and add whatever you want :) Finally, use a `<Buttons>` component (`import Buttons from './button'`) to highlight call-to-action buttons. If it's the main button, use the primary prop to add a background color!

Your challenge: try and make the card as unique as possible, like a mini poster! Not sure where to start? Look at other cards on the page :)

</details>

<details>
<summary>Add to the carousel</summary>

<img width="600" alt="Screenshot of a carousel section" src="https://github.com/hackclub/site/assets/65808924/044660eb-fb3d-43b6-a270-64a3fe51f3ca">

If there's a Hack Club or Hack Club community-led project (past or present) that Hack Clubbers can get involved in, please add it to [public/carousel.json](public/carousel.json) and add your card to the end of the json file. An example looks like this:

```json
{
  "background": "dark",
  "titleColor": "white",
  "descriptionColor": "white",
  "title": "Hackers Wanted",
  "description": "Our open love letter to hackers",
  "img": "https://a.slack-edge.com/production-standard-emoji-assets/14.0/apple-large/1f4bb@2x.png",
  "link": "/hackers-wanted"
}
```

</details>

Every week, thousands of people visit hackclub.com. What story do you want to tell?

_Have questions? Join us in [#hackclub-site-dev](https://hackclub.slack.com/archives/C036BTDGP43) and to learn more about the style guide at Hack Club check [this](https://hackclub.com/brand/) out_

---

Hack Club, 2026. MIT License.

[next.js]: https://nextjs.org
[mdx]: https://mdxjs.com
[theme ui]: https://theme-ui.com
[hack club theme]: https://theme.hackclub.com


================================================
FILE: components/AButton.ts
================================================
import { Button } from 'theme-ui'

export const AButton = Button as any


================================================
FILE: components/analytics.tsx
================================================
import Script from 'next/script'

const Analytics = () => (
  <Script
    defer
    data-domain="hackclub.com"
    src="https://plausible.io/js/script.pageview-props.tagged-events.js"
  />
)

export default Analytics


================================================
FILE: components/announcement.tsx
================================================
import { keyframes } from '@emotion/react'
import Image from 'next/image'
import { Box, Card, Text } from 'theme-ui'
import Icon from './icon'

export const unfold = keyframes({
  from: { transform: 'scaleY(0)' },
  to: { transform: 'scaleY(100%)' }
})

type AnnouncementProps = {
  caption?: string
  copy: string
  iconLeft?: string
  iconRight?: string
  imgSrc?: string
  imgAlt?: string
  color?: string
  textColor?: string
  sx?: any
  width?: number | string
  href?: string
}

const Announcement = ({
  caption,
  copy,
  iconLeft,
  iconRight,
  imgSrc,
  imgAlt,
  color = 'accent',
  textColor = 'secondary',
  sx = {},
  width,
  ...props
}: AnnouncementProps) => (
  <Card
    as={props.href ? 'a' : 'div'}
    variant="interactive"
    sx={{
      variant: 'cards.translucent',
      mx: 'auto',
      maxWidth: 'narrow',
      width: width ? width : '100%',
      textAlign: 'left',
      textDecoration: 'none',
      lineHeight: 'caption',
      display: 'flex',
      alignItems: 'center',
      p: [2, 2],
      px: 3,
      mb: [3, 4],
      mt: [null, -3, -5],
      transform: 'scale(1)',
      '@media (prefers-reduced-motion: no-preference)': {
        animation: `${unfold} 0.5s ease-out`
      },
      svg: { flexShrink: 'none' },
      ...sx
    }}
    {...props}
  >
    {iconLeft && (
      <Icon
        glyph={iconLeft}
        sx={{ mr: [2, 3], ml: 2, color, display: ['none', 'block'] }}
      />
    )}
    {imgSrc && (
      <Box sx={{ mr: [2, 3], ml: 2, width: 32, flexShrink: 0 }}>
        <Image
          src={imgSrc}
          alt={imgAlt}
          width={32}
          height={32}
          style={{
            maxWidth: '100%',
            height: 'auto'
          }}
        />
      </Box>
    )}
    <Text
      as="p"
      sx={{
        flex: '1 1 auto',
        strong: { display: ['inline', 'block'], color: textColor }
      }}
    >
      <strong>{copy}</strong>
      {caption && (
        <Text as="span" variant="caption" color={textColor}>
          {' '}
          {caption}
        </Text>
      )}
    </Text>
    {iconRight && <Icon glyph={iconRight} sx={{ ml: [2, 3], color }} />}
  </Card>
)

export default Announcement


================================================
FILE: components/announcements/amount.tsx
================================================
import Sparkles from '../sparkles'

const Amount = ({ amount }) => (
  <Sparkles
    sx={{
      WebkitTextStroke: 'currentColor',
      WebkitTextStrokeWidth: ['2px', '3px'],
      WebkitTextFillColor: 'transparent'
    }}
  >
    {amount}
  </Sparkles>
)

export default Amount


================================================
FILE: components/announcements/cta.tsx
================================================
import { Box, Button, Grid, Heading, Text } from 'theme-ui'
import Icon from '@hackclub/icons'
import NextLink from 'next/link'
import { thousands } from '../../lib/members'

export default function SlackCTA() {
  return (
    <Box
      as="section"
      sx={{
        bg: 'orange',
        backgroundImage: (t: any) => t.util.gx('yellow', 'orange'),
        color: 'white',
        py: [4, 5]
      }}
    >
      <Grid gap={[3, 4]} columns={[null, 'auto 1fr']} variant="layout.copy">
        <Icon glyph="welcome" size={72} />
        <Box>
          <Heading as="h2" variant="headline" mt={0}>
            Teenager? New here? Welcome!
          </Heading>
          <Text variant="subtitle" sx={{ lineHeight: 'caption', mb: 3 }}>
            Hack Club is a global community of high school makers & student-led
            coding clubs. We’ve got a 24/7 Slack chatroom of {thousands}k+
            teenagers learning to code & building amazing projects, & you’ll fit
            right in.
          </Text>
          <br />
          <br />
          <NextLink href="/">
            <Button bg="cyan">Learn more</Button>
          </NextLink>
        </Box>
      </Grid>
    </Box>
  )
}


================================================
FILE: components/announcements/elon.mdx
================================================
import Amount from './amount'
import Signature from '../signature'

# Today, I’m proud to share: Elon&nbsp;Musk is donating <Amount amount="$500,000" /> to&nbsp;[Hack&nbsp;Club](https://hackclub.com).

Elon Musk is one of the most prolific and ambitious hackers of the last decade.

It was a huge honor last month to have Elon [spend an hour in an ask-me-anything call with our community of high schoolers](https://youtu.be/riru9OzScwk)—at one point he remarked we were “asking better questions than all the mainstream media” and called our community “very wholesome.”

**Afterwards, Elon wanted to support Hack&nbsp;Club further.**

When hackers see problems in the world, we don’t blame someone else: we try to take them on to solve. Elon is very selective about the nonprofits he supports and I’m proud Hack&nbsp;Club is one of them.

So…how will Hack&nbsp;Club invest $500,000? We want to use this to help 1,000 more students start and join Hack Clubs in their towns ([see the worldwide map](https://hackclub.com/map/)). For those already in Hack&nbsp;Club, we look to you to help us make a higher-quality experience. We plan to continue much of what we’re already doing (and [what I wrote about in January](https://zachinto2020.wordpress.com/2019/12/31/as-midnight-approaches/)): spending as little money as possible at all times, growing slowly, adding diverse staff to make Hack&nbsp;Club better (video game designers, software engineers, media producers, and more). We are pushing hard to try and make the [Hack&nbsp;Club Slack](https://hackclub.com/) the best place to be a teenager on the internet and expanding [HCB](https://hackclub.com/fiscal-sponsorship/).

We’ll be fully transparent in how we spend this money. One thing we’ve been working toward after winning the [Frank Grant](https://grant.frank.ly/) is open sourcing our finances. Hack&nbsp;Club HQ has been running on HCB since February, and starting today, [**you can see our finances publicly**](https://hcb.hackclub.com/hq). Through HCB, you can track how we spend every dollar of Elon’s gift. Soon, we’ll also launch [Frank’s](https://frank.ly/) transparency tools on [hackclub.com](https://hackclub.com/).

Hack&nbsp;Club’s mission is to build a new generation of hackers. This starts in high school, where Hack&nbsp;Club students learn to be technically proficient, build their friend network, learn to raise and spend money, and develop into kind, curious, thoughtful, optimistic, and honest leaders. And now Elon Musk is one of our largest supporters.

To every Hack Clubber: Elon is now supporting you and your work, so go forth and do amazing things. We can’t wait to show Elon what you make.

<Signature fname="Zach" lname="Latta" />

Zach Latta, Founder


================================================
FILE: components/announcements/hcb-mobile.mdx
================================================
I’m Mohamad, a 17-year-old from the SF Bay Area, and I just shipped the official mobile app for HCB.

If you haven't heard of it, HCB is the financial backbone for over **6,500 teenager-led nonprofits**, clubs, and hackathons. We provide **501(c)(3) nonprofit** status, access to a bank account, a donation collection platform, and debit cards for thousands of young people trying to do good in their communities.

HCB is currently processing an average of **$6 million per month** (over $80M in its lifetime).[^1] For the last year, I’ve led the project to build the first-ever mobile app for this entire community.

_The entire project is open source on [GitHub](https://github.com/hackclub/hcb-mobile) (we'd love a ⭐️!)._

## Why build this?

These teenagers are running run robotics teams, hackathons, and nonprofit projects that improve their community. They need a way to manage their organization's finances from their pocket.
With HCB Mobile, they'll be able to:

- Track their **organization's balance** and transactions on the go.
- Accept in-person **tap-to-pay donations**, perfect for an in-person fundraiser or event! No extra hardware required. Just tap any credit/debit card against your phone.
- **Issue new debit cards**, add them to **Apple / Google Wallet**, and freeze or cancel them directly from their phone.
- **Upload receipts** directly from their device or match existing receipts in Receipt Bin to transactions with a tap.

## The Technical Stuff

When I started working on this app, I wanted to build in native code like **SwiftUI** for iOS and **Kotlin/Jetpack Compose** for Android. However, I realized that it would be a pain for me, a **full-time student** with classes, to handle two codebases. I'd have to duplicate every feature I created for one OS to the other and deal with all the integration issues along the way. Then, I discovered **Expo** (a React Native framework) which allowed me to write one app that worked on multiple devices. Working with Expo, I learned about creating my own Expo Modules (to bridge native code features to Typescript) and optimization methods like memoization and component recycling.

The non-code side of this app was _no joke_, either. I had to work with the Apple and Google app review teams to obtain **restricted entitlements** for features like mobile **tap-to-pay terminal provisioning** (made possible by Stripe) and **push provisioning** (which allows users to add cards to their payment wallet directly from HCB Mobile). It took several months and many back-and-forth email chains to finally get the entitlements we needed.

After over 250 hours of development work, I can say that I'm incredibly proud of HCB Mobile because it's **built by teenagers** to make it easier for teenagers like me to run nonprofit organizations and projects with HCB. Beyond teenagers, HCB also supports hundreds of adult-ran organizations such as mutual aid groups, open source projects, and community spaces.

<br />

## Download the app!

<br />
<a href="https://apps.apple.com/us/app/hcb-by-hack-club/id6465424810">
  <img
    src="/fiscal-sponsorship/apple-web-badge.svg"
    alt="Download on the App Store"
    height="40"
  />
</a>
&nbsp;&nbsp;&nbsp;
<a href="https://play.google.com/store/apps/details?id=com.hackclub.hcb">
  <img
    src="/fiscal-sponsorship/google-play-web-badge.png"
    alt="Get it on Google Play"
    height="40"
  />
</a>

[^1]: _This amount is excluding HQ (our own) [finances](https://hcb.hackclub.com/hq)._


================================================
FILE: components/announcements/hcb-open-source.mdx
================================================
Hack Club launched HCB in 2018 to enable hackathons to raise and spend money
through [fiscal sponsorship](https://hackclub.com/fiscal-sponsorship/). Since
then, we’ve expanded to all nonprofit projects; our 12,000 users have transacted
$50 million.

<p style={{ textAlign: 'center' }}>
  <img
    alt="HCB's user interface showing Hack Club HQ's transactions"
    src="https://cdn.hackclub.com/019c76b7-a601-7e83-a9fb-e26595864142/flGLlg.png"
    width="700px"
  />
</p>

Local student-ran hackathons, robotics teams, and community groups use HCB as a
nonprofit neobank to collect donations, send payments, issue debit cards, and
gain 501(c)(3) status.

When we started HCB, it was developed in private for security reasons. That
said, one of Hack Club’s core principles has always been transparency - we [open
source](https://github.com/hackclub/ledger) our
[finances](https://hcb.hackclub.com/hq), [document how we run
events](https://github.com/hackclub/assemble), and have 500+ public repositories
on [GitHub](https://github.com/hackclub).

**_[github.com/hackclub/hcb](https://github.com/hackclub/hcb) is now public -
check it out and star it._**

Paired with our technical documentation, it’s a great resource for anyone
interested in building financial software or applications with Ruby on Rails.
Our engineering work is also entirely public; the world can learn from our
successes and mistakes.

Since 2018, over fifty people have made 10k+ commits to HCB (thank you!); we
can’t wait for more contributors to join us:

<video width="100%" controls style={{ borderRadius: '8px' }}>
  <source
    src="https://noras-second-secret-cdn.hackclub.dev/gsource.mp4"
    type="video/mp4"
  />
  Your browser does not support the video tag.
</video>

PS: if you’re looking to start a nonprofit, we’re accepting applications! Head
over to [nonprofit.new](https://nonprofit.new/) and we’ll be in touch.

<img src="https://cdn.hackclub.com/019c76b9-f285-79f8-93af-2b43e0a67674/A8ZCLg.jpeg" />
<small>We're launching this live from SF!</small>


================================================
FILE: components/announcements/hcb_cta.tsx
================================================
import { Box, Button, Grid, Heading, Text } from 'theme-ui'
import Icon from '@hackclub/icons'
import NextLink from 'next/link'

export default function HCBCTA() {
  return (
    <Box
      as="section"
      sx={{
        bg: 'orange',
        backgroundImage: (t: any) => t.util.gx('yellow', 'orange'),
        color: 'white',
        py: [4, 5]
      }}
    >
      <Grid gap={[3, 4]} columns={[null, 'auto 1fr']} variant="layout.copy">
        <Icon glyph="bank-account" size={72} />
        <Box>
          <Heading as="h2" variant="headline" mt={0}>
            Looking to start a nonprofit?
          </Heading>
          <Text variant="subtitle" sx={{ lineHeight: 'caption', mb: 3 }}>
            We're accepting applications! No startup fees, no minimum balance,
            and no long wait time.
          </Text>
          <br />
          <br />
          <NextLink href="/fiscal-sponsorship">
            <Button bg="cyan">Learn more</Button>
          </NextLink>
          &nbsp;&nbsp;&nbsp;
          <NextLink href="https://nonprofit.new">
            <Button bg="orange">Apply now</Button>
          </NextLink>
        </Box>
      </Grid>
    </Box>
  )
}


================================================
FILE: components/announcements/holder.tsx
================================================
import { Container, BaseStyles } from 'theme-ui'

export default function AnnouncementHolder({ children }) {
  return (
    <Container
      as={BaseStyles}
      variant="copy"
      sx={{
        py: [4, 5],
        fontSize: [2, 3],
        h1: {
          textAlign: ['left', 'center'],
          color: 'cyan',
          my: 4,
          a: { color: 'inherit' }
        },
        'a[href^="#fn-"], a[href^="#fnref-"]': {
          textDecoration: 'none',
          color: 'inherit'
        }
      }}
    >
      {children}
    </Container>
  )
}


================================================
FILE: components/announcements/pills.tsx
================================================
import { Avatar, Badge, Flex } from 'theme-ui'

export function PillHolder({ children }) {
  return (
    <Flex
      sx={{
        flexWrap: 'wrap',
        justifyContent: 'center',
        alignItems: 'center',
        div: {
          mt: 0,
          mb: 2,
          color: 'muted',
          border: '1px solid',
          borderColor: 'border',
          bg: 'snow',
          fontSize: 2,
          fontWeight: 'body',
          lineHeight: '36px'
        }
      }}
    >
      {children}
    </Flex>
  )
}

export function AuthorPill({ tag, image, firstName }) {
  return (
    <Badge
      variant="pill"
      sx={{
        mr: [2, 3],
        pl: 2,
        pr: 3,
        display: 'inline-flex',
        alignItems: 'center'
      }}
    >
      <Avatar src={image} alt={firstName} size={36} mr={2} />
      {tag}
    </Badge>
  )
}

export function DatePill({ tag }) {
  return (
    <Badge variant="pill" px={3}>
      {tag}
    </Badge>
  )
}


================================================
FILE: components/announcements/preston-werner-2022.mdx
================================================
This gift means a lot to the Hack Club community, and we are grateful for Tom and Theresa’s continued support.

In 2014, Hack Club was founded, and Tom joined as Hack Club’s first board member. In the years since, he has contributed open source code, mentored Hack Clubbers 1:1, donated dozens of laptops to teenagers who didn't have access to computers, and been a constant advisor on the Hack Club community, strategy, and product.

Tom and Theresa also helped fund [The Hacker Zephyr](https://hack.af/zephyrdoc), an epic, cross-country train hackathon taken by 42 teen hackers in the summer of 2021. Tom even hacked alongside Hack Clubbers onboard.

With this gift, we will continue to build the engineering team at Hack Club, including a Tech Lead for [HCB](https://hackclub.com/fiscal-sponsorship), and new engineers to support clubs, the Hack Club online community, and events.

One of our goals in 2022 is to improve Hack Club and to support more teenagers in joining the community. Thank you Tom and Theresa for helping make this possible.

We thank Tom and Theresa for their generous gift and will carefully use each cent to advance our mission to create a new generation of young, highly-technical teen leaders capable of solving our world’s greatest problems. Every penny will be spent [transparently](https://hcb.hackclub.com/hq).

— Christina Asquith, COO, and Zach Latta, founder


================================================
FILE: components/announcements/preston-werner.mdx
================================================
import Amount from './amount'

# Today, we're proud to share: Tom and Theresa Preston-Werner are donating <Amount amount="$500,000" /> to&nbsp;[Hack&nbsp;Club](https://hackclub.com).

We are deeply grateful for this gift.

In the coming months, we hope you’ll share our excitement as we make 2 new hires directly serving Hack Clubbers. This gift increases Hack Club’s budget by 60%, and helps us build a diverse foundation at the leadership level of Hack Club as we grow.

We are so honored to be included among the many gifts the Preston-Werners make each year. This is the 3rd year the Preston-Werners have given a gift to Hack Club, and they've supported the organization from the beginning.

Tom and Theresa inspire Hack Club's values. They are self-made hackers, passionate about constructing a better world in creative ways. They are deeply committed to environmental protection, women’s rights, ending global poverty and injustice; and are tremendous collaborators in making Hack Club a place where all young people can build and create their own solutions through coding and technology, regardless of their background. They apply rigorous-thinking, curiosity, humility, transparency, and deep expertise in academia and coding to the problems that need solving in the world, and inspire us to do the same.

The Preston-Werners generously donate dozens of hours of their time each year to Hack Club HQ and Hack Clubbers. Theresa has been a steady champion of Hack Club, supporting us with feedback, advice, editing, and meeting with Hack Club students. Tom is a founding board member and a personal mentor of Zach’s for the last 5 years. Just some of the ways they support Hack Club is that they inspired the idea to launch Hack Club’s “Ask Me Anything” series, and Tom was our first speaker last April. In December 2019, they threw an amazing Christmas party at their San Francisco home for Hack Club.

Their incredible and generous gift ushers Hack Club into a big new year in which we get closer to our vision to build a new cultural institution for the 21st century akin to the Boy and Girl Scouts, in which we support high schoolers to gain critical computer science skills, healthy, fun and wholesome friendships, and a set of modern values that honor kindness, integrity, inclusivity, curiosity, optimism, and building and doing.

We send them a huge thank you. To every Hack Clubber: Tom and Theresa are now supporting you and your work, so go forth and do amazing things. We can’t wait to show them what you make.

—Christina Asquith, COO, and Zach Latta, founder


================================================
FILE: components/announcements/relon.mdx
================================================
import Signature from '../signature'
import Signatures from '../signatures'
import Image from 'theme-ui'

In March 2020, Elon Musk [spent an hour hanging out with Hack Clubbers](https://www.youtube.com/watch?v=riru9OzScwk). He [donated $500,000 to build our team](https://hackclub.com/elon/), [tweeted Hack Club was a cool group](https://twitter.com/elonmusk/status/1263275969743216640), and said that Hack Club makes him more optimistic about the future. This year, Hack Clubbers met SpaceX engineers and demoed projects on SpaceX's factory floor in Hawthorne, California.

This summer, Elon reached back out.

Today, we're excited to announce Elon is donating $1 million to Hack Club.

This gift will help launch a number of ideas we've been discussing, including helping more in-person hackathons get off the ground, providing more direct 1:1 technical support on the [Hack Club Slack](https://slack.hackclub.com), and starting up cool new projects like [The Hacker Zephyr](https://github.com/hackclub/the-hacker-zephyr). We also want to use his gift to help 1,000 more teenagers start and join Hack Clubs in their towns.

We will be spending every dollar as wisely as possible, growing thoughtfully, and adding diverse staff to make Hack Club better. We are pushing hard to try and make the Hack Club Slack the best place to be a teenager on the internet and expanding [HCB](https://hackclub.com/fiscal-sponsorship/).

Elon is very selective about the nonprofits he supports and we're proud Hack Club is one of them.

Hack Club will be fully transparent in how we spend this money. Hack Club HQ has been running on HCB since February 2020, and [you can see our finances publicly here](https://hcb.hackclub.com/hq).

Hack Club's mission is to help foster a new generation of hackers. This starts in high school, where Hack Clubbers learn to be technically proficient, build their friend network, learn to raise and spend money, and develop into kind, curious, thoughtful, optimistic, and honest leaders. And now Elon Musk is one of our largest supporters.

To every Hack Clubber: Elon continues to support you and your work, so go forth and do amazing things. We can't wait to share what you make.

<Signatures fileName="christina_and_zrl" width={320} />

Zach Latta, Founder & Executive Director  
Christina Asquith, COO


================================================
FILE: components/arcade/footer.tsx
================================================
import { Box, Heading, Text, Link } from 'theme-ui'
import Footer from '../footer'

const Description = () => (
  <Box sx={{ a: { color: '#FF5C00' }, pb: 4 }}>
    <Heading as="h3" variant="subheadline" mb={2}>
      A project by <a href="https://hackclub.com/">Hack Club</a>.
    </Heading>
    <Text as="p" variant="caption" mb={3} sx={{ width: ['85%', '75%', '60%'] }}>
      <Link href="/arcade/power-hour">Previous edition: Power Hour</Link>
    </Text>
    <Text as="p" variant="caption" mb={3} sx={{ width: ['85%', '75%', '60%'] }}>
      Hack Club is a registered 501(c)3 nonprofit organization that supports a
      network of 20k+ technical high schoolers. We believe you learn best by
      building so we're creating community and providing grants so you can make.
      In the past few years, we've{' '}
      <Link href="https://summer.hackclub.com" target="_blank">
        given away 100k+ in hardware grants
      </Link>
      ,{' '}
      <Link
        href="https://github.com/hackclub/the-hacker-zephyr"
        target="_blank"
      >
        hosted the world's longest hackathon on land
      </Link>
      , and{' '}
      <Link href="https://github.com/hackclub/assemble" target="_blank">
        brought 183 teenagers to SF for a hackathon
      </Link>
      .
    </Text>
  </Box>
)

const ArcadeFooter = () => {
  return (
    <Footer>
      <Description />
    </Footer>
  )
}

export default ArcadeFooter


================================================
FILE: components/arcade/projects.tsx
================================================
/** @jsxImportSource theme-ui */
import React, { useState } from 'react'
import styled from '@emotion/styled'
import {
  Box,
  Button,
  Container,
  Flex,
  Heading,
  Card,
  Grid,
  Text,
  Avatar
} from 'theme-ui'
import NextImage from 'next/image'
import Marquee from '../marquee'
import Photo1 from '../../public/winter/1.jpeg'
import Photo2 from '../../public/winter/2.png'
import Photo3 from '../../public/winter/3.jpeg'
import Photo4 from '../../public/winter/4.jpeg'
import Photo5 from '../../public/winter/5.jpeg'
import Photo6 from '../../public/winter/6.jpeg'
import Photo7 from '../../public/winter/7.jpeg'
import Photo8 from '../../public/winter/8.jpeg'
import Photo9 from '../../public/winter/9.jpeg'
import Photo10 from '../../public/winter/10.jpeg'
import Photo12 from '../../public/winter/12.jpeg'
import Photo13 from '../../public/winter/13.jpeg'
import Photo14 from '../../public/winter/14.jpeg'
import Photo15 from '../../public/winter/15.jpeg'
import Photo16 from '../../public/winter/16.jpeg'
import Photo17 from '../../public/winter/17.jpeg'
import Photo18 from '../../public/winter/18.jpeg'
import Photo19 from '../../public/winter/19.jpeg'
import Photo20 from '../../public/winter/20.jpeg'
import Photo21 from '../../public/winter/21.jpeg'

const Header = styled(Box)`
  background: url('/pattern.svg');
`

const PhotoRow = ({ photos }) => (
  <Box sx={{ height: '225px', overflow: 'hidden' }}>
    <Box sx={{ display: ['block', 'block', 'block', 'block', 'none'] }}>
      <Marquee velocity={12} onInit={() => {}} onFinish={() => {}}>
        {photos.map((photo, index) => (
          <NextImage
            placeholder="blur"
            src={photo}
            className="next-image"
            height="225px"
            width="300px"
            alt="Hack Club students"
            key={'image-' + index}
            style={{
              maxWidth: '100%',
              height: 'auto',
              objectFit: 'cover'
            }}
          />
        ))}
      </Marquee>
    </Box>
    <Box sx={{ display: ['none', 'none', 'none', 'none', 'block'] }}>
      <Marquee velocity={12} onInit={() => {}} onFinish={() => {}}>
        {photos.map((photo, index) => (
          <NextImage
            placeholder="blur"
            src={photo}
            className="next-image"
            height="200px"
            width="600px"
            key={'image-' + index}
            alt="Hack Club students"
            style={{
              maxWidth: '100%',
              height: 'auto',
              objectFit: 'cover'
            }}
          />
        ))}
      </Marquee>
    </Box>
  </Box>
)

const Cards = ({ avatar, username, description, image }) => {
  return (
    <Card
      className="post"
      sx={{ p: [3, 3], width: '100%', background: '#FAEFD6', color: '#5E3414' }}
    >
      <Flex
        as="a"
        href={
          username !== 'cjmika110'
            ? `https://scrapbook.hackclub.com/${username}`
            : 'https://scrapbook.hackclub.com'
        }
        sx={{
          color: 'inherit',
          textDecoration: 'none',
          alignItems: 'center',
          mb: 2
        }}
      >
        <Avatar loading="lazy" src={avatar} alt="" mr={2} />
        <Box>
          <Text variant="subheadline" my={0} fontSize={[1, 1]}>
            @{username}
          </Text>
        </Box>
      </Flex>
      <Text
        as="p"
        sx={{
          fontSize: 1,
          textAlign: 'left',
          mb: 2,
          a: {
            color: 'primary',
            wordBreak: 'break-all',
            wordWrap: 'break-word'
          },
          '> div': { width: 18, height: 18 }
        }}
      >
        {description}
      </Text>
      <Box
        sx={{
          position: 'relative',
          width: '100%',
          height: '160px',
          overflow: 'hidden',
          backgroundImage: `url('${image}')`,
          backgroundSize: '100%',
          backgroundPosition: 'bottom center',
          backgroundRepeat: 'no-repeat'
        }}
      >
        {/* <img src={image} sx={{ width: '100%' }} /> */}
      </Box>
    </Card>
  )
}

export default function Projects() {
  const [count, setCount] = useState(0)

  const list = [
    'Drawing robot',
    '3D printer',
    'DIY Electric Skateboard',
    'Pixel art display',
    'Smart Garden',
    'CNC machine',
    'Interactive LED Art',
    'VR Escape Room',
    'Image Recognition App',
    'DIY Camera',
    'Multiplayer AR Game',
    'Drone Swarm Choreography'
  ]

  if (count === list.length - 1) {
    setCount(0)
  }

  const project_idea = list[count]

  return (
    <Box>
      <Header sx={{ position: 'relative' }}>
        <Box
          sx={{
            background: [
              '#D0BF97 url(/arcade/white_bg.svg) no-repeat center center',
              '#D0BF97 url(/arcade/white_bg.svg) no-repeat center center',
              'rgba(0,0,0, 0.8)',
              'rgba(0,0,0, 0.8)'
            ],
            backgroundSize: 'cover',
            zIndex: 1,
            position: 'relative',
            color: 'white!important',
            height: ['auto', 'auto', '900px', '900px']
          }}
          pt={[5, 5, 5, '50px']}
          pb={[5, 5, 0, 0]}
        >
          <Box
            sx={{
              maxWidth: '64rem',
              mx: 'auto',
              zIndex: 1,
              position: 'relative'
            }}
            align="center"
            py={2}
            px={[1, 3]}
          >
            <Container sx={{ maxWidth: '48rem' }}>
              <Heading
                variant="headline"
                sx={{
                  textShadow: '0px 0px 21px #FAEFD6',
                  color: '#FAEFD6',
                  display: 'flex',
                  flexDirection: 'column',
                  alignItems: 'center',
                  gap: 1,
                  fontSize: [2, 4, 5]
                }}
              >
                <Text>You could be building a</Text>
                <Text
                  sx={{
                    backgroundColor: '#FF5C00',
                    py: 2,
                    px: 3,
                    borderRadius: 10,
                    position: 'relative',
                    width: 'fit-content',
                    height: 'min-content',
                    cursor: 'pointer',
                    userSelect: 'none',
                    color: '#FAEFD6'
                  }}
                  onClick={() => setCount(count + 1)}
                >
                  <Box as="span" sx={{ whiteSpace: 'nowrap' }}>
                    {project_idea}
                  </Box>
                </Text>
              </Heading>
              <Grid
                columns={[1, 1, 3, 3]}
                mt={4}
                mx={['5vw', '5vw', 'auto', 'auto']}
              >
                <Cards
                  avatar="https://scrapbook.hackclub.com/_next/image?url=https%3A%2F%2Favatars.slack-edge.com%2F2024-05-06%2F7077145829972_8597fe575e09a698859c_192.png&w=48&q=75"
                  username="elijah"
                  description="Finally shipped my personal ai clone and had a ton of fun playing around with it and seeing what other people did with it! Personal favorite was when it threatened to kill me and got very unhinged when the person threatened to send screenshots to me"
                  image="https://scrapbook-into-the-redwoods.s3.amazonaws.com/4d4ecc40-c388-4b9d-997f-1f3d6a21302c-image.png"
                />
                <Cards
                  avatar="https://scrapbook.hackclub.com/_next/image?url=https%3A%2F%2Favatars.slack-edge.com%2F2023-04-15%2F5116546887938_afb907f96fa13e434a49_192.png&w=48&q=75"
                  username="cupcakes"
                  description="Assembling blot robot! 🪛"
                  image="https://scrapbook-into-the-redwoods.s3.amazonaws.com/e75cf24a-46d9-45fa-92d3-b9e5862d0d47-img_2442.jpg"
                />
                <Cards
                  avatar="https://scrapbook.hackclub.com/_next/image?url=https://secure.gravatar.com/avatar/c2e358d7bf4677cac086556035ce1dbc.jpg?s%3D192%26d%3Dhttps%253A%252F%252Fa.slack-edge.com%252Fdf10d%252Fimg%252Favatars%252Fava_0011-192.png&w=640&q=75"
                  username="KonstantinosFragkoulis"
                  description="Well, the drone now should be able to follow the biggest object that it sees with a specific color. I haven't tested it yet though 😞 (I'm too scared to crash it). Here is a clip from earlier today, my genuine reaction to the first takeoff ever (got a bit scared at the end) 👍 "
                  image="https://cloud-fshng6w8x-hack-club-bot.vercel.app/0videoframe_809.png"
                />
              </Grid>
              <Button
                as="a"
                variant="cta"
                href="https://scrapbook.hackclub.com/"
                sx={{
                  background:
                    'linear-gradient(32deg, rgba(51, 142, 218, 0.9) 0%, rgba(51, 214, 166, 0.9) 100%)',
                  mt: 4
                }}
              >
                See more projects →
              </Button>
            </Container>
          </Box>
        </Box>
        <Box
          sx={{
            position: 'absolute',
            top: 0,
            zIndex: 0,
            width: '100%',
            display: ['none', 'none', 'block', 'block']
          }}
        >
          <PhotoRow photos={[Photo1, Photo2, Photo3, Photo4, Photo5]} />
          <PhotoRow photos={[Photo6, Photo7, Photo8, Photo9, Photo10]} />
          <PhotoRow photos={[Photo21, Photo12, Photo13, Photo14, Photo15]} />
          <PhotoRow photos={[Photo16, Photo17, Photo18, Photo19, Photo20]} />
        </Box>
      </Header>
    </Box>
  )
}


================================================
FILE: components/background-image.tsx
================================================
import { Box } from 'theme-ui'
import Image, { StaticImageData } from 'next/image'

/*
 * Use this component inside a container with CSS:
 * `position: relative; overflow: hidden;`
 * then pass width/height/alt/src as usual
 * (you can pass `gradient` valueless to avoid gradient)
 */

type BGImgProps = {
  gradient?: string | boolean
  alt?: string
  src: string | StaticImageData
  placeholder?: 'blur' | 'empty'
}

export default function BGImg({
  gradient = 'linear-gradient(rgba(0,0,0,0.25), rgba(0,0,0,0.5))',
  alt = '',
  ...props
}: BGImgProps) {
  return (
    <Box
      sx={{
        position: 'absolute',
        display: 'block',
        top: 0,
        left: 0,
        right: 0,
        bottom: 0,
        zIndex: 0,
        '&:after': {
          content: '""',
          position: 'absolute',
          ...(typeof gradient === 'string'
            ? { backgroundImage: gradient }
            : {}),
          top: 0,
          left: 0,
          right: 0,
          bottom: 0
        },
        img: { objectFit: 'cover', objectPosition: 'center center' },
        '~ *': { position: 'relative' }
      }}
    >
      <Image fill alt={alt} {...props} />
    </Box>
  )
}


================================================
FILE: components/bin/GalleryPosts.tsx
================================================
/** @jsxImportSource theme-ui */
import Image from 'next/image'
import styles from '../../public/bin/style/gallery.module.css'
import PartTag from './PartTag'

type BinPostProps = {
  title: string
  desc: string
  slack: string
  link: string
  id: string
  date: string
  parts?: string[]
}

const BinPost = ({
  title = 'Bin Post',
  desc = 'Bin Project',
  slack = '',
  link = '',
  id,
  date,
  parts
}: BinPostProps) => {
  link = link.trim()
  if (!/^https?:\/\//i.test(link)) {
    link = 'https://' + link
  }
  const projectID = link.split('/')[4]
  const imgLink = `https://thumbs.wokwi.com/projects/${projectID}/social/bin.png`

  function handleClick() {
    if (typeof window !== 'undefined') {
      window.open(link, '_blank')
    }
  }

  function formatDate(dateString) {
    const inputDate = new Date(dateString)
    const now = new Date()
    const oneDay = 24 * 60 * 60 * 1000 // Number of milliseconds in one day

    // Check if the input date is within the last 24 hours
    if (now.getTime() - inputDate.getTime() < oneDay) {
      const hours = inputDate.getHours().toString().padStart(2, '0')
      const minutes = inputDate.getMinutes().toString().padStart(2, '0')
      return `Today at ${hours}:${minutes}`
    } else {
      // Format the date to "Month day, year"
      const options = {
        year: 'numeric',
        month: 'long',
        day: 'numeric'
      } as const
      return inputDate.toLocaleDateString(undefined, options)
    }
  }
  if (parts) {
    parts = parts.filter(
      part => part !== 'recvK14pXAY1tn3HQ' && part !== 'rec5TQNvkGkscsGuQ'
    ) //Filter out breadboards and raspberry pi
  }

  return (
    <div alt={id} className={styles.gallery_card} onClick={handleClick}>
      <h1 className={styles.card_title}>
        {title}
        <br />
      </h1>

      <div className={styles.img_container}>
        <Image src={imgLink} alt="Project Image" width={1200} height={628} />
      </div>

      <p className={styles.card_desc}>{desc}</p>
      <span className={styles.slack}>
        {(slack ? (slack.startsWith('@') ? slack : `@${slack}`) : '') + ' '}
      </span>
      <span className={styles.date}>{formatDate(date)}</span>
      <div className={styles.tag_container}>
        {parts &&
          parts.map(part => {
            return <PartTag key={part} partID={part} />
          })}
      </div>
    </div>
  )
}

export default BinPost


================================================
FILE: components/bin/PartTag.module.css
================================================
.tag {
  color: e1e1e1;
  padding: 4px 10px;
  border-radius: 20px;
  width: fit-content;
  max-width: 300px;
  display: flex;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: transform 0.3s ease;
  box-sizing: border-box;
}

.tag:hover {
  cursor: pointer;
  transform: scale(1.1);
}

.outlined {
  border: 5px dotted #c5c5c5;
}


================================================
FILE: components/bin/PartTag.tsx
================================================
import React from 'react'
import styles from './PartTag.module.css'
import { useState } from 'react'

const PartTag = ({ partID, search = false, addFilter, removeFilter }) => {
  const [isOutlined, setIsOutlined] = useState(false)

  const handleClick = () => {
    if (search) {
      setIsOutlined(prevState => !prevState)
      if (isOutlined) {
        removeFilter(partID)
      } else {
        addFilter(partID)
      }
    }
  }

  let backgroundColor: string
  let text: string
  switch (partID) {
    case 'recltWikgPdLvpJfe':
      backgroundColor = '#0000FF' // Vibrant blue
      text = 'Servo'
      break
    case 'recRzllr0dui91NLd':
      backgroundColor = '#008000' // Vibrant green
      text = 'LED'
      break
    case 'recM7OOofV9Bp7AM9':
      backgroundColor = '#FF0000' // Vibrant red
      text = 'ESP32'
      break
    case 'recALoD1CCKt3CxKE':
      backgroundColor = '#800080' // Vibrant purple
      text = 'Buzzer'
      break
    case 'rechtwyljZ5WR8DtR':
      backgroundColor = '#FF4500' // Vibrant orange
      text = 'Slider'
      break
    case 'recry1GsMO6QLakzw':
      backgroundColor = '#8B4513' // Dark brown
      text = 'Photoresistor'
      break
    case 'recjRu1vTAU3qDanE':
      backgroundColor = '#FF1493' // Vibrant pink
      text = 'LCD'
      break
    case 'recrgS7NnxS42tkmg':
      backgroundColor = '#A52A2A' // Vibrant brown
      text = 'LED Screen'
      break
    case 'recocuypi4xP0UgAj':
      backgroundColor = '#000000' // Black
      text = 'Joystick'
      break
    case 'recgLUxtFZHufN70W':
      backgroundColor = '#1E90FF' // Dodger blue
      text = 'LED Bar Graph'
      break
    case 'recKBAnftT9PgppUC':
      backgroundColor = '#00FFFF' // Vibrant cyan
      text = 'Shift Register'
      break
    case 'recibIXNCSdhDHjXD':
      backgroundColor = '#FF00FF' // Vibrant magenta
      text = 'Thermistor'
      break
    case 'recwSKHd3anpKqNbg':
      backgroundColor = '#00FF00' // Vibrant lime
      text = 'IR Receiver'
      break
    case 'recLRovQNumB1Et8B':
      backgroundColor = '#008080' // Vibrant teal
      text = 'Range Finder'
      break
    case 'recMVBkeJ4KQdZihl':
      backgroundColor = '#808000' // Vibrant olive
      text = 'Keypad'
      break
    case 'recGrj5GpSExI18Ff':
      backgroundColor = '#000080' // Vibrant navy
      text = 'Humidity'
      break
    case 'rec9G0CAXM0kdp7HY':
      backgroundColor = '#800000' // Vibrant maroon
      text = 'RTC'
      break
    case 'rec4vTiJIx4UP8Thl':
      backgroundColor = '#DAA520' // Goldenrod
      text = 'Motion Sensor'
      break
    case 'reczWN9rZOY95VXOT':
      backgroundColor = '#FF8C00' // Dark orange
      text = 'LED Matrix'
      break
    case 'recNjAmh8gF0gZNtI':
      backgroundColor = '#FF6347' // Tomato red
      text = 'Accelerometer'
      break
    case 'recPmyV5b8cvaMtTk':
      backgroundColor = '#4B0082' // Vibrant indigo
      text = 'Neopixel LED'
      break
    case 'recj5b4DKez4GNa8i':
      backgroundColor = '#87CEEB' // Vibrant sky blue
      text = 'Relay'
      break
    case 'rec5TQNvkGkscsGuQ':
      backgroundColor = '#9932CC' // Vibrant orchid
      text = 'Pico W'
      break
    case 'recqffGd1j1jRh56m':
      backgroundColor = '#DDA0DD' // Vibrant plum
      text = 'Multicolor LED'
      break
    case 'recJUolkJURydamzG':
      backgroundColor = '#CD5C5C' // Vibrant light coral
      text = 'Encoder'
      break
    case 'rec7lggt0DsgrWHzc':
      backgroundColor = '#20B2AA' // Vibrant light sea green
      text = 'Temp Sensor'
      break
    case 'rectVgu4kWbbaqccc':
      backgroundColor = '#FFA07A' // Vibrant light salmon
      text = 'Button'
      break
    case 'recWKEXSaByRvl68t':
      backgroundColor = '#4682B4' // Vibrant light steel blue
      text = '4 Digit Display'
      break
    default:
      backgroundColor = 'gray' // Default gray
      text = 'Invalid Tag'
      console.log('invalid', partID)
  }

  return (
    <div
      style={{ backgroundColor }}
      className={styles.tag + (isOutlined ? ` ${styles.outlined}` : '')}
      onClick={handleClick}
    >
      {text}
    </div>
  )
}

export default PartTag


================================================
FILE: components/bin/nav.tsx
================================================
import React from 'react'
import styles from '../../public/bin/style/gallery.module.css'

const Nav = () => {
  return (
    <div className={styles.nav}>
      <button
        className={styles.nav_button}
        onClick={() => (window.location.href = '/bin')}
      >
        Bin Home
      </button>
      <button
        className={styles.nav_button}
        onClick={() => (window.location.href = '/bin/gallery')}
      >
        Gallery
      </button>
    </div>
  )
}

export default Nav


================================================
FILE: components/bin/rsvp-form.tsx
================================================
/** @jsxImportSource theme-ui */

import { Checkbox, Input, Label, Text, Box } from 'theme-ui'
import useForm from '../../lib/use-form'
import Submit from '../submit'
import { Slide } from '../react-reveal-compat'

export default function RsvpForm() {
  const { status, formProps, useField } = useForm('/api/bin/rsvp', null, {
    clearOnSubmit: 5000,
    method: 'POST',
    initData: {},
    bearer: null
  })

  return (
    <>
      <form {...formProps}>
        <Label>
          <Text>Email</Text>
          <Input
            {...useField('email')}
            placeholder="fiona@hackclub.com"
            required
            sx={{ border: '1px solid', borderColor: 'muted', mb: 2 }}
          />
        </Label>
        <Label variant="labelHoriz" sx={{ fontSize: 1, pt: 2 }}>
          <Checkbox
            {...useField('high_schooler', 'checkbox')}
            defaultChecked={false}
          />
          I am a current high school student or younger.
        </Label>
        <Label variant="labelHoriz" sx={{ fontSize: 1, pt: 2 }}>
          <Checkbox {...useField('stickers', 'checkbox')} />I want a sticker
          sheet.
        </Label>
        <Box
          sx={{
            display: (useField('stickers', 'checkbox') as any).checked
              ? 'block'
              : 'none'
          }}
        >
          <Slide left delay={20}>
            <Label mt={2}>
              Address (line 1)
              <Input
                {...useField('address_line_1')}
                placeholder="1 Hacker Way"
                sx={{ border: '1px solid', borderColor: 'muted' }}
              />
            </Label>
            <Label mt={2}>
              Address (zip code)
              <Input
                {...useField('address_zip')}
                placeholder="01337"
                sx={{ border: '1px solid', borderColor: 'muted' }}
              />
            </Label>
          </Slide>
        </Box>
        <Submit
          status={status}
          labels={{
            default: 'Submit',
            error: 'Something went wrong',
            success: 'Success!'
          }}
        />
      </form>
    </>
  )
}


================================================
FILE: components/bio.tsx
================================================
/** @jsxImportSource theme-ui */
import Icon from '@hackclub/icons'
import { useState } from 'react'
import { Box, Card, Flex, Text } from 'theme-ui'

export default function Bio({ popup = true, spanTwo = false, ...props }) {
  const { name, teamRole, pronouns, text, subrole, email, href, video, img } =
    props
  const [expand, setExpand] = useState(false)
  return (
    <>
      <Card
        bg="snow"
        p={popup ? [2, 2, 2] : [3, 3, 3]}
        py={popup ? [3, 3, 3] : [4, 4, 4]}
        sx={{
          display: 'flex',
          alignItems: popup ? 'center' : 'flex-start',
          transition: 'transform 0.125s ease-in-out',
          '&:hover': { transform: 'scale(1.025)' },
          cursor: (text && popup) || href ? 'pointer' : null,
          textDecoration: 'none',
          maxWidth: '600px',
          zIndex: !popup ? 1003 : 5,
          maxHeight: '90vh',
          overflowY: 'hidden',
          overscrollBehavior: 'auto',
          gridColumn: !spanTwo ? null : [null, null, '1 / span 2'],
          position: 'relative'
        }}
        as={href && !text ? 'a' : 'div'}
        href={href}
        target="_blank"
        onClick={() => {
          if (text && popup) {
            setExpand(true)
          }
        }}
      >
        {img && (
          <Box
            as="img"
            src={img}
            alt={name}
            sx={{
              width: 96,
              height: 96,
              minWidth: 96,
              borderRadius: '50%',
              objectFit: 'cover',
              mr: 3
            }}
          />
        )}
        <Box>
          <Text sx={{ fontSize: [3, 3, 3] }} variant="headline" color="black">
            {name}
          </Text>
          <Flex>
            <Text>
              <Text
                color="#24B5A5"
                variant="subheadline"
                fontSize={2}
                sx={{
                  mb: ['0px', '0px', '0px'],
                  fontSize: '1.1em',
                  width: 'fit-content'
                }}
              >
                {teamRole}
              </Text>
              {subrole && (
                <>
                  <br />
                  <Text
                    color="#24B5A5"
                    sx={{
                      mb: ['0px', '0px', '0px'],
                      fontSize: 1,
                      fontWeight: 400,
                      width: 'fit-content'
                    }}
                  >
                    {subrole}
                  </Text>
                </>
              )}
              {pronouns && (
                <Text fontSize={1} ml={1} color="muted" align="center">
                  ({pronouns})
                </Text>
              )}
            </Text>
          </Flex>
          {!popup &&
            email &&
            (email.includes('@') ? (
              <Text color="muted" as={'a'} href={`mailto:${email}`}>
                {email}
                <br />
              </Text>
            ) : (
              <Text
                color="muted"
                as={'a'}
                href={`mailto:${email}@hackclub.com`}
              >
                {email}@hackclub.com
                <br />
              </Text>
            ))}

          {!popup && (
            <>
              <Text mt={2} mb={0} color="black">
                {text}
              </Text>
              {video && (
                <Flex
                  sx={{
                    marginTop: 4,
                    marginX: 5,
                    justifyContent: 'center',
                    aspectRatio: 4 / 3
                  }}
                >
                  <iframe
                    width="100%"
                    src={video}
                    title="YouTube video player"
                    frameBorder="0"
                    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
                    allowfullscreen
                  />
                </Flex>
              )}
            </>
          )}
          {!popup && href && (
            <Flex sx={{ alignItems: 'center' }}>
              <Text
                sx={{
                  transform: 'translateX(-4px) translateY(2px)',
                  display: 'inline-flex',
                  alignItems: 'center'
                }}
              >
                <Icon glyph="external-fill" size={24} />
              </Text>
              <Text
                mt={1}
                mb={0}
                color="black"
                as={'a'}
                target="_blank"
                href={href}
                sx={{ transform: 'translateX(-2px)' }}
              >
                {href}
              </Text>
            </Flex>
          )}
        </Box>
      </Card>
      {popup && expand && (
        <Flex
          sx={{
            position: 'fixed',
            zIndex: 1004,
            top: 0,
            left: 0,
            height: '100vh',
            width: '100vw',
            alignItems: 'center',
            justifyContent: 'center',
            background: 'rgba(0,0,0,0.6)',
            pb: 4
          }}
        >
          <Bio {...props} popup={false} />
          <Flex
            sx={{
              position: 'fixed',
              zIndex: 1002,
              top: 0,
              left: 0,
              height: '100vh',
              width: '100vw',
              alignItems: 'center',
              justifyContent: 'center',
              pb: 4
            }}
            onClick={() => setExpand(false)}
          />
        </Flex>
      )}
    </>
  )
}


================================================
FILE: components/boardbio.tsx
================================================
/** @jsxImportSource theme-ui */
import Icon from '@hackclub/icons'
import { useState } from 'react'
import { Avatar, Box, Card, Flex, Text } from 'theme-ui'

export default function BoardBox({ popup = true, ...props }) {
  const { img, name, teamRole, pronouns, text, subrole, email, href, video } =
    props
  const [expand, setExpand] = useState(false)

  return (
    <>
      <Card
        bg="#d9f7ed"
        sx={{
          display: 'flex',
          flexDirection: popup ? 'column' : 'row',
          alignItems: popup ? 'center' : 'flex-start',
          justifyContent: popup ? 'center' : 'flex-start',
          transition: 'transform 0.125s ease-in-out',
          '&:hover': { transform: 'scale(1.025)' },
          cursor: (text && popup) || href ? 'pointer' : null,
          textDecoration: 'none',
          maxWidth: popup ? 'auto' : '600px',
          zIndex: !popup ? 1003 : 5,
          maxHeight: popup ? 'auto' : '90vh',
          overflowY: 'hidden',
          position: 'relative'
        }}
        as={href && !text ? 'a' : 'div'}
        href={href}
        target="_blank"
        onClick={() => {
          if (text && popup) {
            setExpand(true)
          }
        }}
      >
        {popup ? (
          <>
            <Text
              variant="headline"
              sx={{
                fontSize: subrole ? 3 : 4,
                textAlign: 'center',
                mb: subrole ? 0 : 1,
                mt: subrole ? -3 : -2
              }}
              color="black"
            >
              {name}
            </Text>
            <Text
              color="#24B5A5"
              variant="subheadline"
              sx={{
                fontSize: subrole ? 1 : 3,
                textAlign: 'center',
                mb: subrole ? 0 : 2
              }}
            >
              {teamRole}
            </Text>
            {subrole && (
              <Text
                color="#24B5A5"
                sx={{
                  fontSize: 1,
                  textAlign: 'center',
                  mb: 2,
                  fontWeight: 400
                }}
              >
                {subrole}
              </Text>
            )}
            <Box
              as="img"
              src={img}
              alt={name}
              sx={{
                width: '120px',
                height: '120px',
                borderRadius: '50%',
                objectFit: 'cover',
                mb: subrole ? -3 : -2
              }}
            />
          </>
        ) : (
          <>
            <Avatar
              size={64}
              width={64}
              height={64}
              mr={3}
              src={img}
              alt={name}
              sx={{
                overflow: 'hidden',
                objectFit: 'cover',
                transition: 'transform 0.125s ease-in-out',
                '&:hover': { transform: 'rotate(-8deg) scale(1.25)' },
                flexShrink: 0,
                width: '64px',
                height: '64px'
              }}
            />
            <Box>
              <Text
                sx={{ fontSize: [3, 3, 3] }}
                variant="headline"
                color="black"
              >
                {name}
              </Text>
              <Flex>
                <Text>
                  <Text
                    color="#24B5A5"
                    variant="subheadline"
                    fontSize={2}
                    sx={{
                      mb: ['0px', '0px', '0px'],
                      fontSize: '1.1em',
                      width: 'fit-content'
                    }}
                  >
                    {teamRole}
                  </Text>
                  {subrole && (
                    <>
                      <br />
                      <Text
                        color="#24B5A5"
                        sx={{
                          mb: ['0px', '0px', '0px'],
                          fontSize: 1,
                          fontWeight: 400,
                          width: 'fit-content'
                        }}
                      >
                        {subrole}
                      </Text>
                    </>
                  )}
                  {pronouns && (
                    <Text fontSize={1} ml={1} color="muted" align="center">
                      ({pronouns})
                    </Text>
                  )}
                </Text>
              </Flex>
              {email &&
                (email.includes('@') ? (
                  <Text color="muted" as={'a'} href={`mailto:${email}`}>
                    {email}
                    <br />
                  </Text>
                ) : (
                  <Text
                    color="muted"
                    as={'a'}
                    href={`mailto:${email}@hackclub.com`}
                  >
                    {email}@hackclub.com
                    <br />
                  </Text>
                ))}
              <Text mt={2} mb={0} color="black">
                {text}
              </Text>
              {video && (
                <Flex
                  sx={{
                    marginTop: 4,
                    marginX: 5,
                    justifyContent: 'center',
                    aspectRatio: 4 / 3
                  }}
                >
                  <iframe
                    width="100%"
                    src={video}
                    title="YouTube video player"
                    frameBorder="0"
                    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
                    allowFullScreen
                  />
                </Flex>
              )}
              {href && (
                <Flex sx={{ alignItems: 'center' }}>
                  <Text
                    sx={{
                      transform: 'translateX(-4px) translateY(2px)',
                      display: 'inline-flex',
                      alignItems: 'center'
                    }}
                  >
                    <Icon glyph="external-fill" size={24} />
                  </Text>
                  <Text
                    mt={1}
                    mb={0}
                    color="black"
                    as={'a'}
                    target="_blank"
                    href={href}
                    sx={{ transform: 'translateX(-2px)' }}
                  >
                    {href}
                  </Text>
                </Flex>
              )}
            </Box>
          </>
        )}
      </Card>
      {popup && expand && (
        <Flex
          sx={{
            position: 'fixed',
            zIndex: 1004,
            top: 0,
            left: 0,
            height: '100vh',
            width: '100vw',
            alignItems: 'center',
            justifyContent: 'center',
            background: 'rgba(0,0,0,0.6)',
            pb: 4
          }}
        >
          <BoardBox {...props} popup={false} />
          <Flex
            sx={{
              position: 'fixed',
              zIndex: 1002,
              top: 0,
              left: 0,
              height: '100vh',
              width: '100vw',
              alignItems: 'center',
              justifyContent: 'center',
              pb: 4
            }}
            onClick={() => setExpand(false)}
          />
        </Flex>
      )}
    </>
  )
}


================================================
FILE: components/color-switcher.tsx
================================================
import { IconButton, useColorMode } from 'theme-ui'

const ColorSwitcher = props => {
  const [mode, setMode] = useColorMode()
  return (
    <IconButton
      onClick={() => setMode(mode === 'dark' ? 'light' : 'dark')}
      title={`Switch to ${mode === 'dark' ? 'light' : 'dark'} mode`}
      sx={{
        position: 'absolute',
        top: [2, 3],
        right: [2, 3],
        color: 'primary',
        cursor: 'pointer',
        borderRadius: 'circle',
        transition: 'box-shadow .125s ease-in-out',
        ':hover,:focus': {
          boxShadow: '0 0 0 3px',
          outline: 'none'
        }
      }}
      {...props}
    >
      <svg viewBox="0 0 32 32" width={24} height={24} fill="currentcolor">
        <circle
          cx={16}
          cy={16}
          r={14}
          fill="none"
          stroke="currentcolor"
          strokeWidth={4}
        />
        <path d="M 16 0 A 16 16 0 0 0 16 32 z" />
      </svg>
    </IconButton>
  )
}

export default ColorSwitcher


================================================
FILE: components/comma.ts
================================================
export default function Comma({ children }) {
  return children
    ? children.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
    : ''
}


================================================
FILE: components/directoryModal.tsx
================================================
/** @jsxImportSource theme-ui */

export const badges = [
  {
    label: 'Transparent',
    id: 'Transparent',
    tooltip: 'Transparent',
    color: 'purple',
    icon: 'explore',
    match: org => org.isTransparent
  }
]

export function getBadgesForOrg(org: { [key: string]: any }): typeof badges {
  return badges.filter(badge => badge.match?.(org))
}

import { Badge as ThemeBadge, Box, Flex } from 'theme-ui'
import { Text, Button, Card } from 'theme-ui'
import Icon from '@hackclub/icons'
import Image from 'next/image'

type OrganizationModalProps = {
  organization: {
    name: string
    location: {
      country: string
    }
    branding: {
      backgroundImage: string
      logo?: string
      description?: string
    }
    links: {
      website?: string
      financials?: string
      donations: string
    }
    raw: {
      transparent?: boolean
    }
  }
  onClose: () => void
}
export function OrganizationModal({
  organization,
  onClose
}: OrganizationModalProps) {
  return (
    <Box
      sx={{
        position: 'fixed',
        top: '0px',
        left: '0px',
        right: '0px',
        bottom: '0px',
        zIndex: 1000,
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        bg: '#00000044'
      }}
      onClick={onClose}
    >
      <Card
        sx={{
          width: 'min(640px, 90%)',
          bg: 'elevated',
          borderRadius: '10px',
          position: 'relative',
          display: 'flex',
          boxSizing: 'border-box',
          flexDirection: 'column',
          maxHeight: '90vh',
          overflowY: 'scroll'
        }}
        onClick={e => {
          e.stopPropagation()
        }}
      >
        <Flex
          sx={{
            position: 'absolute',
            top: '10px',
            right: '10px',
            width: '40px',
            height: '40px',
            bg: 'smoke',
            borderRadius: '50%',
            justifyContent: 'center',
            alignItems: 'center',
            cursor: 'pointer'
          }}
        >
          <Icon glyph="view-close" size={32} onClick={onClose} />
        </Flex>
        <Flex
          sx={{
            flexDirection: 'column',
            alignItems: 'stretch',
            gap: 3
          }}
        >
          <Flex
            sx={{
              flexDirection: 'column',
              justifyContent: 'end',
              minHeight: '200px',
              m: -4,
              p: '24px',
              boxSizing: 'content-box',
              backgroundPosition: 'center center',
              color: 'white',
              backgroundRepeat: 'no-repeat',
              backgroundSize: 'cover',
              backgroundImage: `url('${organization.branding.backgroundImage}')`
            }}
          >
            <Flex
              sx={{
                flexDirection: ['column', 'row', 'row'],
                alignItems: 'center',
                justifyContent: 'start',
                gap: '24px'
              }}
            >
              {organization.branding.logo && (
                <Image
                  alt={`${organization.name}'s logo`}
                  src={organization.branding.logo}
                  width={128}
                  height={128}
                  sx={{
                    width: 'auto',
                    height: '96px',
                    borderRadius: '8px'
                  }}
                />
              )}
              <Flex
                sx={{
                  flexDirection: 'column'
                }}
              >
                <Text
                  variant="title"
                  sx={{
                    wordBreak: 'break-word',
                    marginBottom: '12px',
                    textAlign: ['center', 'left', 'left'],
                    fontSize: ['36px', '36px', '36px'],
                    color: 'white',
                    textShadow: '0px 10px 10px rgba(0, 0, 0, 0.25)'
                  }}
                >
                  {organization.name}
                </Text>
                <Text
                  variant="subheadline"
                  sx={{
                    whiteSpace: 'nowrap',
                    textAlign: ['center', 'left', 'left'],
                    color: 'white',
                    textShadow: '0px 10px 10px rgba(0, 0, 0, 0.25)',
                    marginBottom: '0px'
                  }}
                >
                  {organization.location.country}
                </Text>
              </Flex>
            </Flex>
          </Flex>

          {/* Badges */}
          <Flex
            sx={{
              flexDirection: 'row',
              justifyContent: ['center', 'start', 'start'],
              alignItems: 'center',
              gap: 2,
              width: '100%',
              mt: '40px',
              mb: -2,
              flexWrap: 'wrap'
            }}
          >
            {/* hardcoded "nonprofit" badge */}
            <ThemeBadge
              as="span"
              aria-label="Nonprofit"
              sx={{
                bg: 'blue',
                color: 'snow',
                fontSize: '20px',
                textShadow: 'none',
                borderRadius: '15px',
                px: 2,
                display: 'block'
              }}
            >
              Nonprofit
            </ThemeBadge>

            {organization.raw.transparent && (
              <ThemeBadge
                as="span"
                aria-label="Transparent"
                sx={{
                  bg: 'purple',
                  color: 'snow',
                  fontSize: '20px',
                  textShadow: 'none',
                  borderRadius: '15px',
                  px: 2,
                  display: 'block'
                }}
              >
                Transparent
              </ThemeBadge>
            )}
          </Flex>

          <Flex
            sx={{
              flexDirection: 'row',
              alignItems: 'start',
              gap: 4,
              width: '100%'
            }}
          >
            {/* info & buttons */}
            <Flex
              sx={{
                flexDirection: 'column',
                alignItems: 'start',
                flex: '1'
              }}
            >
              {organization.branding.description && (
                <Text variant="lead" style={{ fontSize: '22px' }}>
                  {organization.branding.description}
                </Text>
              )}

              <Flex
                sx={{
                  flexDirection: 'column',
                  alignItems: 'start',
                  my: 2,
                  ml: -1,
                  gap: 1
                }}
              >
                {organization.links.website && (
                  <Flex
                    as="a"
                    target="_blank"
                    href={organization.links.website}
                    sx={{
                      flexDirection: 'row',
                      justifyContent: 'start',
                      alignItems: 'center',
                      color: 'slate',
                      textDecoration: 'none'
                    }}
                  >
                    <Icon glyph="web" size={38} />
                    <Text style={{ fontSize: '20px', marginLeft: '6px' }}>
                      Website
                    </Text>
                    <Icon
                      glyph="external"
                      size={20}
                      style={{ marginLeft: '2px', marginBottom: '6px' }}
                    />
                  </Flex>
                )}
                {organization.links.financials && (
                  <Flex
                    as="a"
                    target="_blank"
                    href={organization.links.financials}
                    sx={{
                      flexDirection: 'row',
                      justifyContent: 'start',
                      alignItems: 'center',
                      color: 'slate',
                      textDecoration: 'none'
                    }}
                  >
                    <Icon glyph="explore" size={38} />
                    <Text style={{ fontSize: '20px', marginLeft: '6px' }}>
                      Transparent Finances
                    </Text>
                    <Icon
                      glyph="external"
                      size={20}
                      style={{ marginLeft: '2px', marginBottom: '6px' }}
                    />
                  </Flex>
                )}
              </Flex>
            </Flex>
          </Flex>

          <Flex
            sx={{
              flexDirection: 'row',
              width: '100%',
              justifyContent: 'space-between',
              alignItems: 'center'
            }}
          >
            <Text sx={{ display: ['none', 'none', 'block'] }}>
              All donations are tax-deductible.
            </Text>

            <Button
              as="a"
              variant="lg"
              href={organization.links.donations}
              target="_blank"
              sx={{
                backgroundImage: t => t.util.gx('green', 'blue'),
                width: ['100%', 'auto', 'auto']
              }}
            >
              <Flex
                sx={{
                  flexDirection: 'row',
                  alignItems: 'center',
                  justifyContent: 'center',
                  width: '24px',
                  height: '24px',
                  marginLeft: -1,
                  marginRight: 2
                }}
              >
                <Icon glyph="friend" size={20} style={{ scale: '2.5' }} />
              </Flex>
              Make a Donation
            </Button>
          </Flex>
        </Flex>
      </Card>
    </Box>
  )
}


================================================
FILE: components/donate/donors.json
================================================
{
  "1517": "http://www.1517fund.com/",
  "Aakash Adesara": null,
  "Abby Fischler": null,
  "Achal Srinivasan": null,
  "Adora Svitak": null,
  "Adrienne Tran": null,
  "Alex Koren": "https://twitter.com/alexekoren",
  "Alex Peña": "http://www.alexaaronpena.com/home.html",
  "Alexander Turin": null,
  "Alishaan Ali": "https://alishaan.io",
  "Allyson Dias": "https://twitter.com/AllysonDias",
  "Amanda Mae-an Wofford": null,
  "Amanda Southworth": "https://twitter.com/amndasuthwrth",
  "Amogh Chaubey": "https://amogh.sh",
  "Amritha Jayanti": null,
  "Amy Sorto": null,
  "Andrew Breckenridge": "https://github.com/AndrewSB",
  "Andrew Downing": null,
  "Andrew Ninh": null,
  "Andrew Zoerb": null,
  "Andy Haden": "https://github.com/andyh2",
  "Angus Jyu": null,
  "Ankit Ranjan": "http://www.ankit.io/",
  "Ankit Shah": "https://twitter.com/AnkitShah",
  "Ann Mazuk": null,
  "Arjun Dileep": null,
  "Asta Lasf": null,
  "Athul Blesson": "https://www.linkedin.com/in/athul-blesson-92ab3b115/",
  "Avi Romanoff": null,
  "Ben Yu": "https://twitter.com/intenex",
  "Beyang Liu": "https://www.linkedin.com/in/beyang-liu-07651227",
  "Bhargav Yadavalli": "https://www.linkedin.com/in/bhargavy/",
  "Bigglesworth Family Foundation": "https://www.bigglesworthff.org/",
  "Brayden McLean": null,
  "Brett Neese": null,
  "Brian Nguyen": null,
  "Cayce Beames": null,
  "Chaleb Pommells": null,
  "Changbai Li": "https://changbai.li/",
  "Chaoyi Zha": null,
  "Chris Van Pelt": "https://twitter.com/vanpelt",
  "Chris Walker": "https://twitter.com/EnDimensions",
  "Christian Zenaty": null,
  "Christina Kim": null,
  "Christina Lewis Halpern": null,
  "Clara Tsao": null,
  "Connie Liu": null,
  "Daniel Sinclair": null,
  "David C Farnan-Williams": null,
  "Dennis Ashendorf": null,
  "Dhruv Maheshwari": null,
  "Doris Capet": null,
  "Edward Jiang": null,
  "Elon Musk": "https://en.wikipedia.org/wiki/Elon_Musk",
  "Emily Pries": null,
  "Emily Tseng": null,
  "Erik Batista": null,
  "Ethan Resnick": null,
  "Evan Shui": null,
  "Fast Forward": "https://www.ffwd.org/",
  "Fern Ray": null,
  "Ferran Arricivita": null,
  "Fiona Carty": "https://dribbble.com/nonafiona",
  "Garrett Wesley": null,
  "Gautam Bhargava": null,
  "Gautam Mittal": null,
  "Gemma Busoni": "https://twitter.com/gemmabusoni",
  "Geoff Ralston": null,
  "Gisela Kottmeier": null,
  "Google.org": "https://www.google.org/",
  "Gordon Smith": null,
  "Guilherme de Souza": null,
  "Hallie Lomax": "http://lomax.ninja/",
  "Hamza bnr Bellucci": null,
  "Hortensia Gomez-tirella": null,
  "Ishaan Parikh": null,
  "Jack Chak": null,
  "Jackcheal Dang": null,
  "Jacob Haap": "https://jacobhaap.com",
  "Jake Brownson": null,
  "Jamsheed Mistri": null,
  "Jason Marmon": null,
  "Jay Freeman": "http://www.saurik.com/",
  "Jeff Hilnbrand": null,
  "Jeffrey Owens": null,
  "Jennifer Kakuske": null,
  "Jevin Sidhu": null,
  "Jim Latta": null,
  "Joe Lonsdale": null,
  "Joseph Douglas": "https://twitter.com/JosephRDouglas",
  "Josh & Michelle Weatherspoon": null,
  "Julie Latta": null,
  "Junius Sim": "https://www.linkedin.com/in/juniussim/",
  "Justin Brezhnev": null,
  "Justin Harris": "https://envisionwithjustin.com/",
  "Kartik Talwar": null,
  "Katie Latta": null,
  "Keala Lusk": "http://kea.la/",
  "Kelly Peng": null,
  "Kevin Chu": null,
  "Kevin Conner": null,
  "Kevin Wang": "https://twitter.com/kevinverse",
  "Kunal Batra": null,
  "Kyle Emile": null,
  "Lachlan Campbell": "https://lachlanjc.com",
  "LạiDuy": null,
  "Lan Paje": "https://twitter.com/lanpaje",
  "Larry Weiss": null,
  "Lia Stanciu Gregory": null,
  "Liam Horne": "https://twitter.com/liamihorne",
  "Mackenzie Burnett": null,
  "Maria Choi": null,
  "Mark Prideaux": null,
  "Matthew Stanciu": "https://matthewstanciu.me",
  "Megan Cui": "https://megancui.com/",
  "Michael Akilian": null,
  "Michael Copley": null,
  "Michael Hulet": null,
  "Michael Yoo": null,
  "Michelle Leveille": null,
  "Mick Donahue": null,
  "Mike Swift": "https://twitter.com/swiftalphaone",
  "Mingjie Jiang": "https://mingjie.info",
  "Mohit Bhatia": "https://github.com/mohitbhatia1994",
  "Myles Byrne": "https://twitter.com/quackingduck",
  "Nate Wienert": "https://github.com/natew",
  "Nelson Gomez": null,
  "Nick Quinlan": null,
  "Nikhil Srinivasan": null,
  "Oliver Belanger": null,
  "Patrick Pistor": "https://github.com/yogert96",
  "Paul Cichocki": null,
  "Phat Le": "https://www.phatle.com/",
  "Phil Hedayatnia": "http://www.hedayatnia.com/",
  "Polly Schneider": null,
  "Prisma Data, Inc.": "https://prismic.io/",
  "Quinn Slack": "https://qslack.com/",
  "Rashid Al-Abri": null,
  "Reid Workman": null,
  "Robert Gregory": null,
  "Rohith Varanasi": null,
  "Rush Wofford": null,
  "Ryan Orbuch": "https://twitter.com/orbuch",
  "Saharsh Yeruva": "https://saharsh.tech",
  "Samay Shamdasani": "https://shamdasani.org/",
  "Samuel Escapa": "https://github.com/saescapa",
  "Santiago Siri": "https://twitter.com/santisiri",
  "Scott Chow": null,
  "Scott Motte": "https://www.scottmotte.com/",
  "Sean Kim": null,
  "Selynna Sun": "https://www.selynnasun.com/",
  "Shariq Hashme": "https://shar.iq/",
  "Sheryl Kern-Jones": null,
  "Shrav Mehta": null,
  "Shriya Nevatia": null,
  "Shriyash Jalukar": "https://www.linkedin.com/in/shriyashjalukar/",
  "Siddhartha Desai": null,
  "Sina Hamedian": null,
  "Sourcegraph": "https://sourcegraph.com/",
  "Spencer Yen": null,
  "Stephanie He": null,
  "Steven Duong": null,
  "Tanya Latta": null,
  "Taylor Otwell": null,
  "Tejas Manohar": "https://tejas.io/",
  "The Reva & David Logan Foundation": "http://www.loganfdn.org/",
  "The Thiel Fellowship": "http://thielfellowship.org/",
  "Thiel Foundation": "http://www.thielfoundation.org/",
  "Tiffany Yin": null,
  "Tom Preston-Werner": "http://tom.preston-werner.com/",
  "Truman Chan": null,
  "Tyler Hilliard": null,
  "Victor Truong": "https://victortruong.net",
  "Waj Waj": null,
  "Will Gaybrick": null,
  "William Wold": null,
  "Xavier Shay": "https://xaviershay.com/",
  "Yacoub Oulad Daoud": null,
  "Yev Barkalov": "http://www.yev.sh/",
  "Zach Holman": "https://zachholman.com/",
  "Zane Davis-Barrs": "https://zane.sh/",
  "Zane Sindhu": null
}


================================================
FILE: components/donate/sponsors.tsx
================================================
/** @jsxImportSource theme-ui */
import styled from '@emotion/styled'
import { Box, Image, Link } from 'theme-ui'

const Base = styled(Box)`
  display: grid;
  grid-gap: 18px;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  align-items: center;
  justify-content: center;
  img {
    margin: auto;
    max-width: 12rem;
  }
`

const Sponsor = ({ name, href, img, ...props }) => (
  <Link href={href || `https://${name.toLowerCase()}.com`} target="_blank">
    <Image
      src={`/inkind_logos/${img || name.toLowerCase() + '.svg'}`}
      alt={name}
      {...props}
    />
  </Link>
)

const Sponsors = props => (
  <Base maxWidth={48} {...props}>
    {[
      'Vercel',
      'Slack',
      'Netlify',
      'FullStory',
      'BrowserStack',
      'Stripe',
      'Segment',
      'Bugsnag',
      'Google',
      'Dialpad'
    ].map(name => (
      <Sponsor name={name} key={name} />
    ))}
    <Sponsor name="Checkly" href="https://checklyhq.com" img="checkly.svg" />
    <Sponsor
      name="Fast Forward"
      href="https://ffwd.org"
      img="fastforward.png"
    />
    <Sponsor
      name="Intercom"
      href="https://www.intercom.com"
      img="intercom.png"
    />
  </Base>
)

export default Sponsors


================================================
FILE: components/dot.tsx
================================================
import { Text } from 'theme-ui'
import { keyframes } from '@emotion/react'

const flashing = keyframes({
  from: { opacity: 0 },
  '50%': { opacity: 1 },
  to: { opacity: 0 }
})

export default function Dot({ hideOnMobile }) {
  return (
    <Text
      sx={{
        bg: 'green',
        color: 'white',
        borderRadius: 'circle',
        lineHeight: 0,
        width: '.4em',
        height: '.4em',
        marginRight: '.4em',
        marginBottom: '.12em',
        animationName: `${flashing}`,
        animationDuration: '3s',
        animationTimingFunction: 'ease-in-out',
        animationIterationCount: 'infinite',
        display: hideOnMobile ? ['none', 'default'] : 'default'
      }}
    />
  )
}


================================================
FILE: components/elon.mdx
================================================
Elon Musk holds a special place amongst hackers. After growing up in a difficult
family situation in South Africa, working his way in small jobs until reaching
Los Angeles, teaching himself to code, and making hundreds of millions
co-founding PayPal, he kept on building.

It was a huge honor last month to have Elon [spend an hour in a Hack Club
AMA](https://youtu.be/riru9OzScwk)—at one point he remarked we were “asking
better questions than all the mainstream media.”

Afterwards, Elon wanted to support Hack Club further.

# Today, I’m proud to share: Elon&nbsp;Musk is donating $500,000 to&nbsp;Hack&nbsp;Club.

In so many ways, this is a milestone for every Hack Clubber. 6 years ago, I
started Hack Club as a 16-year-old programmer living on my own, scraping by,
barely able to make rent. Now Elon Musk is one of our largest supporters.

Elon is supporting us because we are a community of builders. When hackers see
problems in the world, we don’t blame someone else: we try to take them on
ourselves to solve. Elon is very selective about the nonprofits he supports and
I’m proud Hack Club is one of them.

So…how is Hack Club going to invest $500k? We want to use this to help 1000 more
students start and join Hack Clubs in their communities. For those already in
Hack Clubs, we look to you to help us make a more high-quality experience. We’re
a lot of what we’ve already been doing (and [what I wrote about at the beginning
of the year](https://zachinto2020.wordpress.com/2019/12/31/as-midnight-approaches/)):
we’ll spend as little money as possible at all times, and we’ll hire a small
number of diverse staff from video game engineers to media producers to make
Hack Club better. We are pushing hard now to expand users of [HCB](https://hackclub.com/fiscal-sponsorship/),
and continuing to try and make the Hack Club Slack the best place to be a teenager on the intenet.

We’ll have a proper announcement in a few weeks, but one thing we’re doing after
winning the [Frank Grant](https://grant.frank.ly/) and now receiving Elon’s
gift, is open sourcing our finances. Hack Club HQ has been running on HCB
since February and starting today, you can see our account publicly at
https://hcb.hackclub.com/hq. You can track how we spend every single dollar of
Elon’s gift. Soon, we will also launch https://frank.ly/ on Hack&nbsp;Club’s
website.

Hack Club’s mission is to build a new generation of hackers. This starts in high
school, where Hack Club students learn to be technically proficient, build their
friend network, learn to raise and spend money, and develop into kind, curious,
thoughtful, optimistic, and honest leaders.

Elon Musk is now supporting you and your work, so go out and do amazing things.
Elon can’t wait to see what you make.

—Zach


================================================
FILE: components/fade-in.tsx
================================================
import React from 'react'
import { Box } from 'theme-ui'
import styled from '@emotion/styled'
import { keyframes } from '@emotion/react'

const fadeIn = keyframes({ from: { opacity: 0 }, to: { opacity: 1 } })

const Wrapper = styled(Box)`
  @media (prefers-reduced-motion: no-preference) {
    animation-name: ${fadeIn};
    animation-fill-mode: backwards;
  }
`

const FadeIn = ({ duration = 300, delay = 0, ...props }) => (
  <Wrapper
    {...props}
    style={{
      ...(props.style || {}),
      animationDuration: duration + 'ms',
      animationDelay: delay + 'ms'
    }}
  />
)

export default FadeIn


================================================
FILE: components/fiscal-sponsorship/contact.tsx
================================================
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={{
        display: ['none', 'flex'],
        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>
  )
}


================================================
FILE: components/fiscal-sponsorship/directory/card.tsx
================================================
import { Card, Badge as ThemeBadge, Box, Heading, Text, Image } from 'theme-ui'
import { Organization } from '../../../lib/organization'
import Tilt from '../../tilt'
import Icon from '@hackclub/icons'
import Tooltip from '../tooltip'

export const Badge = ({ badge }) =>
  badge.image ? (
    <ThemeBadge
      as="span"
      sx={{
        backgroundImage: `url("${badge.image}")`,
        backgroundSize: 'contain',
        backgroundColor: 'unset',
        backgroundRepeat: 'no-repeat',
        backgroundPosition: 'center',
        fontSize: 'inherit',
        textShadow: 'none',
        borderRadius: 5,
        display: 'block',
        height: 30,
        width: 38
      }}
    >
      <span style={{ opacity: '0' }}>.</span>
    </ThemeBadge>
  ) : (
    <ThemeBadge
      as="span"
      sx={{
        bg: badge.color,
        color: 'snow',
        fontSize: 'inherit',
        textShadow: 'none',
        borderRadius: 5,
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center'
      }}
    >
      <Icon glyph={badge.icon} size={30} />
    </ThemeBadge>
  )

type OrganizationCardProps = {
  organization: Organization
  openModal: (organization: Organization) => void
  badges: any[]
}

/**
 *
 * @param {{
 * organization: Organization,
 * showTags: boolean
 * }} props
 * @returns
 */
export const OrganizationCard = ({
  openModal,
  badges,
  organization
}: OrganizationCardProps) => (
  <Tilt>
    <Card
      onClick={() => openModal(organization)}
      rel="noopener noreferrer"
      itemScope
      itemType="http://schema.org/Event"
      variant="event"
      sx={{
        justifyContent: 'center',
        alignItems: 'center',
        minHeight: 128,
        color: 'white',
        cursor: 'pointer',
        textShadow: '0 1px 4px rgba(0, 0, 0, 0.375)',
        textDecoration: 'none',
        backgroundColor: 'black',
        backgroundSize: 'cover',
        backgroundPosition: 'center',
        backgroundRepeat: 'no-repeat',
        borderRadius: 'extra',
        overflow: 'hidden',
        position: 'relative',
        p: 3,
        height: '100%',
        display: 'flex',
        px: 3,
        backgroundImage: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,0.375) 75%), url('${organization.branding.backgroundImage}')`,
        textAlign: 'center',
        flexDirection: 'column'
      }}
    >
      <Box
        sx={{
          display: 'flex',
          justifyContent: 'end',
          alignItems: 'center',
          width: '100%',
          gap: 2,
          flexDirection: 'row',
          mb: 3
        }}
      >
        {badges.map((badge, i) => (
          <Tooltip.W key={i} text={badge.label} id={badge.id}>
            <span className={`tooltipped-${badge.id}`}>
              <Badge badge={badge} />
            </span>
          </Tooltip.W>
        ))}
      </Box>

      {organization.branding.logo && (
        <Image
          src={organization.branding.logo}
          alt={`${organization.name} logo`}
          loading="lazy"
          sx={{
            // minWidth: 64,
            height: 64,
            objectFit: 'contain',
            objectPosition: 'left',
            borderRadius: 'default',
            mt: 'auto'
          }}
        />
      )}
      <Heading
        as={'h3'}
        itemProp="name"
        sx={{
          fontSize: [3, 4],
          mt: 2,
          mb: 3,
          overflowWrap: 'anywhere',
          width: '100%',
          display: 'block'
        }}
      >
        {organization.name}
      </Heading>
      <Box
        as="footer"
        sx={{
          mt: 'auto',
          mb: 0,
          width: '100%',
          opacity: 0.875,
          textTransform: 'none'
        }}
      >
        <>
          <Text
            as="span"
            itemProp="location"
            itemScope
            itemType="http://schema.org/Place"
          >
            <span itemProp="address">
              {organization.raw.location.continent}
            </span>
          </Text>
        </>
      </Box>
      <Box sx={{ display: 'none' }}>
        <span itemProp="url">{organization.links.website}</span>
      </Box>
    </Card>
  </Tilt>
)

export default OrganizationCard


================================================
FILE: components/fiscal-sponsorship/features.tsx
================================================
import { Box, Heading, Link, Text, Container, Grid } from 'theme-ui'
import Icon from '../icon'
import { Balancer } from 'react-wrap-balancer'
import Image from 'next/image'
import imgLaptop from '../../public/fiscal-sponsorship/laptop.png'

export default function Features() {
  return (
    <Box sx={{ pt: 5, pb: [5, 6] }}>
      <Container>
        <Heading as="h2" variant="title" sx={{ mb: 3, maxWidth: 'copyUltra' }}>
          <Balancer>
            Powerful financial tools built by our nonprofit, for yours.
          </Balancer>
        </Heading>
        <Text as="p" variant="lead" sx={{ color: 'slate', maxWidth: '55ch' }}>
          Since day one, we’ve built beautiful, self-serve software to empower
          you to raise and spend money without administrative hassle. We’re also
          open&nbsp;source!
        </Text>
        <Grid columns={[null, 2, 3]} sx={{ mt: 4, rowGap: 3, columnGap: 4 }}>
          <Module
            icon="bank-account"
            name="Receive foundation grants"
            body="with tax-deductible 501(c)(3) status."
          />
          {/* Send money & reimburse via check, ACH, bank wire, & more.
              Operate globally with a US Entity.
              Issue physical & virtual debit cards to your team.
              Get 24 hour support on weekdays.
              Pay team members with built-in payroll.
              Embed a custom donation form on your website.
              We file all your taxes automatically, including Form 990. " */}
          <Module
            icon="card"
            name="Issue physical & virtual debit cards"
            body="with receipt tracking & Apple Pay."
          />
          <Module
            icon="web"
            name="Operate globally"
            body="with a U.S. legal entity."
          />
          <Module
            icon="payment-transfer"
            name="Send money & reimburse"
            body="via check, ACH, bank wire, & more."
          />
          <Module
            icon="explore"
            name="Make your finances transparent"
            body="to your team and optionally, public."
          />
          <Module
            icon="docs"
            name="We file all your taxes"
            body="automatically, including Form 990."
          />
          <Module
            icon="admin"
            name="Pay team members"
            body="with built-in payroll."
          />
          <Module
            icon="support"
            name="Accept donations of any size"
            body="with a custom, embeddable online form."
          />
          <Module
            icon="leader"
            name="Get 24-hour support"
            body="on weekdays with a dedicated point of contact."
          />
        </Grid>
      </Container>
      <Container variant="copy" sx={{ mt: [4, 5] }}>
        <Laptop
          href="https://hcb.hackclub.com/reboot"
          title="See Reboot’s finances in public"
        />
        <Link
          href="https://github.com/hackclub/hcb"
          title="Open Source"
          sx={{ textAlign: 'center' }}
        >
          <Text variant="caption" as="p" sx={{ color: 'primary', mt: 2 }}>
            See our open source on GitHub
          </Text>
        </Link>
      </Container>
    </Box>
  )
}

function Module({ icon, name, body }) {
  return (
    <Box
      sx={{
        display: 'flex',
        alignItems: 'start',
        columnGap: 3
      }}
    >
      <Box
        sx={{
          flexShrink: 0,
          width: 40,
          height: 40,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center'
        }}
      >
        <Icon
          size={40}
          glyph={icon}
          sx={{
            color: 'primary',
            flexShrink: 0,
            display: 'block',
            width: 40,
            height: 40
          }}
        />
      </Box>
      <Text
        as="p"
        sx={{
          color: 'slate',
          lineHeight: '1.375',
          fontSize: 20,
          m: 0
        }}
      >
        <Balancer>
          <Text as="strong" color="slate">
            {name}
          </Text>{' '}
          {body}
        </Balancer>
      </Text>
    </Box>
  )
}

function Laptop({ href, title }) {
  return (
    <Link href={href} title={title} sx={{ textAlign: 'center' }}>
      <Image
        src={imgLaptop}
        alt="Laptop"
        unoptimized
        style={{
          width: '100%',
          maxWidth: '100%',
          height: 'auto'
        }}
      />
      <Text variant="caption" as="p" sx={{ color: 'primary', mt: 2 }}>
        See <i>Reboot</i>’s finances in Transparency Mode
      </Text>
    </Link>
  )
}


================================================
FILE: components/fiscal-sponsorship/first/apply-button.tsx
================================================
import { Button, Text, Flex } from 'theme-ui'
import Icon from '../../icon'
import Link from 'next/link'

export default function ApplyButton() {
  return (
    <Link href="https://hcb.hackclub.com/applications/new">
      <Button
        variant="ctaLg"
        sx={{
          width: '100%',
          height: '4.2rem'
          // borderRadius: '1.5rem',
        }}
      >
        <Flex
          sx={{
            alignItems: 'center',
            gap: 3,
            mr: '-32px' // Man...
          }}
        >
          <Text color="white" sx={{ fontWeight: 'bold', fontSize: 4 }}>
            Apply now
          </Text>
          <Icon glyph="view-forward" size={46} color="white" />
        </Flex>
      </Button>
    </Link>
  )
}


================================================
FILE: components/fiscal-sponsorship/first/features.tsx
================================================
/** @jsxImportSource theme-ui */
import { Box, Heading, Link, Text, Container, Card, Image } from 'theme-ui'
import Icon from '../../icon'
import Masonry from 'react-masonry-css'
import NextImage from 'next/image'

import { Fade } from '../../react-reveal-compat'

export default function Features() {
  return (
    <Box sx={{ py: 5 }}>
      <Box as="a" href="#testimonials">
        <Image
          src="/fiscal-sponsorship/meet-teams-using-hcb.svg"
          alt="yeah"
          width={200}
          height={100}
          sx={{
            position: 'absolute',
            right: 2,
            mt: -36,
            display: ['none', 'none', 'none', 'block'],
            '&:hover': {
              transform: 'scale(1.05)'
            }
          }}
        />
      </Box>
      <Container>
        <Text variant="heading" sx={{ fontSize: 50 }}>
          Everything you'll need.
        </Text>
        <br />
        <br />
        <Text sx={{ color: 'muted', maxWidth: '48', fontSize: 28 }}>
          Organize your team's finances in real time, receive grants, gain
          nonprofit status, & more.
          <br />
          Use features engineered by <i>FIRST</i> alumni to help you run a
          successful team.
        </Text>
        <br />
        <br />
      </Container>
      <Container>
        <Masonry
          breakpointCols={{
            10000: 3,
            640: 2,
            480: 1,
            default: 1
          }}
          className="masonry-posts"
          columnClassName="masonry-posts-column"
        >
          <Module
            icon="bank-account"
            name="Nonprofit status"
            body="Become part of Hack Club's legal entity, getting the benefits of our 501(c)(3) tax status."
          />

          <ModuleDetails>
            <Link
              href="https://hcb.hackclub.com/poseidon-robotics"
              target="_blank"
            >
              <NextImage
                src="/fiscal-sponsorship/poseidon-dashboard.png"
                alt="iPad"
                width={500}
                height={300}
                style={{
                  maxWidth: '100%',
                  height: 'auto'
                }}
              />
            </Link>
          </ModuleDetails>

          <Module
            icon="analytics"
            name="Balance &amp; history"
            body="Keep everyone on your team and beyond up to date with real-time balance and transaction history."
          />

          <Module
            icon="card"
            name="Debit cards"
            body="Issue physical debit cards to all your teammates."
          />

          <Module
            icon="payment"
            name="Grants &amp; donations"
            body="Easily receive and deposit money from grants and donations into your account. You'll also get a customizable online donation form to share with friends and family."
          />

          <Module
            icon="payment-transfer"
            name="Reimbursement flow"
            body="Reimburse teammates for expenses with flexible money transfer options including ACH, mailed checks, and more."
          />
          {/* <Fade bottom>
            <Tilt>
              <Card
                as="div"
                sx={{
                  backgroundImage:
                    'url("https://cloud-ehtgzdn7u-hack-club-bot.vercel.app/0card.png")',
                  height: '230px',
                  backgroundSize: 'cover',
                  boxShadow: '0 8px 32px rgba(255, 255, 255, 0.0625)'
                }}
              />
            </Tilt>
          </Fade> */}
          <Module
            icon="support"
            name="Support anytime"
            body="With 24-hour response time on weekdays, we'll never leave you hanging."
          />
          {/* <Tilt>
            <Card
              as="div"
              sx={{
                borderRadius: 0,
                backgroundColor: '#193046',
                boxShadow:
                  '0 0 2px 0 rgb(0 0 0 / 6%), 0 6px 12px 0 rgb(0 0 0 / 25%)',
                '&::before': {
                  position: 'absolute',
                  content: '""',
                  top: 0,
                  left: 0,
                  right: 0,
                  bottom: 0,
                  margin: '0.5rem',
                  border: '1px dotted #8492a6'
                }
              }}
            >
              <Flex sx={{ justifyContent: 'end' }}>
                <Text
                  sx={{
                    textTransform: 'uppercase',
                    fontSize: '10px',
                    lineHeight: 1
                  }}
                >
                  Date
                </Text>
                <Text sx={{ fontFamily: 'cursive' }}>10-10-2020</Text>
              </Flex>
              <Flex sx={{ width: '100%' }}>
                <Text
                  sx={{
                    textTransform: 'uppercase',
                    fontSize: '10px',
                    lineHeight: 1
                  }}
                >
                  Pay to the <br />
                  order of
                </Text>
                <Text
                  as="span"
                  sx={{ fontFamily: 'cursive', textAlign: 'left', ml: 2 }}
                >
                  Hack Club
                </Text>

                <Text
                  sx={{
                    textAlign: 'right',
                    ml: 'auto'
                  }}
                >
                  $
                  <Text
                    as="span"
                    sx={{
                      border: '1px solid rgba(255, 255, 255, 0.25)',
                      fontFamily: 'cursive'
                    }}
                  >
                    1000
                  </Text>
                </Text>
              </Flex>
              <Flex sx={{ justifyContent: 'space-between', alignItems: 'end' }}>
                <Text sx={{ fontFamily: 'cursive' }}>One thousand only</Text>
                <Text
                  sx={{
                    textTransform: 'uppercase',
                    fontSize: '10px',
                    lineHeight: 1
                  }}
                >
                  Dollars
                </Text>
              </Flex>

              <Flex
                sx={{
                  justifyContent: 'space-between',
                  alignItems: 'center',
                  pb: 1
                }}
              >
                <Text
                  sx={{
                    textTransform: 'uppercase',
                    fontSize: '10px',
                    lineHeight: 1
                  }}
                >
                  Memo
                  <Text
                    as="span"
                    sx={{
                      fontFamily: 'cursive',
                      fontSize: '12px',
                      textTransform: 'none'
                    }}
                  >
                    {' '}
                    Grant for Poseidon Robotics
                  </Text>
                </Text>
                <Image
                  src="/signatures/prophet_orpheus-light.png"
                  alt="Prophet Orpheus signature"
                  width={80}
                  height={30}
                />
              </Flex>
              <Flex>
                <Text
                  sx={{
                    fontFamily: 'monospace',
                    fontSize: '10px',
                    lineHeight: 1,
                    pt: 1,
                    mb: -3
                  }}
                >
                  ⑆ 00000000000 ⑆ 123456789 ⑆
                </Text>
              </Flex>
            </Card>
          </Tilt> */}
          {/* <Module
            icon="rep"
            name="No start-up costs"
            body="All fees waived on your first $25k until September 1st, 2023. Then, just 7% of revenue (as compared to 10-14% charged by other fiscal sponsors). "
          /> */}
        </Masonry>
      </Container>
      <Container
        variant="narrow"
        sx={{
          pt: 3,
          borderColor: 'muted',
          textAlign: 'center'
        }}
      >
        <Text variant="caption" sx={{ color: 'muted' }}>
          Hack Club does not directly provide banking services. Banking services
          are provided by FDIC-certified financial institutions.
        </Text>
      </Container>
      <style>{`
      .masonry-posts {
        display: flex;
        width: 100%;
        max-width: 100%;
      }

      .masonry-posts-column {
        background-clip: padding-box;
      }

      .post {
        margin-bottom: 16px;
      }

      @media (max-width: 32em) {
        .post:nth-child(8) ~ .post {
          display: none;
        }
      }

      @media (min-width: 32em) {
        .masonry-posts {
          padding-right: 12px;
        }

        .masonry-posts-column {
          padding-left: 12px;
        }

        .post {
          border-radius: 12px;
          margin-bottom: 12px;
        }
      }

      @media (min-width: 64em) {
        .masonry-posts {
          padding-right: 24px;
        }

        .masonry-posts-column {
          padding-left: 24px;
        }

        .post {
          margin-bottom: 24px;
        }
      }

    `}</style>
    </Box>
  )
}

type ModuleProps = {
  icon: string
  name: string
  body: string
  iconColor?: string
}

function Module({ icon, name, body, iconColor }: ModuleProps) {
  return (
    <Fade bottom>
      <Card
        variant="primary"
        sx={{
          display: 'flex',
          flexDirection: 'column',
          p: [4, null, 4]
        }}
        className="post"
      >
        <Box
          as="span"
          sx={{
            width: 'fit-content',
            background: iconColor || 'primary',
            borderRadius: 'default',
            lineHeight: 0,
            p: 1,
            mb: 1,
            display: 'inline-block',
            transform: ['scale(0.75)', 'none'],
            transformOrigin: 'bottom left',
            boxShadow:
              'inset 2px 2px 6px rgba(255,255,255,0.2), inset -2px -2px 6px rgba(0,0,0,0.1), 0 1px 4px rgba(0,0,0,0.1), 0 4px 8px rgba(0,0,0,0.1)'
          }}
        >
          <Icon glyph={icon} size={28} />
        </Box>
        <Box>
          <Heading sx={{ color: 'snow', lineHeight: '1.5' }}>{name}</Heading>
          <Text
            sx={{
              color: 'muted',
              lineHeight: '1.375',
              fontSize: 17
            }}
          >
            {body}
          </Text>
        </Box>
      </Card>
    </Fade>
  )
}

function ModuleDetails({ children }) {
  return (
    <Fade bottom>
      <Box
        sx={{
          bg: 'none',
          color: 'smoke',
          boxShadow: '0 8px 32px rgba(255, 255, 255, 0.0625)',
          borderRadius: 'default',
          p: 0,
          mb: 3
        }}
      >
        {children}
      </Box>
    </Fade>
  )
}

function Document({ name, cost }) {
  return (
    <Box sx={{ display: 'flex' }}>
      <Icon
        size={28}
        mr={1}
        glyph="payment"
        sx={{ flexShrink: 0, color: 'green' }}
      />
      <Box sx={{ display: 'flex', flexDirection: 'column' }}>
        <Text fontSize={2}>{name}</Text>

        {cost && (
          <Text fontSize={1} color="muted" style={{ lineHeight: '1.375' }}>
            {cost}
          </Text>
        )}
      </Box>
    </Box>
  )
}

function Laptop({ href, title, sx }) {
  return (
    <Link href={href} title={title} sx={sx}>
      <Box
        sx={{
          display: 'block',
          width: '100%',
          height: '100%',
          minHeight: '16rem',
          backgroundSize: 'auto 115%',
          backgroundImage:
            "url('https://cloud-az94fzpyw-hack-club-bot.vercel.app/1poseidon.png')",
          backgroundPosition: 'center top',
          backgroundRepeat: 'no-repeat'
        }}
      ></Box>
    </Link>
  )
}


================================================
FILE: components/fiscal-sponsorship/first/start.tsx
================================================
import { Box, Link, Text, Heading, Flex } from 'theme-ui'
import Stats from './stats'
import ApplyButton from './apply-button'

export default function Start({ stats }) {
  return (
    <>
      <Box as="section" id="apply" py={6}>
        <Flex
          sx={{ flexDirection: 'column', alignItems: 'center', gap: 5, mx: 4 }}
        >
          <Flex
            sx={{
              flexDirection: 'column',
              textAlign: 'center',
              gap: 3
            }}
          >
            <Heading variant="ultratitle" color="white">
              Sign up for HCB.
            </Heading>
            <Text color="muted" variant="lead" m="0 !important">
              Open to Hack Clubs, hackathons, and charitable organizations in
              the US and Canada.
            </Text>
          </Flex>
          <Stats stats={stats} />
          <Flex
            sx={{ flexDirection: 'column', textAlign: 'center', gap: 4, mx: 3 }}
          >
            <ApplyButton />
            <Text color="muted" sx={{ fontSize: 18 }}>
              We run Hack Club HQ on HCB!{' '}
              <Link href="https://hcb.hackclub.com/hq" color="primary">
                See&nbsp;our&nbsp;finances.
              </Link>
            </Text>
          </Flex>
        </Flex>
      </Box>
    </>
  )
}


================================================
FILE: components/fiscal-sponsorship/first/stats.tsx
================================================
import { Text, Box, Flex } from 'theme-ui'
import { useEffect, useState } from 'react'

const easeInOutExpo = x =>
  x === 0
    ? 0
    : x === 1
      ? 1
      : x < 0.5
        ? Math.pow(2, 20 * x - 10) / 2
        : (2 - Math.pow(2, -20 * x + 10)) / 2

function startMoneyAnimation(
  setBalance,
  amount,
  duration = 2_000,
  moneyFormatter
) {
  const startTime = performance.now()

  function animate() {
    const time = performance.now() - startTime
    const progress = time / duration
    const easedProgress = easeInOutExpo(progress)

    setBalance(moneyFormatter(amount * easedProgress))

    if (progress < 1) {
      requestAnimationFrame(animate)
    } else {
      setBalance(moneyFormatter(amount))
    }
  }

  requestAnimationFrame(animate)
}

function formatMoney(amount) {
  const normalisedAmount = amount / 100
  return normalisedAmount
    .toLocaleString('en-US', { style: 'currency', currency: 'USD' })
    .split('.')
}

const Stats = ({ stats }) => {
  const [balance, setBalance] = useState(0) // A formatted balance string, split by decimal

  useEffect(() => {
    const observer = new IntersectionObserver(
      e => {
        if (e[0].isIntersecting) {
          console.info('intersecting')
          startMoneyAnimation(
            setBalance,
            stats.transactions_volume,
            2_500,
            formatMoney
          )
        }
      },
      { threshold: 1.0 }
    )
    observer.observe(document.querySelector('#parent'))

    return () => observer.disconnect()
  }, [stats.transactions_volume])

  if (stats.transactions_volume === undefined) {
    return null
  }

  return (
    <Box id="parent">
      <Flex sx={{ flexDirection: 'column', alignItems: 'center' }}>
        <Text sx={{ fontSize: [3, 4] }}>So far we have enabled</Text>
        {stats ? (
          <>
            <Text
              variant="title"
              color="green"
              sx={{
                color: 'green',
                fontSize: [5, 6]
              }}
            >
              {balance[0]}
              <Text sx={{ fontSize: [3, 4] }}>.{balance[1]}</Text>
            </Text>
          </>
        ) : (
          <Text
            variant="title"
            color="green"
            sx={{
              color: 'green',
              fontSize: [5, 6]
            }}
          >
            ...
          </Text>
        )}
        <Text sx={{ fontSize: [3, 4] }}>in transactions</Text>
      </Flex>
    </Box>
  )
}

export async function getStaticProps() {
  const res = await fetch(`https://hcb.hackclub.com/stats`)
  try {
    const stats = await res.json()
    return {
      props: {
        stats
      },
      revalidate: 10
    }
  } catch (e) {
    return {
      props: {
        stats: {}
      },
      revalidate: 10
    }
  }
}

export default Stats


================================================
FILE: components/fiscal-sponsorship/first/testimonials.tsx
================================================
import {
  Box,
  Image,
  Text,
  Heading,
  Container,
  Grid,
  Link,
  Avatar,
  Button
} from 'theme-ui'
import { Slide } from '../../react-reveal-compat'

export default function Testimonials() {
  return (
    <>
      <Container
        variant="copy"
        sx={{
          display: 'flex',
          flexDirection: 'column',
          justifyContent: 'center',
          textAlign: 'center'
        }}
      >
        <Heading variant="title">
          <i>FIRST</i> teams all over the country run on HCB.
        </Heading>
        <Text variant="lead" color="muted">
          Everywhere from San Jose to Boston to New York, HCB powers teams of
          all sizes.
        </Text>
      </Container>
      <Container>
        <Grid
          gap={4}
          sx={{
            gridTemplateColumns: ['100%', null, null, '1fr 1fr']
          }}
        >
          <Organization
            logo="https://cloud-ab81zjlm9-hack-club-bot.vercel.app/0image.png"
            name="Poseidon Robotics"
            teamNum="FTC Team #16898"
            teamLocation="San Jose, CA"
            budget="$1,000,000"
            budgetLabel="in grants"
            website="evposeidon.wixsite.com"
            url="https://evposeidon.wixsite.com/robo/home"
            imgSrc="https://cloud-qtng6088u-hack-club-bot.vercel.app/0image.png"
            quote="Overall, [HCB] has opened more opportunities for Poseidon, allowing us to undertake larger projects, both on the playing field and in our community."
            hackerName="Ian Marwong"
            hackerRole="Team Lead"
            hackerAvatarUrl="/hackers/ian-marwong.jpg"
            transparency="poseidon-robotics"
          />
          <Organization
            logo="https://cloud-ga0lm1r8d-hack-club-bot.vercel.app/0image.png"
            name="Killabytez"
            teamNum="FTC Team #14663"
            teamLocation="Fremont, CA"
            budget="$1,000,000"
            budgetLabel="in grants"
            website="killabytez.club"
            url="http://www.killabytez.club/"
            hackerAvatarUrl="/hackers/brian-cisto.jpeg"
            hackerName="Brian Cisto"
            hackerRole="Team Captain & Software Lead"
            imgSrc="https://cloud-oelh6sp7b-hack-club-bot.vercel.app/0screen_shot_2022-11-06_at_8.45.37_pm.png"
            quote="[HCB] has been essential to keeping track of our finances as well as giving us the opportunity to establish ourselves as a nonprofit."
          />
        </Grid>
      </Container>
    </>
  )
}

function Organization({
  logo,
  name,
  website,
  teamNum,
  teamLocation,
  budget: _budget,
  budgetLabel: _budgetLabel,
  url,
  imgSrc,
  quote,
  hackerName,
  hackerAvatarUrl,
  hackerRole,
  transparency = undefined
}) {
  return (
    <Slide bottom>
      <Box
        sx={{
          backgroundColor: 'darkless',
          color: 'smoke',
          borderRadius: 'extra',
          mx: 'auto'
        }}
      >
        <Container sx={{ padding: 0, margin: 0 }}>
          <Image
            src={imgSrc}
            alt="Robots team"
            width={800}
            height={450}
            sx={{
              borderRadius: 'default',
              objectFit: 'cover'
            }}
          />
          <Box p={[3, null, 4]}>
            <Box
              sx={{
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'space-between'
              }}
            >
              <Box sx={{ display: 'flex', alignItems: 'center' }}>
                <Image
                  src={logo}
                  alt={`${name} logo`}
                  sx={{
                    height: '4rem',
                    width: '4rem',
                    objectFit: 'cover',
                    borderRadius: 'default'
                  }}
                />
                <Box sx={{ ml: 3 }}>
                  <Text
                    color="white"
                    variant="headline"
                    sx={{
                      fontSize: [28, null, 38],
                      lineHeight: 1,
                      letterSpacing: -0.1
                    }}
                  >
                    {name}
                  </Text>
                  <br />
                  <Link
                    href={url || `https://${website}`}
                    sx={{
                      textDecoration: 'none',
                      color: 'muted',
                      '&:hover': { textDecoration: 'underline' }
                    }}
                  >
                    {teamNum}
                  </Link>{' '}
                  • {teamLocation}
                </Box>
              </Box>
            </Box>

            <br />
            <Text
              sx={{
                color: 'snow',
                textIndent: '-.375em',
                lineHeight: 'caption',
                fontSize: 18
              }}
            >
              "{quote}"
            </Text>

            <Box
              sx={{
                display: 'flex',
                flexDirection: 'row',
                flexWrap: 'wrap',
                justifyContent: 'space-between',
                marginTop: ['0px', 3]
              }}
            >
              <Box
                sx={{
                  display: 'flex',
                  alignItems: 'center',
                  mt: ['16px', '0px']
                }}
              >
                <Avatar
                  src={hackerAvatarUrl}
                  size={48}
                  sx={{
                    mr: 2,
                    borderRadius: '100%'
                  }}
                  alt="Photo of ${hackerName}"
                />
                <Text
                  color="white"
                  sx={{
                    fontSize: 19,
                    display: 'flex',
                    flexDirection: 'column'
                  }}
                >
                  <Text sx={{ fontWeight: 'bold', lineHeight: 1.125 }}>
                    {hackerName}
                  </Text>
                  <Text>{hackerRole}</Text>
                </Text>
              </Box>
              {transparency && (
                <Link
                  href={`https://hcb.hackclub.com/${transparency}`}
                  target="_blank"
                  rel="noreferrer"
                  sx={{ mt: ['16px', '0px'] }}
                >
                  <Button
                    mt={[null, null, 4, 0]}
                    ml={[0, 'auto']}
                    sx={{ textTransform: 'none' }}
                    variant="primary"
                    title="🎶 take a look, it's in our books 🎵"
                  >
                    See Finances
                  </Button>
                </Link>
              )}
            </Box>
          </Box>
        </Container>
      </Box>
    </Slide>
  )
}


================================================
FILE: components/fiscal-sponsorship/open-source.tsx
================================================
/** @jsxImportSource theme-ui */

import { Box, Heading, Button, Text, Container, Grid, Flex } from 'theme-ui'
import Icon from '../icon'
import Photo from '../photo'
import HCBGource from '../../public/fiscal-sponsorship/hcb-gource.gif'

export default function OpenSource() {
  return (
    <Box as="section" sx={{ py: [4, 5], bg: 'snow' }}>
      <Container>
        <Grid columns={[1, 2]} gap={[4, 5]} sx={{ alignItems: 'center' }}>
          <div>
            <Heading as="h2" variant="headline" sx={{ mb: 3 }}>
              Open source infrastructure for fiscally sponsored organizations.
            </Heading>
            <Text as="p" sx={{ mb: 3 }}>
              HCB is open source and built in public, like many other Hack Club
              projects. Join us in building the infrastructure powering fiscally
              sponsored organizations around the world.
            </Text>
            <Flex
              sx={{
                flexWrap: 'wrap',
                gap: 3
              }}
            >
              <Button
                as="a"
                sx={{ flexShrink: 0, gap: 14, paddingLeft: 25 }}
                variant="outline"
                target="_blank"
                href="https://github.com/hackclub/hcb"
              >
                Star on GitHub
                <Icon glyph="github" />
              </Button>
              <Button
                as="a"
                sx={{
                  flexShrink: 0,
                  gap: 1,
                  paddingLeft: 25,
                  paddingRight: '5px'
                }}
                href="https://hackclub.com/hcb/open-source"
                target="_blank"
              >
                Read our blog post
                <Icon glyph="view-forward" />
              </Button>
            </Flex>
          </div>
          <Photo
            src={HCBGource}
            width={888}
            height={500}
            unoptimized
            sx={{
              maxWidth: '100%',
              width: 'auto !important',
              height: '500 !important',
              boxShadow: 'elevated'
            }}
            alt="Since open-sourcing, we've merged over 1,800 pull requests from contributors!"
            showAlt
          />
        </Grid>
      </Container>
    </Box>
  )
}


================================================
FILE: components/fiscal-sponsorship/organization-spotlight.tsx
================================================
/** @jsxImportSource theme-ui */
import Tilt from '../tilt'
import { Card, Heading, Text } from 'theme-ui'
import Image from 'next/image'
import { Balancer } from 'react-wrap-balancer'

export default function OrganizationSpotlight({ organization }) {
  return (
    <Tilt>
      <Card
        as="a"
        href={`https://hcb.hackclub.com/${organization.slug}`}
        sx={{
          justifyContent: 'center',
          alignItems: 'center',
          minHeight: 128,
          color: 'white',
          cursor: 'pointer',
          textShadow: '0 1px 4px rgba(0, 0, 0, 0.5)',
          textDecoration: 'none',
          backgroundColor: 'black',
          backgroundSize: 'cover',
          backgroundPosition: 'center',
          backgroundRepeat: 'no-repeat',
          borderRadius: 'extra',
          overflow: 'hidden',
          position: 'relative',
          p: 3,
          height: '100%',
          display: 'grid',
          gridTemplateColumns: '64px 1fr',
          columnGap: 3,
          rowGap: 2
        }}
        style={{
          backgroundImage: `linear-gradient(rgba(0,0,0,0.375) 0%, rgba(0,0,0,0.5) 75%), url('${organization.background_image}')`
        }}
      >
        <Image
          src={organization.logo}
          alt={`${organization.name} logo`}
          loading="lazy"
          width={64}
          height={64}
          style={{
            borderRadius: '16px',
            maxWidth: '100%',
            height: 'auto'
          }}
        />
        <div>
          <Heading
            as="h3"
            sx={{
              fontSize: [3, 4],
              m: 0,
              overflowWrap: 'anywhere',
              width: '100%',
              display: 'block'
            }}
          >
            {organization.name}
          </Heading>
          <Text
            variant="caption"
            sx={{
              color: 'white',
              opacity: 0.875
            }}
          >
            {organization.location.readable}
          </Text>
        </div>
        <Text as="p" sx={{ gridColumn: ['span 2', '2'] }}>
          <Balancer>{organization.description}</Balancer>
        </Text>
      </Card>
    </Tilt>
  )
}


================================================
FILE: components/fiscal-sponsorship/sign-in.tsx
================================================
/** @jsxImportSource theme-ui */
import { useEffect, useState } from 'react'
import { Button, Image } from 'theme-ui'

export default function SignIn() {
  const [user, setUser] = useState(null)

  useEffect(() => {
    ;(async () => {
      const _user = await fetch('https://hcb.hackclub.com/api/current_user', {
        credentials: 'include'
      })
        .then(r => (r.ok ? r.json() : null))
        .catch(() => {})

      if (_user) setUser(_user)
    })()
  }, [])

  return (
    <Button
      as="a"
      href="https://hcb.hackclub.com"
      variant="outline"
      sx={{ color: 'white' }}
    >
      {user ? (
        <>
          <Image
            src={user.avatar}
            alt={`${user.name}'s HCB avatar`}
            width={30}
            sx={{ borderRadius: 'circle', mr: 2, boxShadow: 'elevated' }}
          />
          Continue to HCB
        </>
      ) : (
        'Sign in'
      )}
    </Button>
  )
}


================================================
FILE: components/fiscal-sponsorship/tooltip.tsx
================================================
import React from 'react'

const tooltip = direction =>
  function Tooltip({ children, text, id }) {
    const escapedText = text.replace(/'/g, "\\'")
    const directionalStyles = {
      e: `
            left: 100%;
            bottom: 50%;
            right: 0;
            margin-left: 0.5rem;
            transform: translateY(50%);
        `,
      w: `
            right: 100%;
            bottom: 50%;
            margin-right: 0.5rem;
            transform: translateY(50%);
        `,
      n: `
            right: 50%;
            bottom: 100%;
            margin-bottom: 0.5rem;
            transform: translateX(50%);
        `,
      s: `
            right: 50%;
            top: 100%;
            margin-top: 0.5rem;
            transform: translateX(50%);
        `
    }[direction || 'e']

    return (
      <>
        <style>{`.tooltipped${id ? '-' + id : ''} {
                position: relative;
            }
            
            @media (min-width: 56em) {
                .tooltipped${id ? '-' + id : ''}:after {
                    background-color: rgba(31, 45, 61, 0.875);
                    border-radius: 0.5rem;
                    box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.0625),
                    0 4px 8px 0 rgba(0, 0, 0, 0.125);
                    color: #ffffff;
                    content: '${escapedText}';
                    font-family: $font-family;
                    font-size: 0.875rem;
                    font-weight: 500;
                    height: min-content;
                    letter-spacing: 0;
                    line-height: 1.375;
                    max-width: 16rem;
                    min-height: 1.25rem;
                    opacity: 0;
                    padding: 0.25rem 0.75rem;
                    pointer-events: none;
                    position: absolute;
                    right: 100%;
                    text-align: center;
                    transform: translateY(50%);
                    transition: 0.125s all ease-in-out;
                    width: max-content;
                    z-index: 1000000;
            
                }
            
                .tooltipped${id ? '-' + id : ''}:hover:after,
                .tooltipped${id ? '-' + id : ''}:active:after,
                .tooltipped${id ? '-' + id : ''}:focus:after {
                    opacity: 1;
                    z-index: 9000000;
                    backdrop-filter: blur(2px);
                }
            
                .tooltipped${id ? '-' + id : ''}:after {
                    ${directionalStyles}
                }
            }`}</style>

        {children}
      </>
    )
  }

type TooltipComponent = React.FC<{ children: any; text: any; id: any }> & {
  N: React.FC<{ children: any; text: any; id: any }>
  S: React.FC<{ children: any; text: any; id: any }>
  E: React.FC<{ children: any; text: any; id: any }>
  W: React.FC<{ children: any; text: any; id: any }>
}

const Tooltip = tooltip('e') as TooltipComponent
Tooltip.N = tooltip('n')
Tooltip.S = tooltip('s')
Tooltip.E = tooltip('e')
Tooltip.W = tooltip('w')

export { Tooltip }
export default Tooltip


================================================
FILE: components/flag.tsx
================================================
import theme from '../lib/theme'
import styled from '@emotion/styled'
import { css, keyframes } from '@emotion/react'
import Link from 'next/link'

const waveFlag = keyframes`
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(-5deg);
  }
`

const waveFlagScaled = keyframes`
  from {
    transform: scale(.875) rotate(0deg);
  }
  to {
    transform: scale(.875) rotate(-5deg);
  }
`

const scrolled = props =>
  props.scrolled
    ? css`
        transform: scale(0.875);
        height: 56px;
        &:hover,
        &:focus {
          animation: ${waveFlagScaled} 0.5s linear infinite alternate;
        }
      `
    : undefined

const Base = styled(Link)<{ uwu?: boolean }>`
  background-image: ${props =>
    props.uwu
      ? 'url(/stickers/hack-club-anime.png)'
      : 'url(https://assets.hackclub.com/flag-orpheus-top.svg)'};
  background-repeat: no-repeat;
  background-position: top left;
  background-size: contain;
  cursor: pointer;
  flex-shrink: 0;
  width: 112px;
  height: 48px;
  transition: ${3 / 16}s cubic-bezier(0.375, 0, 0.675, 1) transform;
  transform-origin: top left;
  @media (min-width: ${theme.breakpoints[1]}) {
    width: 172px;
    height: 64px;
  }
  &:hover,
  &:focus {
    animation: ${waveFlag} 0.5s linear infinite alternate;
  }
  @media (prefers-reduced-motion: reduce) {
    animation: none !important;
  }
  ${scrolled};
`

const Flag = props => <Base href="/" title="Homepage" {...props} />

export default Flag


================================================
FILE: components/flex-col.tsx
================================================
import { Flex } from 'theme-ui'

export default function FlexCol({ children, ...props }) {
  return <Flex sx={{ flexDirection: 'column', ...props }}>{children}</Flex>
}


================================================
FILE: components/footer.tsx
================================================
import React from 'react'
import styled from '@emotion/styled'
import { Box, Container, Grid, Heading, Link, Text } from 'theme-ui'
import NextLink from 'next/link'
import theme from '@hackclub/theme'
import Icon from './icon'
import { getGitSha, getGitShaShort } from '../lib/git-info'

const Base = styled(Box, { shouldForwardProp: prop => prop !== 'dark' })<{
  dark?: boolean
}>`
  background: ${props =>
    props.dark
      ? `${theme.colors.darker} radial-gradient(${theme.colors.black} 1px, transparent 1px)`
      : `${theme.colors.snow} url('/pattern.svg') repeat`};
  ${props =>
    props.dark &&
    `
      background-size: ${theme.space[4]}px ${theme.space[4]}px;
    `} @media print {
    display: none;
  }
`

const Logo = props => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    width="256"
    height="90"
    fill="#8492A6"
    viewBox="0 0 256 90"
    {...props}
  >
    <path d="M75.156 38.08l6.475 1.105s1.798-11.402-.224-10.199l-6.251 9.094zM204.85 34.495l2.161 5.06s5.237-2.106 4.619-4.915c-.537-2.442-3.098-1.496-5.641-.557h-.001c-.382.142-.764.282-1.138.412zM207.752 43.455s1.483 6.212 1.421 5.93c-.007-.093.397-.247 1.002-.477 2.014-.766 6.257-2.379 4.999-5.453-1.636-3.997-7.422 0-7.422 0z" />
    <path
      fillRule="evenodd"
      d="M7.205 89.303c-.022-2.227-.161-16.553 3.072-32.54 15.846-2.401 28.778.144 54.94 7.37 5.142 1.42 10.135 2.927 15.139 4.437 21.52 6.494 43.238 13.047 77.819 13.047 39.513 0 89.839-46.125 96.97-52.854.321-.303.07-.804-.37-.798a895.798 895.798 0 01-22.817-.006.484.484 0 01-.422-.707L241.991 6.9c.186-.36-.392-.91-.737-.696-10.403 6.44-68.291 38.655-125.701 11.127C62.987-7.874 36.693.801 29.405 4.381c.206-.647.195-1.355-.559-1.45-.953-.121-1.458.46-1.458.46-.955.738-11.701 20.409-18.91 41.665C1.272 66.313-.092 87.361.006 89.551h7.202c0-.049 0-.132-.002-.248zm33.522-73.187c-.647 3.657-1.888 9.939-4.497 18.056-5.42 12.948 3.823 10.836 6.47 5.457 1.569-2.97 3.182-6.194 3.182-6.194l8.307 3.185s-.669 3.783-1.353 6.912c-2.61 8.118 4.998 7.144 7.102 1.146.177-.583.477-1.518.856-2.697 1.62-5.045 4.672-14.553 5.648-20.073 1.814-4.357-4.395-8.336-7.205-1.295-1.502 2.593-3.941 8.27-3.941 8.27s-6.857-2.534-6.938-2.81c-.14-.362.021-1.024.212-1.812.177-.727.38-1.562.397-2.37-.418-11.655-7.37-10.693-8.24-5.775zm36.6 9.076c2.114-4.209 4.542-4.915 6.347-4.723.779.065 1.838 1.648 2.648 3.17 2.651 10.02-2.1 28.448-2.94 29.686-2.892 4.671-7.967 3.788-6.04-1.259.901-3.066 1.865-5.852 1.865-5.852l-6.568-.734c-5.162 10.028-9.802 5.829-7.128 1.497 2.861-5.074 8.956-16.183 11.816-21.785zm33.437 10.102c.857-2.414-.924-7.875-7.149-6.964-9.016.065-12.136 15.862-12.136 15.862s-1.498 7.65.867 12.865c1.971 4.611 6.52 5.007 8.041 5.139.137.012.25.022.334.032 5.917-1.78 3.891-5.722 2.879-5.849-.221-.011-.456-.014-.701-.018-1.178-.015-2.578-.034-3.746-.988-2.393-1.928-1.967-6.824-1.447-9.457 1.224-4.429 3.918-13.223 8.213-11.07 2.577 3.293 4.386 1.78 4.845.448zm5.93-.406c-.608 1.855-.691 3.748-.785 5.895-.151 3.458-.332 7.576-2.777 13.261-.68 1.62-2.071 4.212-2.9 5.756-.323.602-.561 1.045-.638 1.21-2.196 4.16 2.263 6.611 7.175-.657 1.19-1.664 2.501-5.919 2.501-5.919l2.137-.24s1.867 8.216 2.296 11.736c.46 3.396 6.476 5.328 6.564-1.338-.215-2.285-1.011-5.374-2.509-9.298 0 0-.978-2.874-1.925-3.247 0 0 6.713-6.677 7.353-9.268.67-2.714-.552-4.6-5.802-.172-5.249 4.428-5.858 5.846-5.858 5.846s1.248-5.583 1.123-9.812c.456-4.473-4.584-7.73-5.955-3.753zm33.811 8.412c-2.253 2.233-3.67 6.425-3.512 12.767.314 9.466 4.236 14.906 10.933 13.822 6.697-1.083 5.12-5.915 4.503-6.075-.088-.022-.163-.059-.244-.098-.376-.181-.861-.415-3.12.435-2.746 1.032-4.814-.173-6.545-4.375-1.144-2.843-1.764-8.367.302-11.452.537-.795 1.051-1.088 1.378-1.275l.075-.042.039-.024.019-.011c1.235-.753 2.5-.023 2.717.166 3.458 2.504 4.135-.27 2.899-2.736-2.44-3.446-5.681-4.15-9.444-1.102zm14.971.143c-.033-3.593 3.677-6.363 4.981 1.672.926 2.985 1.185 7.574 1.384 11.111.147 2.614.262 4.655.59 5.05.773.93 6.526-.368 8.084-.892 1.558-.524 4.428.164 3.78 1.724-.423 1.281-1.467 1.63-2.02 1.814-.134.045-.239.08-.3.116-.309.187-13.313 4.042-13.796 1.475-.342-1.815-.457-2.938-.667-4.986h-.001c-.087-.848-.19-1.854-.332-3.133-.178-1.594-.448-3.404-.721-5.234h-.001c-.475-3.187-.961-6.434-.981-8.717zm15.594-3.216c-.282-2.598 2.367-4.185 3.927-1.396.534.974 1.107 3.415 1.752 6.165.788 3.354 1.682 7.167 2.746 9.337 1.06 1.599 3.243 1.887 4.271.42 1.214-2.218.338-7.759-.413-12.204a62.31 62.31 0 00-.479-1.777v-.001c-.361-1.286-.655-2.334-.634-3.168.466-4.003 3.677-3.055 5.175 1.049 1.249 4.572 2.551 11.959 1.898 14.585l-.074.3c-.604 2.447-1.329 5.39-4.442 6.131-.842.185-7.855 1.196-10.321-6.477l-.757-2.562c-1.783-6.024-2.399-8.103-2.649-10.402zm21.992-8.576c4.312-2.607 7.547-3.502 10.075-2.589 1.48.91 2.436 3.407 2.037 5.558-.461 1.87-1.231 3.396-1.231 3.396 2.559.258 4.432 2.811 4.918 6.153.487 3.341-2.661 6.486-8.515 8.433-1.972.556-4.067.549-4.16-.138-.063-1.341-5.033-17.326-5.033-17.326-.015-.096-.034-.193-.053-.29-.175-.892-.37-1.884 1.962-3.197z"
      clipRule="evenodd"
    />
  </svg>
)

const Service = ({ href, icon, name = '', ...props }) => (
  <Link
    target="_blank"
    rel="noopener me"
    href={href}
    title={`Hack Club on ${name ? name : icon}`}
    {...props}
  >
    <Icon glyph={icon} />
  </Link>
)

const Footer = ({
  dark = false,
  email = 'team@hackclub.com',
  children = undefined,
  ...props
}) => (
  <Base
    color={dark ? 'muted' : 'slate'}
    py={[4, 5]}
    dark={dark}
    sx={{ textAlign: 'left' }}
    as="footer"
    {...props}
  >
    <Container px={[3, null, 4]}>
      {children}
      <Grid
        as="article"
        gap={[2, 4]}
        columns={[2, 3, 4]}
        sx={{
          px: 0,
          a: {
            textDecoration: 'none',
            color: 'muted',
            transition: '0.125s color ease-in-out',
            ':hover,:focus': { color: 'slate', textDecoration: 'underline' }
          },
          '> div > a': {
            display: 'block',
            mb: 2
          },
          'h2,p': { color: 'muted' },
          h2: { fontSize: 3 },
          'a,p': { fontSize: 2 }
        }}
      >
        <Box>
          <Heading as="h2" variant="subheadline" mb={3}>
            Hack&nbsp;Club
          </Heading>
          <Link as={NextLink} href="/philosophy">
            Philosophy
          </Link>
          <Link as={NextLink} href="/team">
            Our Team & Board
          </Link>
          <Link as={NextLink} href="/jobs">
            Jobs
          </Link>
          <Link as={NextLink} href="/brand">
            Brand Guide
          </Link>
          <Link as={NextLink} href="/press">
            Press Inquiries
          </Link>
          <Link as={NextLink} href="/philanthropy">
            Donate
          </Link>
          <Link as={NextLink} href="/imprint">
            Imprint
          </Link>
        </Box>
        <Box>
          <Heading as="h2" variant="subheadline" mb={3}>
            Resources
          </Heading>
          <Link href="https://events.hackclub.com/">Community Events</Link>
          <Link href="https://jams.hackclub.com/">Jams</Link>
          <Link href="https://toolbox.hackclub.com/">Toolbox</Link>
          <Link href="https://hackclub.com/map">Clubs Map</Link>
          <Link href="https://hackclub.com/conduct/">Code of Conduct</Link>
          <Link href="https://hackclub.com/privacy/">Privacy & Terms</Link>
        </Box>
        <Box sx={{ gridColumn: ['span 2', 'span 1'] }}>
          <Box
            sx={{ display: 'flex', alignItems: 'end', flexDirection: 'row' }}
          >
            <Logo aria-label="Hack Club logo" width={128} height={45} />
            <Text as="span" color="muted" sx={{ marginBottom: '-.5em' }}>
              <Link
                sx={{ fontSize: 'inherit' }}
                href={`https://github.com/hackclub/site/commit/${getGitSha()}`}
                target="_blank"
                rel="noopener noreferrer"
              >
                <code style={{ fontFamily: 'monospace', fontSize: '13px' }}>
                  {getGitShaShort()}
                </code>
              </Link>
            </Text>
          </Box>
          <Grid
            columns={[8, 4]}
            gap={2}
            sx={{
              alignItems: 'center',
              ml: -1,
              my: 3,
              maxWidth: [null, 192],
              svg: { fill: 'currentColor', width: 32, height: 32 },
              a: {
                lineHeight: 0,
                mb: 0,
                transition:
                  'transform .125s ease-in-out, color .125s ease-in-out',
                ':hover,:focus': { transform: 'scale(1.125)' }
              },
              placeItems: 'center'
            }}
          >
            <Service
              href="https://slack.hackclub.com"
              icon="slack-fill"
              name="Slack"
              target="_self"
            />
            <Service
              href="https://twitter.com/hackclub"
              icon="twitter"
              name="Twitter"
            />
            <Service
              href="https://github.com/hackclub"
              icon="github"
              name="GitHub"
            />
            <Service
              href="https://figma.com/@hackclub"
              icon="figma-fill"
              name="Figma"
            />
            <Service
              href="https://social.dino.icu/@hackclub"
              icon="mastodon"
              name="Mastodon"
            />
            <Service
              href="https://www.youtube.com/c/HackClubHQ"
              icon="youtube"
              name="YouTube"
            />
            <Service
              href="https://www.instagram.com/starthackclub"
              icon="instagram"
              name="Instagram"
            />
            <Service href={`mailto:${email}`} icon="email-fill" name="Email" />
          </Grid>
          <Text my={2}>
            <Link href="tel:1-855-625-4225">1-855-625-HACK</Link>
            <br />
            <Text as="span" color="muted">
              (call toll-free)
            </Text>
          </Text>
        </Box>
      </Grid>
      <Text as="p" variant="caption" sx={{ mt: 3 }}>
        © {new Date().getFullYear()} Hack&nbsp;Club. 501(c)(3) nonprofit (EIN:
        81-2908499)
      </Text>
    </Container>
  </Base>
)

export default Footer


================================================
FILE: components/force-theme.ts
================================================
import { useEffect } from 'react'
import { useColorMode } from 'theme-ui'

const ForceTheme = ({ theme }) => {
  const [_colorMode, setColorMode] = useColorMode()
  useEffect(() => {
    setColorMode(theme)
  }, [setColorMode, theme])
  return null
}

export default ForceTheme


================================================
FILE: components/hackathons/features/marketing.tsx
================================================
/** @jsxImportSource theme-ui */
import { Button, Box, Container, Heading, Text } from 'theme-ui'
import usePrefersMotion from '../../../lib/use-prefers-motion'
import useHasMounted from '../../../lib/use-has-mounted'
import Link from 'next/link'

const Content = () => (
  <Container
    sx={{
      zIndex: 999,
      py: 6,
      color: 'white',
      'h2,p': { textShadow: 'text' },
      textAlign: [null, 'center'],
      position: 'relative',
      overflow: 'hidden'
    }}
  >
    <Text as="p" variant="eyebrow" sx={{ color: 'white', opacity: 0.75 }}>
      hackathons.hackclub.com
    </Text>
    <Heading as="h2" variant="title">
      Spread the word about your hackathon.
    </Heading>
    <Text as="p" variant="lead" sx={{ maxWidth: 'copyPlus', mx: 'auto' }}>
      Reach hackers worldwide by listing your event on hackathons.hackclub.com,
      the first Google search result for "high school hackathons." Your event
      will also be emailed to a network of high school hackers in your area.
    </Text>
    <Link href="https://hackathons.hackclub.com">
      <Button
        variant="ctaLg"
        sx={{
          backgroundImage: (theme: any) => theme.util.gx('yellow', 'red')
        }}
      >
        Add your hackathon →
      </Button>
    </Link>
  </Container>
)

const Cover = () => (
  <Box
    sx={{
      position: 'absolute',
      bottom: 0,
      top: 0,
      left: 0,
      right: 0,
      backgroundImage: (t: any) => t.util.gx('slate', 'black'),
      opacity: 0.7,
      zIndex: 1
    }}
  />
)

const Static = ({
  img = 'https://cloud-ateizv565-hack-club-bot.vercel.app/0screen_shot_2022-07-27_at_2.57.41_pm.png'
}) => (
  <Box
    as="section"
    id="slack"
    sx={{
      position: 'relative',
      overflow: 'hidden',
      backgroundImage: `url(${img})`,
      backgroundSize: 'cover'
    }}
  >
    <Cover />
    <Content />
  </Box>
)

const Marketing = () => {
  const hasMounted = useHasMounted()
  const prefersMotion = usePrefersMotion()
  if (hasMounted && prefersMotion) {
    return (
      <Box
        as="section"
        id="slack"
        sx={{ overflow: 'hidden', position: 'relative' }}
      >
        <Box
          as="video"
          autoPlay
          muted
          loop
          playsInline
          poster="https://cloud-ateizv565-hack-club-bot.vercel.app/0screen_shot_2022-07-27_at_2.57.41_pm.png"
          duration={2000}
          sx={{
            position: 'absolute',
            bottom: 0,
            top: 0,
            left: 0,
            right: 0,
            height: '100%',
            zIndex: -1,
            width: '100vw',
            objectFit: 'cover'
          }}
        >
          <source
            src="https://cloud-55tm7eveg-hack-club-bot.vercel.app/0screen_recording_2022-07-27_at_2.48.43_pm.mp4"
            type="video/mp4; codecs=hevc"
          />
          <source
            src="https://cloud-r9u5vfqcv-hack-club-bot.vercel.app/0screen_recording_2022-07-27_at_2.48.43_pm.webm"
            type="video/webm; codecs=vp9,opus"
          />
          <source
            src="https://cloud-r9u5vfqcv-hack-club-bot.vercel.app/1screen_recording_2022-07-27_at_2.48.43_pm.mp4"
            type="video/quicktime"
          />
        </Box>
        <Cover />
        <Content />
      </Box>
    )
  } else {
    return <Static />
  }
}

export default Marketing


================================================
FILE: components/hackathons/features/slack.tsx
================================================
/** @jsxImportSource theme-ui */
import { Button, Box, Container, Heading, Text, Link } from 'theme-ui'
import usePrefersMotion from '../../../lib/use-prefers-motion'
import useHasMounted from '../../../lib/use-has-mounted'
import NextLink from 'next/link'

const Content = () => (
  <Container
    sx={{
      zIndex: 999,
      py: 6,
      color: 'white',
      'h2,p': { textShadow: 'text' },
      textAlign: [null, 'center'],
      position: 'relative',
      overflow: 'hidden'
    }}
  >
    <Text as="p" variant="eyebrow" sx={{ color: 'white', opacity: 0.75 }}>
      The Hack Club Community
    </Text>
    <Heading as="h2" variant="title">
      A hackathon organizer's{' '}
      <Text
        as="span"
        sx={{
          borderRadius: 'default',
          px: 2,
          mx: [-2, 0],
          whiteSpace: 'nowrap',
          color: 'currentColor',
          bg: 'green'
        }}
      >
        best friend
      </Text>
      .
    </Heading>
    <Text as="p" variant="lead" sx={{ maxWidth: 'copyPlus', mx: 'auto' }}>
      The{' '}
      <Box
        as="span"
        sx={{
          bg: 'rgb(245, 233, 181, .3)',
          px: 1,
          borderRadius: 5
        }}
      >
        <Link
          href="https://hackclub.slack.com/archives/C03QSGGCJN7"
          sx={{ textDecoration: 'none', color: 'currentColor' }}
          target="_blank"
        >
          #hackathon-organizers
        </Link>
      </Box>{' '}
      channel is where teenagers around the world ask questions and share their
      own hackathon organizing experiences—from finding a venue to securing
      sponsorships to ordering food.
    </Text>
    <NextLink href="https://slack.hackclub.com">
      <Button
        variant="ctaLg"
        sx={{
          background: 'linear-gradient(-132deg, #338eda 14%, #33d6a6 82%)'
        }}
      >
        Join us on Slack →
      </Button>
    </NextLink>
  </Container>
)

const Cover = () => (
  <Box
    sx={{
      position: 'absolute',
      bottom: 0,
      top: 0,
      left: 0,
      right: 0,
      backgroundImage: (t: any) => t.util.gx('cyan', 'purple'),
      opacity: 0.825,
      zIndex: 1
    }}
  />
)

const Static = ({
  // screenshot of messages from #hackathon-organizers
  img = 'https://cloud-8611bon87-hack-club-bot.vercel.app/0screen_shot_2022-08-05_at_2.27.38_pm.png'
}) => (
  <Box
    as="section"
    id="slack"
    sx={{
      position: 'relative',
      overflow: 'hidden',
      backgroundImage: `url(${img})`,
      backgroundSize: 'cover'
    }}
  >
    <Cover />
    <Content />
  </Box>
)

const Slack = () => {
  const hasMounted = useHasMounted()
  const prefersMotion = usePrefersMotion()
  if (hasMounted && prefersMotion) {
    return (
      <Box
        as="section"
        id="slack"
        sx={{ overflow: 'hidden', position: 'relative' }}
      >
        <Box
          as="video"
          autoPlay
          muted
          loop
          playsInline
          // screenshot of messages from #hackathon-organizers
          poster="https://cloud-iwkoq2544-hack-club-bot.vercel.app/0screen_shot_2022-07-30_at_9.03.43_am.png"
          duration={2000}
          sx={{
            position: 'absolute',
            bottom: 0,
            top: 0,
            left: 0,
            right: 0,
            height: '100%',
            zIndex: -1,
            width: '100vw',
            objectFit: 'cover'
          }}
        >
          <source
            src="https://cloud-hsc3k1am6-hack-club-bot.vercel.app/0screen_recording_2022-08-03_at_9.50.26_am.mp4"
            type="video/mp4; codecs=hevc"
          />
          <source
            src="https://cloud-azjxx4vqu-hack-club-bot.vercel.app/0have-finally-figured-it-out-hell-yeah.webm"
            type="video/webm; codecs=vp9,opus"
          />
          <source
            src="https://cloud-hsc3k1am6-hack-club-bot.vercel.app/0screen_recording_2022-08-03_at_9.50.26_am.mp4"
            type="video/quicktime"
          />
        </Box>
        <Cover />
        <Content />
      </Box>
    )
  } else {
    return <Static />
  }
}

export default Slack


================================================
FILE: components/hackathons/keep-exploring.tsx
================================================
import { Box, Heading, Button, Text, Grid, Container } from 'theme-ui'
import Link from 'next/link'
import Icon from '../icon'

export default function KeepExploring() {
  return (
    <>
      <Box
        sx={{
          backgroundImage: (t: any) => t.util.gx('orange', 'red'),
          margin: 'auto',
          maxWidth: '90%',
          my: 4,
          borderRadius: 8,
          color: 'white',
          textAlign: 'center',
          py: 5
        }}
      >
        <Heading
          as="h1"
          sx={{
            fontSize: 6,
            mb: 3,
            display: 'flex',
            justifyContent: 'center',
            alignContent: 'center'
          }}
        >
          Keep exploring{' '}
          <Icon
            glyph="explore"
            size={70}
            sx={{ display: ['none', 'flex', 'flex'] }}
          />
        </Heading>
        <Link href="https://slack.hackclub.com">
          <Button
            sx={{
              bg: 'white',
              color: 'red',
              mr: [0, 3],
              mb: [3, 0],
              fontSize: [2, 3]
            }}
          >
            Meet other hackers
          </Button>
        </Link>

        <Link href="https://hackathons.hackclub.com">
          <Button sx={{ bg: 'white', color: 'red', fontSize: [2, 3] }}>
            Discover more hackathons
          </Button>
        </Link>
      </Box>

      <Container>
        <Grid
          columns={[null, '1fr 1fr']}
          my={[3, 5]}
          sx={{ maxWidth: 'copyUltra', mx: 'auto' }}
        >
          <Heading as="h3" variant="headline" sx={{ fontSize: [4, 5], mb: 0 }}>
            Behind the scenes...
          </Heading>
          <Text
            as="p"
            variant="lead"
            sx={{ mt: 0, a: { variant: 'styles.a', color: 'blue' } }}
          >
            Teenagers organize hackathons like{' '}
            <a
              href="https://assemble.hackclub.com"
              target="_blank"
              rel="noreferrer"
            >
              Assemble
            </a>{' '}
            &{' '}
            <a href="https://windyhacks.com" target="_blank" rel="noreferrer">
              Windy&nbsp;City&nbsp;Hacks
            </a>
            . The&nbsp;hack’s the limit.
          </Text>
        </Grid>
      </Container>
    </>
  )
}


================================================
FILE: components/hackathons/landing.tsx
================================================
import { Box, Button, Heading, Text, Card } from 'theme-ui'
import { Fade } from '../react-reveal-compat'
import ScrollHint from '../scroll-hint'
import Image from 'next/image'
import Icon from '../icon'

export default function Landing() {
  return (
    <>
      <Slide>
        <BlueGradientFilter />
        <Box
          sx={{
            position: 'absolute',
            flexDirection: 'column',
            justifyContent: 'center',
            bottom: 140,
            mx: 'auto',
            width: '100%'
          }}
        >
          <Box
            sx={{
              zIndex: 999,
              paddingTop: 96
            }}
          >
            <Fade duration={625} bottom>
              <Card
                variant="translucent"
                sx={{
                  variant: 'layout.container',
                  maxWidth: [null, 700, 1000],
                  borderRadius: 'extra',
                  p: [3, 4],
                  position: 'relative',
                  color: 'black'
                }}
              >
                <Button
                  as="a"
                  {...({ target: '_blank' } as any)}
                  variant="cta"
                  href="https://hackathons.hackclub.com"
                  sx={{
                    backgroundImage: (t: any) => t.util.gx('yellow', 'pink'),
                    position: 'absolute',
                    right: [0, -3],
                    top: -3,
                    transform: [
                      'translateY(-50%) rotate(8deg)',
                      'translateX(15%) rotate(12deg)'
                    ],
                    fontSize: [2, 3],
                    display: ['none', 'inline', 'inline']
                  }}
                >
                  Looking for hackathons?{' '}
                  <Icon glyph="external" size={30} sx={{ pl: 1 }} />
                </Button>

                <Heading
                  as="h2"
                  variant="title"
                  sx={{
                    color: 'black',
                    span: { color: 'white', display: 'block' }
                  }}
                >
                  Welcome to the{' '}
                  <Text
                    as="span"
                    variant="ultratitle"
                    sx={{
                      WebkitTextStroke: 'currentColor',
                      WebkitTextStrokeWidth: '2px',
                      WebkitTextFillColor: '#33D6A6',
                      whiteSpace: [null, null, 'nowrap']
                    }}
                  >
                    high school hackathon.
                  </Text>
                </Heading>
                <Text
                  as="p"
                  variant="subtitle"
                  sx={{
                    mt: 3,
                    fontSize: [2, 3]
                  }}
                >
                  <strong>
                    It's not an extracurricular or a club. It's not a class or a
                    lecture.
                  </strong>{' '}
                  Hackathons are a place to build things for fun and meet others
                  doing the same.
                </Text>
              </Card>
            </Fade>
          </Box>
          <br />
          <br />
          <ScrollHint />
        </Box>
      </Slide>
    </>
  )
}

function Slide({ children }) {
  return (
    <Box
      style={{
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'end',
        backgroundColor: '#000000',
        boxShadow: 'inset 0 0 4rem 1rem rgba(0, 0, 0, 0.5)',
        backgroundPosition: 'center',
        backgroundSize: 'cover',
        width: '100%',
        minHeight: '100vh',
        position: 'relative'
      }}
    >
      <Image
        // public/hackathons/assemble.JPG
        src="/hackathons/assemble.JPG"
        alt="Dark room with a stage and students sitting below"
        // placeholder="blur"
        priority
        fill
        sizes="100vw"
        style={{
          objectFit: 'cover'
        }}
      />
      {children}
    </Box>
  )
}

function BlueGradientFilter() {
  return (
    <Box
      style={{
        backgroundImage:
          'linear-gradient(to bottom,rgba(51, 142, 218, .9),rgba(51, 142, 218, 0.7) 35%, rgba(91, 192, 222, 0.2) 100%)',
        height: '100vh',
        left: '0',
        right: '0',
        position: 'absolute',
        zIndex: '0'
      }}
    ></Box>
  )
}


================================================
FILE: components/hackathons/overview.tsx
================================================
import { Box, Heading, Container, Text, Grid } from 'theme-ui'

export default function Overview() {
  return (
    <>
      <Box as="section" sx={{ py: [4, 5], color: 'black' }}>
        <Container sx={{ width: '95vw' }}>
          <Heading
            sx={{
              fontSize: [36, 50, 50, 50, 48],
              mb: 3,
              color: 'purple'
            }}
          >
            A hackathon is a social coding marathon where teenagers{' '}
            <Highlight>come together</Highlight> to{' '}
            <Highlight>build projects</Highlight> for a weekend and{' '}
            <Highlight>share them with the world</Highlight>.
          </Heading>
          <Grid columns={[null, null, 2]} gap={[3, 4]}>
            <Text as="p" variant="subtitle">
              <Box
                as="span"
                sx={{ display: 'block', color: 'blue', fontSize: 28, mb: 2 }}
              >
                The best way to learn is by <b>building</b>.
              </Box>
              A hackathon is a space that helps give makers everything they need
              to start building–mentors, collaborators, inspiration, and a goal
              to work towards. Hackers will leave a hackathon with a project of
              their own, ready and excited to keep hacking once they get home.
            </Text>
            <Text as="p" variant="subtitle">
              <Box
                as="span"
                sx={{ display: 'block', color: 'green', fontSize: 28, mb: 2 }}
              >
                We're at our best when we're <b>making</b>.
              </Box>
              Hack Club is a global community of thousands of high school
              makers. We're organizers, coders, hackers, painters, engineers,
              musicians, writers, volunteers. We make things. We want others to
              make things too.
            </Text>
          </Grid>
          <Grid columns={[null, null, 2]} gap={[3, 4]} mt={4}>
            <iframe
              width="100%"
              height="300px"
              src="https://www.youtube.com/embed/PnK4gzO6S3Q"
              title="YouTube video player"
              style={{ border: 0 }}
              allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
              allowFullScreen
            ></iframe>
            <iframe
              width="100%"
              height="300px"
              src="https://www.youtube.com/embed/KLx4NZZPzMc"
              title="YouTube video player"
              style={{ border: 0 }}
              allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
              allowFullScreen
            ></iframe>
          </Grid>
        </Container>
      </Box>
    </>
  )
}

function Highlight({ children }) {
  return (
    <Text
      as="span"
      sx={{
        bg: 'yellow',
        borderRadius: 'default',
        px: 1,
        color: '#5d114c',
        lineHeight: '1.3'
      }}
    >
      {children}
    </Text>
  )
}


================================================
FILE: components/hackathons/recap.tsx
================================================
/** @jsxImportSource theme-ui */
import { Card, Box, Heading, Grid, Text } from 'theme-ui'
import Stage from '../stage'

export default function Recap() {
  return (
    <>
      <Box as="header" sx={{ textAlign: [null, 'center'], pt: [4, 5] }}>
        <Text as="p" variant="eyebrow">
          Get started today
        </Text>
        <Heading as="h2" variant="title">
          Resources so you can organize an{' '}
          <Text
            as="span"
            sx={{
              borderRadius: 'default',
              px: 2,
              mx: [-2, 0],
              bg: 'rgb(91, 255, 205)',
              color: '#095365',
              display: 'inline-block',
              whiteSpace: ['wrap', 'nowrap']
            }}
          >
            amazing
          </Text>{' '}
          hackathon.
        </Heading>
      </Box>
      <Grid
        pt={[3, 4]}
        pb={[5, 6]}
        gap={[4, 3, 4]}
        columns={[1, null, 2]}
        sx={{
          textAlign: 'left',
          '> a, > div': {
            borderRadius: 'extra',
            boxShadow: 'elevated',
            px: [3, null, 4],
            py: [4, null, 5]
          },
          span: {
            boxShadow:
              '-2px -2px 6px rgba(255,255,255,0.125), inset 2px 2px 6px rgba(0,0,0,0.1), 2px 2px 8px rgba(0,0,0,0.0625)'
          },
          svg: { fill: 'currentColor' }
        }}
      >
        <Card
          variant="interactive"
          as="a"
          href="https://slack.hackclub.com"
          sx={{
            background: 'linear-gradient(-32deg, #6f31b7 14%, #fb558e 82%)',
            color: 'white',
            svg: { color: '#fb558e' }
          }}
        >
          <Stage
            icon="slack"
            color="white"
            name="Slack community"
            desc="Chat in Slack for support with organizing your hackathon, from finding a venue to marketing your event."
          />
        </Card>
        <Card
          variant="interactive"
          as="a"
          href="https://hackathons.hackclub.com/"
          sx={{
            background:
              'linear-gradient(32deg, rgba(51, 142, 218, 0.9) 0%, rgba(51, 214, 166, 0.9) 100%)',
            color: 'white',
            svg: { color: 'rgb(51, 142, 218)' }
          }}
        >
          <Stage
            icon="event-check"
            color="white"
            name="Marketing"
            desc="Get your event listed on Google's front page, emailed to nearby teens, and seen by our hackathon calendar's 3K+ monthly users."
          />
        </Card>
      </Grid>
    </>
  )
}


================================================
FILE: components/hackathons/scrolling-hackathons.tsx
================================================
/** @jsxImportSource theme-ui */
import Ticker from 'react-ticker'
import {
  Box,
  Card,
  Text,
  Heading,
  Badge,
  Container,
  Image,
  Link
} from 'theme-ui'
import { useState } from 'react'
import { keyframes } from '@emotion/react'
import Tilt from '../tilt'
import PageVisibility from 'react-page-visibility'
import { formatAddress } from '../../lib/helpers'

export default function ScrollingHackathons({
  eventData,
  mode,
  title,
  ...props
}) {
  const [pageIsVisible, setPageIsVisible] = useState(true)
  const handleVisibilityChange = isVisible => {
    setPageIsVisible(isVisible)
  }

  return (
    <>
      {title ? (
        <Container>
          <Heading
            sx={{
              fontSize: [36, 64],
              color: 'black',
              textAlign: 'center',
              maxWidth: ['95vw', '66vw'],
              margin: 'auto',
              mt: 4
            }}
          >
            Join other high-schoolers at an upcoming hackathon.
          </Heading>
          <Box
            sx={{
              maxWidth: ['95vw', '66vw'],
              margin: 'auto',
              display: 'flex',
              justifyContent: 'center',
              alignItems: 'center',
              mb: 2
            }}
          >
            <Text sx={{ display: ['none', 'flex'], alignItems: 'center' }}>
              <Dot />
            </Text>
            <Text
              variant="lead"
              sx={{ color: 'muted', mr: 2, textAlign: 'center' }}
            >
              from{' '}
              <Link
                href="https://hackathons.hackclub.com"
                sx={{ color: 'currentcolor' }}
              >
                hackathons.hackclub.com
              </Link>
              , last updated just now.
            </Text>
          </Box>
        </Container>
      ) : (
        <></>
      )}
      <PageVisibility onChange={handleVisibilityChange}>
        {pageIsVisible && (
          <Ticker mode={mode || 'string'} {...props}>
            {() => (
              <Box as="div" sx={{ display: 'flex', py: 3 }}>
                {eventData.map((event: any) => (
                  <EventCard key={event.website} {...event} />
                ))}
              </Box>
            )}
          </Ticker>
        )}
      </PageVisibility>
    </>
  )
}

const flashing = keyframes({
  from: { opacity: 0 },
  '50%': { opacity: 1 },
  to: { opacity: 0 }
})

function Dot() {
  return (
    <Text
      sx={{
        bg: 'green',
        color: 'white',
        borderRadius: 'circle',
        display: 'inline-block',
        lineHeight: 0,
        width: '.5em',
        height: '.5em',
        marginRight: '.4em',
        marginBottom: '.12em',
        animationName: `${flashing}`,
        animationDuration: '3s',
        animationTimingFunction: 'ease-in-out',
        animationIterationCount: 'infinite'
      }}
    />
  )
}

type EventCardProps = {
  name: string
  website: string
  start: string
  end: string
  city?: string
  state?: string
  country?: string
  countryCode?: string
  banner: string
  logo?: string
  virtual?: boolean
  hybrid?: boolean
  footer?: React.ReactNode
}

function EventCard({
  name,
  website,
  start,
  end,
  city,
  state,
  country,
  countryCode,
  banner,
  logo,
  virtual,
  hybrid,
  footer
}: EventCardProps) {
  return (
    <Tilt>
      <Card
        as="a"
        href={website}
        target="_blank"
        rel="noopener noreferrer"
        itemScope
        itemType="http://schema.org/Event"
        sx={{
          display: 'flex',
          flexDirection: 'column',
          px: 4,
          mx: 4,
          borderRadius: 'extra',
          width: '400px',
          height: '200px',
          textDecoration: 'none',
          color: 'white'
        }}
        style={{
          backgroundImage: `linear-gradient(rgba(0,0,0,0) 0%, rgba(0,0,0,0.375) 75%), url('${banner}')`,
          textAlign: 'center',
          backgroundSize: 'cover'
        }}
      >
        <Badge
          as="span"
          itemType="VirtualLocation"
          sx={{
            position: 'absolute',
            top: 16,
            right: 16,
            bg: 'snow',
            color: virtual ? 'red' : hybrid ? 'orange' : 'blue',
            fontSize: 'inherit',
            textShadow: 'none',
            borderRadius: 5
          }}
        >
          {virtual ? 'Online' : hybrid ? 'Hybrid' : 'In-Person'}
        </Badge>

        {logo && (
          <Image
            src={logo}
            alt={`${name} logo`}
            loading="lazy"
            sx={{
              minWidth: 64,
              height: 64,
              objectFit: 'contain',
              borderRadius: 'default',
              mt: 'auto'
            }}
          />
        )}

        <Heading
          variant="headline"
          as="h3"
          itemProp="name"
          sx={{
            fontSize: [3, 4],
            mt: 2,
            mb: 3,
            overflowWrap: 'anywhere',
            width: '100%',
            color: 'white',
            textDecoration: 'none'
          }}
        >
          {name}
        </Heading>
        <Box
          as="footer"
          sx={{
            mt: 'auto',
            mb: 0,
            width: '100%',
            opacity: 0.875
          }}
        >
          {footer ? (
            footer
          ) : (
            <>
              <Text
                as="span"
                itemProp="location"
                itemScope
                itemType="http://schema.org/Place"
              >
                {!virtual && (
                  <span itemProp="address">
                    {formatAddress(city, state, country, countryCode)}
                  </span>
                )}
              </Text>
            </>
          )}
        </Box>
        <Box sx={{ display: 'none' }}>
          <span itemProp="eventAttendanceMode">
            {virtual
              ? 'https://schema.org/OnlineEventAttendanceMode'
              : 'https://schema.org/OfflineEventAttendanceMode'}
          </span>
          <span itemProp="url">{website}</span>
          <span itemProp="startDate" content={start}>
            {start}
          </span>
          <span itemProp="endDate" content={end}>
            {end}
          </span>
        </Box>
      </Card>
    </Tilt>
  )
}


================================================
FILE: components/icon.tsx
================================================
import React from 'react'
import Icon from '@hackclub/icons'

export default function IconComponent(props: any): React.ReactElement {
  return <Icon {...props} />
}


================================================
FILE: components/index/cards/beest.tsx
================================================
/** @jsxImportSource theme-ui */
import CardModel from './card-model'
import { Box, Image, Text } from 'theme-ui'
import { keyframes } from '@emotion/react'

const slideIn = keyframes({
  from: { transform: 'translateX(0)' },
  to: { transform: 'translateX(-70%)' }
})

export default function Beest() {
  return (
    <CardModel
      color="black"
      sx={{
        background: '#A7C1D6',
        backgroundImage:
          'url(https://cdn.hackclub.com/019d88c4-02ec-7b2a-844a-02dcb9f02b99/beestbg.webp)',
        backgroundSize: 'cover',
        backgroundPosition: 'bottom',
        borderRadius: '16px',
        paddingTop: '3em !important',
        paddingBottom: '3em !important',
        position: 'relative',
        overflow: 'hidden'
      }}
      position={[null, 'bottom', 'bottom']}
      visible={true}
    >
      <Image
        alt="strandbeest"
        src="https://cdn.hackclub.com/019d87ae-ead2-7b25-8d39-2730ac702452/beest-sticker.webp"
        sx={{
          position: 'absolute',
          bottom: '45px',
          right: '-170px',
          maxWidth: '21em',
          zIndex: 1,
          display: ['none', 'none', 'none', 'block'],

          // Explicitly handle the animation
          '@supports (animation-timeline: scroll(root))': {
            animationName: `${slideIn}`,
            animationTimingFunction: 'ease-in-out',
            animationFillMode: 'both',
            animationTimeline: 'scroll(root)',
            animationRange: 'entry 10% contain 50%'
          },

          // Firefox Fallback
          '@supports not (animation-timeline: scroll(root))': {
            right: '10px',
            transform: 'none'
          }
        }}
      />
      <Box
        sx={{
          paddingInline: '2em',
          maxWidth: ['100%', '100%', '100%', '75%'],
          display: 'flex',
          flexDirection: 'column',
          justifyContent: 'space-around',
          height: '100%',
          zIndex: 2,
          position: 'relative'
        }}
      >
        <Image
          alt="beest"
          src="https://cdn.hackclub.com/019d87e3-965d-75b0-83dd-c73469f47911/beest-cropped.png"
          sx={{
            maxWidth: ['80%', '60%', '50%', '45%']
          }}
        />

        <Text
          variant="subtitle"
          sx={{
            color: '#4C483C',
            fontSize: ['18px', '24px'],
            fontFamily: 'system-ui, sans-serif',
            fontWeight: '600',
            lineHeight: 1.3,
            mb: 5,
            display: 'block',
            textAlign: 'left'
          }}
        >
          Spend 40 hours building projects, fly to the Netherlands, build a
          mechanical animal!
        </Text>
        <Box
          sx={{
            height: '48px'
          }}
        >
          <Box
            as="a"
            href="https://beest.hackclub.com/"
            sx={{
              display: 'inline-block',
              padding: '8px 22px',
              background: '#c48382',
              color: '#fff',
              fontFamily: '"Courier New", monospace',
              fontSize: '14px',
              fontWeight: 700,
              letterSpacing: '0.04em',
              textDecoration: 'none',
              textTransform: 'uppercase',
              border: '3px solid #a06a69',
              borderBottom: '8px solid #8a5857',
              boxShadow: '4px 4px 0 #3a3832',
              transition:
                'transform 0.1s ease, box-shadow 0.1s ease, border-bottom-width 0.1s ease',
              '&:hover': {
                transform: 'translate(-1px, -1px)',
                boxShadow: '5px 5px 0 #3a3832'
              },
              '&:active': {
                transform: 'translateY(5px)',
                borderBottomWidth: '3px',
                boxShadow: '2px 1px 0 #3a3832'
              }
            }}
          >
            Get building!
          </Box>
        </Box>
      </Box>
    </CardModel>
  )
}


================================================
FILE: components/index/cards/button.tsx
================================================
/** @jsxImportSource theme-ui */
import { Box, Button, Text } from 'theme-ui'
import ReactTooltip from '../../react-tooltip'
import Icon from '@hackclub/icons'

type ButtonsProps = {
  children: React.ReactNode
  icon?: string
  customIcon?: React.ReactNode
  id: string
  content?: React.ReactNode
  link?: string
  primary?: boolean | string
  overrideColor?: string
  zIndex?: number
  sx?: any
}

export default function Buttons({
  children,
  icon,
  customIcon,
  id,
  content,
  link,
  primary,
  overrideColor,
  zIndex,
  sx,
  ...props
}: ButtonsProps) {
  const fontWeight = primary ? '700' : '400'

  return (
    <Box
      as="button"
      sx={{
        background: 'transparent',
        border: 'none',
        color: 'white',
        zIndex: zIndex || 0,
        ...sx
      }}
      py={1}
      tabIndex={-1}
    >
      <Button
        data-place="right"
        data-for={id}
        data-effect="solid"
        data-tip
        sx={{
          background:
            (typeof primary === 'string' ? primary : undefined) ||
            overrideColor ||
            'rgb(255, 255, 255, 0.3)',
          borderRadius: '100px',
          border: 'none',
          display: 'flex',
          alignItems: 'center',
          color: 'inherit',
          px: '3',
          py: primary ? '12px' : 2,
          width: 'fit-content',
          textTransform: 'none',
          fontSize: primary ? ['18px', '20px', '22px'] : [1, '16px', '18px'],
          backdropFilter: 'blur(2px)',
          fontWeight: fontWeight,
          zIndex: 999
        }}
        as="a"
        href={link || '/'}
        target="_blank"
        rel="noreferrer"
        {...props}
      >
        {customIcon ? (
          <Box sx={{ marginRight: 2, display: 'flex', alignItems: 'center' }}>
            {customIcon}
          </Box>
        ) : (
          <Icon
            glyph={(icon || 'plus-fill') as any}
            size={24}
            style={{ color: 'inherit', marginRight: 2 }}
          />
        )}
        <Text sx={{ fontFamily: 'Phantom Sans', textAlign: 'left' }}>
          {children}
        </Text>
      </Button>
      <ReactTooltip
        id={id}
        delayShow={150}
        delayHide={100}
        delayUpdate={500}
        clickable={true}
        getContent={() => {
          return null
        }}
        className="custom-tooltip-radius custom-arrow-radius"
        arrowRadius="2"
        tooltipRadius="10"
      >
        {content}
      </ReactTooltip>
    </Box>
  )
}


================================================
FILE: components/index/cards/card-model.tsx
================================================
import Icon from '../../icon'
import { Box, Card, Flex, Image, Link, Text } from 'theme-ui'
import ReactTooltip from '../../react-tooltip'
import Comma from '../../comma'

/** @jsxImportSource theme-ui */
const CardModel = ({
  background,
  children,
  image,
  image_fit,
  link,
  highlight,
  github_link,
  badge,
  text,
  color,
  stars,
  delay,
  position,
  filter,
  visible = false,
  ...props
}: {
  [x: string]: any
  background?: any
  children?: any
  image?: any
  image_fit?: any
  link?: any
  highlight?: any
  github_link?: any
  badge?: any
  text?: any
  color?: any
  stars?: any
  delay?: any
  position?: any
  filter?: any
  visible?: boolean
}) => (
  // <Zoom delay={delay}>
  <Card
    sx={{
      position: 'relative',
      width: '100%',
      color: color,
      my: [4, 4],
      p: '24px',
      backgroundSize: 'cover',
      backgroundImage: background ? `url(${background})` : undefined,
      backgroundPosition: 'center bottom',
      backgroundRepeat: 'no-repeat',
      '& p': {
        fontSize: ['18px', '20px', '22px']
      },
      overflow: visible ? 'visible' : 'hidden'
    }}
    {...props}
  >
    {badge && (
      <Box
        sx={{
          position: ['relative', 'relative', 'relative', 'absolute'],
          width: 'fit-content',
          right: [0, 0, 0, 3],
          top: [0, 0, 0, 3],
          zIndex: 3,
          px: '12px',
          py: '4px',
          mb: 2,
          float: [null, 'right', null],
          // background: 'rgba(255,255,255,0.2)',
          border: 'rgba(255,255,255,0.2) dashed 1px',
          borderRadius: 'circle',
          fontWeight: 'bold'
        }}
      >
        {text || 'Happening now'}
      </Box>
    )}
    {github_link && (
      <Box>
        {position === 'bottom' ? (
          <Flex
            sx={{
              position: 'absolute',
              left: 3,
              bottom: 2,
              alignItems: 'center',
              zIndex: 2
            }}
          >
            <Link
              href={github_link}
              sx={{ mr: 2 }}
              target="_blank"
              rel="noopener"
            >
              <Icon
                glyph="github"
                size={42}
                color="#2351fs"
                sx={{
                  color: '#000',
                  '&:hover': {
                    color: highlight || color
                  }
                }}
              />
            </Link>
            {stars ? (
              <Text as="h2">
                ⭐️ <Comma>{stars}</Comma>
              </Text>
            ) : (
              <></>
            )}
          </Flex>
        ) : (
          <Flex
            sx={{
              position: 'absolute',
              right: 2,
              top: 2,
              alignItems: 'center',
              zIndex: 2
              // flexDirection: ['column', 'row', 'row']
            }}
          >
            {stars ? (
              <Text as="h2" sx={{ fontSize: ['20px', '24px', '28px'] }}>
                ⭐️ <Comma>{stars}</Comma>
              </Text>
            ) : (
              <></>
            )}
            <Link href={github_link} sx={{ ml: 2 }}>
              <Icon
                glyph="github"
                size={42}
                sx={{
                  color: color,
                  transition: '0.4s',
                  '&:hover': {
                    color: highlight || color
                  }
                }}
              />
            </Link>
          </Flex>
        )}
      </Box>
    )}
    {image && (
      <Image
        src={image}
        draggable="false"
        sx={{
          objectFit: image_fit ? image_fit : 'cover',
          position: 'absolute',
          width: '100%',
          height: '100%',
          ml: ['-24px', '-32px', '-32px', '-32px'],
          mt: ['-24px', '-32px', '-32px', '-32px'],
          zIndex: 0,
          filter
        }}
        alt=""
      />
    )}
    {children}
    <ReactTooltip />
  </Card>
  // </Zoom>
)

export default CardModel


================================================
FILE: components/index/cards/clubs.tsx
================================================
/** @jsxImportSource theme-ui */
import Buttons from './button'
import CardModel from './card-model'
import { Box, Grid, Flex, Image, Text } from 'theme-ui'

const Cover = () => (
  <Box
    sx={{
      position: 'absolute',
      bottom: 0,
      top: 0,
      left: 0,
      right: 0,
      backgroundImage:
        'linear-gradient(to bottom,rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.8))',
      opacity: 0.8,
      zIndex: 1
    }}
  />
)

export default function Clubs() {
  // let [fooRef, setFooRef] = useState('')
  // let [toggle, setToggle] = useState(true)

  return (
    <CardModel
      color="white"
      sx={{
        backgroundColor: 'red'
      }}
    >
      <Image
        src="https://cloud-5pdwvchgm-hack-club-bot.vercel.app/05851864a.jpg"
        alt="Summer Creek Hack Club meeting, February 2020"
        sx={{
          objectFit: 'cover',
          position: 'absolute',
          width: '120%',
          height: '120%',
          ml: ['-24px', '-32px', '-32px', '-32px'],
          mt: ['-24px', '-32px', '-32px', '-32px'],
          zIndex: 0
        }}
      />
      <Cover />
      <Text
        variant="title"
        as="h3"
        sx={{
          borderRadius: 'default',
          px: 2,
          mx: [-2, 0],
          whiteSpace: [null, 'nowrap', 'nowrap'],
          fontSize: ['36px', 4, 5],
          position: 'relative',
          zIndex: 2,
          width: 'fit-content'
        }}
      >
        A Network of 1000+ Coding Clubs
      </Text>
      <Grid columns={[1, 1, 2]} sx={{ position: 'relative', zIndex: 2 }}>
        <Box>
          <Text
            as="p"
            variant="subtitle"
            sx={{ textShadow: '1px 1px 5px black' }}
          >
            Join or start a Hack&nbsp;Club and be part of a network of high
            quality coding clubs where you learn to code entirely through
            building things.
          </Text>
          <Text
            as="p"
            variant="subtitle"
            sx={{ textShadow: '1px 1px 5px black' }}
          >
            You can start with no experience and build and ship a project every
            meeting.
          </Text>
          <Flex sx={{ flexDirection: 'column', mt: [3, 3, 4] }}>
            <Buttons
              content="we'll support you with meeting content, stickers, and more"
              id="2"
              icon="welcome"
              link="https://apply.hackclub.com/"
              primary="red"
            >
              Start a club
            </Buttons>
          </Flex>
        </Box>
      </Grid>
    </CardModel>
  )
}


================================================
FILE: components/index/cards/fallout.tsx
================================================
/** @jsxImportSource theme-ui */
import { Box, Text, Image } from 'theme-ui'
import CardModel from './card-model'
import Buttons from './button'

export default function Fallout() {
  return (
    <CardModel
      color="black"
      sx={{
        borderRadius: '16px',
        border: '2px solid #61453A',
        boxShadow: '0 8px 24px rgba(0, 0, 0, 0.1)',
        position: 'relative',
        backgroundImage:
          'url("https://cdn.hackclub.com/019ce02f-ed7b-7b9f-bf91-84503a43c535/bg.webp")',
        backgroundSize: 'cover',
        backgroundPosition: 'center'
      }}
      position={[null, 'bottom', 'bottom']}
      visible={true}
    >
      <video
        autoPlay
        loop
        muted
        playsInline
        style={{
          width: '300px',
          maxWidth: '30%',
          position: 'absolute',
          bottom: 0,
          right: 10,
          height: 'auto',
          zIndex: 10
        }}
      >
        <source
          src="https://cdn.hackclub.com/019ce0b8-d90a-7f80-866c-185a5ccd74d9/soup.webm"
          type="video/webm"
        />
      </video>

      <Box
        sx={{
          position: 'relative',
          zIndex: 2,
          paddingInline: '20px',
          maxWidth: ['100%', '100%', '100%', '50%'],
          display: 'flex',
          flexDirection: 'column',
          justifyContent: 'space-around',
          height: '100%'
        }}
      >
        <Image
          src="https://cdn.hackclub.com/019cdfd0-6f09-7c8c-bd01-d0349e421c32/logo2.svg"
          alt="Fallout"
          sx={{
            maxWidth: '400px',
            marginTop: '20px',
            width: '100%'
          }}
        />
        <Text
          variant="subtitle"
          as="p"
          sx={{
            fontFamily: 'system-ui, -apple-system, sans-serif',
            color: 'white',
            fontSize: ['20px', '24px'],
            fontWeight: 600,
            lineHeight: 1.5,
            mb: 4,
            maxWidth: '400px',
            display: 'block',
            textAlign: 'left'
          }}
        >
          Build hardware projects, track your hours, then{' '}
          <span style={{ fontWeight: 700 }}>
            attend a hardware hackathon in Shenzhen!
          </span>
        </Text>
        <Buttons
          id="fallout-join"
          icon="enter"
          link="https://fallout.hackclub.com/?utm_source=site_card"
          rel="noopener"
          sx={{
            background: '#9F715D',
            color: '#EDD1B0',
            border: '2px solid #61453A',
            borderRadius: '100px',
            px: 3,
            py: '10px',
            fontFamily: 'system-ui, -apple-system, sans-serif',
            fontWeight: '600'
          }}
        >
          Start Building
        </Buttons>
      </Box>
    </CardModel>
  )
}


================================================
FILE: components/index/cards/flavortown.tsx
================================================
/** @jsxImportSource theme-ui */
import CardModel from './card-model'
import { Box, Flex, Grid, Image, Text } from 'theme-ui'
import Buttons from './button'

export default function Flavortown() {
  return (
    <CardModel
      color="white"
      sx={{
        background:
          'url("https://flavortown.hackclub.com/assets/mask/project-card-bd9acd6b.webp"), linear-gradient(to top, rgba(123,73,66,0.9), rgba(123,73,66,0.9))',
        borderRadius: '24px',
        boxShadow: '0 8px 24px rgba(0, 0, 0, 0.1)'
      }}
      position={[null, 'bottom', 'bottom']}
      visible={true}
    >
      <Grid
        columns={[1, 1, '1.5fr 1fr']}
        sx={{
          position: 'relative',
          alignItems: 'center',
          zIndex: 2,
          paddingInline: '50px'
        }}
      >
        <Box sx={{ textAlign: ['left', 'left', 'left'] }}>
          <Image
            src="https://cdn.hackclub.com/019c76b8-4f54-7de9-ae34-90b2190c2440/TeQ27w.png"
            alt="Flavortown Text Logo"
            sx={{
              height: '70px'
            }}
          />

          <Text
            variant="subtitle"
            sx={{
              color: '#f0dcc8ff',
              fontSize: ['18px', '20px'],
              fontWeight: 500,
              lineHeight: 1.5,
              mb: 3,
              display: 'block',
              textAlign: 'left'
            }}
          >
            Make a website, game, hardware project, or anything your heart
            desires, share your project for others to experience and to get
            cookies - our virtual currency, and exchange your cookies for iPads,
            MacBooks, Raspberry Pis and so many more things - all for free!
          </Text>
          <Buttons
            id="join-flavortown"
            icon="enter"
            
Download .txt
gitextract_sca6vlk2/

├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── attachment-warn.yml
│       ├── caniuse-update.yml
│       ├── ci.yml
│       └── validate-team-json.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── AGENT.md
├── LICENSE.md
├── README.md
├── components/
│   ├── AButton.ts
│   ├── analytics.tsx
│   ├── announcement.tsx
│   ├── announcements/
│   │   ├── amount.tsx
│   │   ├── cta.tsx
│   │   ├── elon.mdx
│   │   ├── hcb-mobile.mdx
│   │   ├── hcb-open-source.mdx
│   │   ├── hcb_cta.tsx
│   │   ├── holder.tsx
│   │   ├── pills.tsx
│   │   ├── preston-werner-2022.mdx
│   │   ├── preston-werner.mdx
│   │   └── relon.mdx
│   ├── arcade/
│   │   ├── footer.tsx
│   │   └── projects.tsx
│   ├── background-image.tsx
│   ├── bin/
│   │   ├── GalleryPosts.tsx
│   │   ├── PartTag.module.css
│   │   ├── PartTag.tsx
│   │   ├── nav.tsx
│   │   └── rsvp-form.tsx
│   ├── bio.tsx
│   ├── boardbio.tsx
│   ├── color-switcher.tsx
│   ├── comma.ts
│   ├── directoryModal.tsx
│   ├── donate/
│   │   ├── donors.json
│   │   └── sponsors.tsx
│   ├── dot.tsx
│   ├── elon.mdx
│   ├── fade-in.tsx
│   ├── fiscal-sponsorship/
│   │   ├── contact.tsx
│   │   ├── directory/
│   │   │   └── card.tsx
│   │   ├── features.tsx
│   │   ├── first/
│   │   │   ├── apply-button.tsx
│   │   │   ├── features.tsx
│   │   │   ├── start.tsx
│   │   │   ├── stats.tsx
│   │   │   └── testimonials.tsx
│   │   ├── open-source.tsx
│   │   ├── organization-spotlight.tsx
│   │   ├── sign-in.tsx
│   │   └── tooltip.tsx
│   ├── flag.tsx
│   ├── flex-col.tsx
│   ├── footer.tsx
│   ├── force-theme.ts
│   ├── hackathons/
│   │   ├── features/
│   │   │   ├── marketing.tsx
│   │   │   └── slack.tsx
│   │   ├── keep-exploring.tsx
│   │   ├── landing.tsx
│   │   ├── overview.tsx
│   │   ├── recap.tsx
│   │   └── scrolling-hackathons.tsx
│   ├── icon.tsx
│   ├── index/
│   │   ├── cards/
│   │   │   ├── beest.tsx
│   │   │   ├── button.tsx
│   │   │   ├── card-model.tsx
│   │   │   ├── clubs.tsx
│   │   │   ├── fallout.tsx
│   │   │   ├── flavortown.tsx
│   │   │   ├── hackathons.tsx
│   │   │   ├── haxidraw.tsx
│   │   │   ├── hcb.tsx
│   │   │   ├── hctg.tsx
│   │   │   ├── horizons.tsx
│   │   │   ├── jackpot.tsx
│   │   │   ├── macondo.tsx
│   │   │   ├── mailing-list.tsx
│   │   │   ├── sinerider.tsx
│   │   │   ├── slack.tsx
│   │   │   ├── sleepover.tsx
│   │   │   ├── sprig-console.tsx
│   │   │   ├── sprig.tsx
│   │   │   ├── stasis.tsx
│   │   │   └── workshops.tsx
│   │   ├── carousel-cards.tsx
│   │   ├── carousel.tsx
│   │   ├── ctas.tsx
│   │   ├── events.tsx
│   │   └── github.tsx
│   ├── letterhead.tsx
│   ├── mail-card.tsx
│   ├── marquee.tsx
│   ├── mention.tsx
│   ├── nav.tsx
│   ├── onboard/
│   │   ├── gallery-paginated.tsx
│   │   ├── item.tsx
│   │   ├── pagination-buttons.tsx
│   │   ├── recap.tsx
│   │   └── youtube-video.tsx
│   ├── particles.tsx
│   ├── photo.tsx
│   ├── posts/
│   │   ├── emoji.tsx
│   │   ├── index.tsx
│   │   └── mention.tsx
│   ├── press.mdx
│   ├── react-reveal-compat.tsx
│   ├── react-tooltip.ts
│   ├── replit/
│   │   ├── scale-up.tsx
│   │   └── token-instructions.tsx
│   ├── scroll-hint.tsx
│   ├── secret.tsx
│   ├── ship/
│   │   └── why.mdx
│   ├── signature.tsx
│   ├── signatures.tsx
│   ├── slack.tsx
│   ├── slide-down.tsx
│   ├── slide-up.tsx
│   ├── sparkles/
│   │   ├── index.tsx
│   │   └── money.tsx
│   ├── stage.tsx
│   ├── stat.tsx
│   ├── submit.tsx
│   ├── tilt.tsx
│   └── winter/
│       ├── breakdown-box.tsx
│       ├── breakdown.tsx
│       ├── footer.tsx
│       ├── info.tsx
│       ├── landing.tsx
│       ├── projects.tsx
│       ├── recap.tsx
│       └── timeline.tsx
├── eslint.config.mts
├── lib/
│   ├── cached-hcb-orgs.ts
│   ├── countries.json
│   ├── cta.json
│   ├── dates.ts
│   ├── fetcher.ts
│   ├── git-info.ts
│   ├── helpers.ts
│   ├── members.ts
│   ├── organization.ts
│   ├── slackData.ts
│   ├── sleep.ts
│   ├── theme.ts
│   ├── use-form.ts
│   ├── use-has-mounted.ts
│   ├── use-media.ts
│   ├── use-prefers-motion.ts
│   ├── use-prefers-reduced-motion.ts
│   └── use-random-interval.ts
├── next.config.ts
├── package.json
├── pages/
│   ├── 404.tsx
│   ├── _app.tsx
│   ├── _document.tsx
│   ├── acknowledged.tsx
│   ├── amas/
│   │   ├── geohot.tsx
│   │   ├── index.tsx
│   │   ├── sal.tsx
│   │   └── vitalik.tsx
│   ├── api/
│   │   ├── arcade/
│   │   │   ├── hack-hour/
│   │   │   │   └── inventory.ts
│   │   │   └── shop.ts
│   │   ├── bin/
│   │   │   ├── gallery/
│   │   │   │   ├── posts.ts
│   │   │   │   └── tags.ts
│   │   │   ├── rsvp.ts
│   │   │   └── wokwi/
│   │   │       ├── new/
│   │   │       │   ├── [parts].ts
│   │   │       │   └── index.ts
│   │   │       └── parts.ts
│   │   ├── bucky.ts
│   │   ├── channels/
│   │   │   └── resolve.ts
│   │   ├── contribute.ts
│   │   ├── first-team.ts
│   │   ├── games.ts
│   │   ├── github.ts
│   │   ├── join.ts
│   │   ├── mailing-list.ts
│   │   ├── onboard/
│   │   │   ├── p/
│   │   │   │   ├── [project]/
│   │   │   │   │   └── index.ts
│   │   │   │   ├── count.ts
│   │   │   │   └── index.ts
│   │   │   └── svg/
│   │   │       └── [board_url]/
│   │   │           ├── bottom.ts
│   │   │           ├── index.ts
│   │   │           └── top.ts
│   │   ├── replit/
│   │   │   └── signup.ts
│   │   ├── sprig-console.ts
│   │   ├── stars.ts
│   │   ├── steve.ts
│   │   ├── stickers.ts
│   │   ├── stuff.ts
│   │   ├── team.ts
│   │   └── winter-rsvp.ts
│   ├── arcade/
│   │   └── index.tsx
│   ├── bin/
│   │   ├── gallery.tsx
│   │   └── prelaunch.tsx
│   ├── brand.tsx
│   ├── clubs.tsx
│   ├── content/
│   │   ├── covid19.mdx
│   │   ├── it-admins.mdx
│   │   ├── sponsorship.mdx
│   │   ├── sunsetting-som.mdx
│   │   └── transparency/
│   │       └── may-2020.mdx
│   ├── deprecated/
│   │   └── [deprecated].tsx
│   ├── elon.tsx
│   ├── events.tsx
│   ├── fiscal-sponsorship/
│   │   ├── about.tsx
│   │   ├── climate/
│   │   │   ├── [region].tsx
│   │   │   └── index.tsx
│   │   ├── directory/
│   │   │   ├── [category]/
│   │   │   │   ├── [region].tsx
│   │   │   │   └── index.tsx
│   │   │   └── index.tsx
│   │   ├── first.tsx
│   │   ├── index.tsx
│   │   ├── mobile/
│   │   │   └── index.tsx
│   │   └── open-source.tsx
│   ├── hackathons/
│   │   ├── grant.tsx
│   │   └── index.tsx
│   ├── imprint.tsx
│   ├── index.tsx
│   ├── jobs/
│   │   └── index.tsx
│   ├── minecraft.tsx
│   ├── night.tsx
│   ├── onboard/
│   │   ├── board/
│   │   │   └── [slug].tsx
│   │   ├── first.tsx
│   │   ├── gallery/
│   │   │   └── index.tsx
│   │   └── index.tsx
│   ├── opensource.tsx
│   ├── philanthropy/
│   │   ├── index.tsx
│   │   └── supporters.tsx
│   ├── philosophy.tsx
│   ├── pizza.tsx
│   ├── press.tsx
│   ├── preston-werner-2022.tsx
│   ├── preston-werner.tsx
│   ├── relon.tsx
│   ├── replit.tsx
│   ├── santa.tsx
│   ├── sharkbank/
│   │   └── index.tsx
│   ├── ship.tsx
│   ├── sitemap.xml.tsx
│   ├── steve.tsx
│   ├── stickers.tsx
│   ├── team.tsx
│   └── winter.tsx
├── public/
│   ├── .well-known/
│   │   └── security.txt
│   ├── acknowledged.json
│   ├── bin/
│   │   ├── data-loading.js
│   │   ├── index.html
│   │   ├── landing/
│   │   │   ├── index.html
│   │   │   ├── script.js
│   │   │   └── style.css
│   │   ├── landing-new/
│   │   │   ├── ascii-art.txt
│   │   │   ├── gambling.js
│   │   │   ├── script.js
│   │   │   └── style.css
│   │   ├── memes.js
│   │   ├── orph/
│   │   │   ├── orph.css
│   │   │   └── orph.js
│   │   ├── selector/
│   │   │   ├── index.html
│   │   │   ├── script.js
│   │   │   └── style.css
│   │   └── style/
│   │       ├── common.css
│   │       ├── footer.css
│   │       └── gallery.module.css
│   ├── carousel.json
│   ├── horizons/
│   │   └── Hypebuzz.otf
│   ├── robots.txt
│   ├── stickers-in-stock.html
│   └── team.json
├── tsconfig.json
├── types/
│   └── mdx.d.ts
└── vercel.json
Download .txt
SYMBOL INDEX (287 symbols across 154 files)

FILE: components/announcement.tsx
  type AnnouncementProps (line 11) | type AnnouncementProps = {

FILE: components/announcements/cta.tsx
  function SlackCTA (line 6) | function SlackCTA() {

FILE: components/announcements/hcb_cta.tsx
  function HCBCTA (line 5) | function HCBCTA() {

FILE: components/announcements/holder.tsx
  function AnnouncementHolder (line 3) | function AnnouncementHolder({ children }) {

FILE: components/announcements/pills.tsx
  function PillHolder (line 3) | function PillHolder({ children }) {
  function AuthorPill (line 28) | function AuthorPill({ tag, image, firstName }) {
  function DatePill (line 46) | function DatePill({ tag }) {

FILE: components/arcade/projects.tsx
  function Projects (line 148) | function Projects() {

FILE: components/background-image.tsx
  type BGImgProps (line 11) | type BGImgProps = {
  function BGImg (line 18) | function BGImg({

FILE: components/bin/GalleryPosts.tsx
  type BinPostProps (line 6) | type BinPostProps = {
  function handleClick (line 32) | function handleClick() {
  function formatDate (line 38) | function formatDate(dateString) {

FILE: components/bin/rsvp-form.tsx
  function RsvpForm (line 8) | function RsvpForm() {

FILE: components/bio.tsx
  function Bio (line 6) | function Bio({ popup = true, spanTwo = false, ...props }) {

FILE: components/boardbio.tsx
  function BoardBox (line 6) | function BoardBox({ popup = true, ...props }) {

FILE: components/comma.ts
  function Comma (line 1) | function Comma({ children }) {

FILE: components/directoryModal.tsx
  function getBadgesForOrg (line 14) | function getBadgesForOrg(org: { [key: string]: any }): typeof badges {
  type OrganizationModalProps (line 23) | type OrganizationModalProps = {
  function OrganizationModal (line 45) | function OrganizationModal({

FILE: components/dot.tsx
  function Dot (line 10) | function Dot({ hideOnMobile }) {

FILE: components/fiscal-sponsorship/contact.tsx
  function ContactBanner (line 8) | function ContactBanner({ sx }) {

FILE: components/fiscal-sponsorship/directory/card.tsx
  type OrganizationCardProps (line 45) | type OrganizationCardProps = {

FILE: components/fiscal-sponsorship/features.tsx
  function Features (line 7) | function Features() {
  function Module (line 95) | function Module({ icon, name, body }) {
  function Laptop (line 146) | function Laptop({ href, title }) {

FILE: components/fiscal-sponsorship/first/apply-button.tsx
  function ApplyButton (line 5) | function ApplyButton() {

FILE: components/fiscal-sponsorship/first/features.tsx
  function Features (line 9) | function Features() {
  type ModuleProps (line 327) | type ModuleProps = {
  function Module (line 334) | function Module({ icon, name, body, iconColor }: ModuleProps) {
  function ModuleDetails (line 381) | function ModuleDetails({ children }) {
  function Document (line 400) | function Document({ name, cost }) {
  function Laptop (line 422) | function Laptop({ href, title, sx }) {

FILE: components/fiscal-sponsorship/first/start.tsx
  function Start (line 5) | function Start({ stats }) {

FILE: components/fiscal-sponsorship/first/stats.tsx
  function startMoneyAnimation (line 13) | function startMoneyAnimation(
  function formatMoney (line 38) | function formatMoney(amount) {
  function getStaticProps (line 108) | async function getStaticProps() {

FILE: components/fiscal-sponsorship/first/testimonials.tsx
  function Testimonials (line 14) | function Testimonials() {
  function Organization (line 78) | function Organization({

FILE: components/fiscal-sponsorship/open-source.tsx
  function OpenSource (line 8) | function OpenSource() {

FILE: components/fiscal-sponsorship/organization-spotlight.tsx
  function OrganizationSpotlight (line 7) | function OrganizationSpotlight({ organization }) {

FILE: components/fiscal-sponsorship/sign-in.tsx
  function SignIn (line 5) | function SignIn() {

FILE: components/fiscal-sponsorship/tooltip.tsx
  type TooltipComponent (line 87) | type TooltipComponent = React.FC<{ children: any; text: any; id: any }> & {

FILE: components/flex-col.tsx
  function FlexCol (line 3) | function FlexCol({ children, ...props }) {

FILE: components/hackathons/keep-exploring.tsx
  function KeepExploring (line 5) | function KeepExploring() {

FILE: components/hackathons/landing.tsx
  function Landing (line 7) | function Landing() {
  function Slide (line 111) | function Slide({ children }) {
  function BlueGradientFilter (line 144) | function BlueGradientFilter() {

FILE: components/hackathons/overview.tsx
  function Overview (line 3) | function Overview() {
  function Highlight (line 72) | function Highlight({ children }) {

FILE: components/hackathons/recap.tsx
  function Recap (line 5) | function Recap() {

FILE: components/hackathons/scrolling-hackathons.tsx
  function ScrollingHackathons (line 19) | function ScrollingHackathons({
  function Dot (line 100) | function Dot() {
  type EventCardProps (line 122) | type EventCardProps = {
  function EventCard (line 138) | function EventCard({

FILE: components/icon.tsx
  function IconComponent (line 4) | function IconComponent(props: any): React.ReactElement {

FILE: components/index/cards/beest.tsx
  function Beest (line 11) | function Beest() {

FILE: components/index/cards/button.tsx
  type ButtonsProps (line 6) | type ButtonsProps = {
  function Buttons (line 19) | function Buttons({

FILE: components/index/cards/clubs.tsx
  function Clubs (line 22) | function Clubs() {

FILE: components/index/cards/fallout.tsx
  function Fallout (line 6) | function Fallout() {

FILE: components/index/cards/flavortown.tsx
  function Flavortown (line 6) | function Flavortown() {

FILE: components/index/cards/hackathons.tsx
  function Hackathons (line 24) | function Hackathons({ data, stars }) {

FILE: components/index/cards/haxidraw.tsx
  function Haxidraw (line 6) | function Haxidraw({ stars }) {

FILE: components/index/cards/hcb.tsx
  function Bank (line 6) | function Bank({ data }) {

FILE: components/index/cards/hctg.tsx
  function HackClubTheGame (line 5) | function HackClubTheGame() {

FILE: components/index/cards/horizons.tsx
  function Horizons (line 9) | function Horizons() {

FILE: components/index/cards/jackpot.tsx
  function Jackpot (line 5) | function Jackpot() {

FILE: components/index/cards/macondo.tsx
  function Macondo (line 6) | function Macondo() {

FILE: components/index/cards/sinerider.tsx
  function Sinerider (line 6) | function Sinerider({ stars }) {

FILE: components/index/cards/slack.tsx
  function Slack (line 44) | function Slack({ data, events }) {

FILE: components/index/cards/sleepover.tsx
  function Sleepover (line 5) | function Sleepover() {

FILE: components/index/cards/sprig-console.tsx
  function SprigConsole (line 7) | function SprigConsole({ stars, consoleCount }) {

FILE: components/index/cards/sprig.tsx
  function Game (line 7) | function Game({ game, gameImage, gameImage1, ...props }) {
  function Sprig (line 168) | function Sprig({ stars, game, gameImage, gameImage1 }) {

FILE: components/index/cards/stasis.tsx
  function Stasis (line 5) | function Stasis() {

FILE: components/index/cards/workshops.tsx
  function Workshops (line 54) | function Workshops({ stars }) {

FILE: components/index/carousel-cards.tsx
  function CarouselCards (line 4) | function CarouselCards({

FILE: components/index/carousel.tsx
  function Carousel (line 8) | function Carousel({ cards }) {

FILE: components/index/ctas.tsx
  function CTAS (line 6) | function CTAS({ cards }) {

FILE: components/index/events.tsx
  function Events (line 79) | function Events({ events }) {

FILE: components/index/github.tsx
  type GitHubProps (line 4) | type GitHubProps = {
  function GitHub (line 14) | function GitHub({

FILE: components/mail-card.tsx
  function MailCard (line 3) | function MailCard({ body, date, link, issue }) {

FILE: components/marquee.tsx
  type Props (line 28) | type Props = {
  function Marquee (line 35) | function Marquee({

FILE: components/nav.tsx
  type HeaderProps (line 171) | type HeaderProps = {
  function Header (line 179) | function Header({

FILE: components/photo.tsx
  type PhotoProps (line 20) | type PhotoProps = {

FILE: components/posts/emoji.tsx
  type CustomEmojiProps (line 41) | type CustomEmojiProps = {

FILE: components/posts/index.tsx
  function Posts (line 140) | function Posts({ data = [] }) {

FILE: components/react-reveal-compat.tsx
  type RevealProps (line 55) | type RevealProps = {
  function RevealWrap (line 70) | function RevealWrap({
  function Fade (line 88) | function Fade({
  function Slide (line 127) | function Slide({
  function Zoom (line 150) | function Zoom({ children, delay = 0, duration = 500 }: RevealProps) {

FILE: components/secret.tsx
  function Secret (line 6) | function Secret({ reveal, ...props }) {

FILE: components/sparkles/index.tsx
  type SparklesProps (line 25) | type SparklesProps = {

FILE: components/sparkles/money.tsx
  type MSparklesProps (line 25) | type MSparklesProps = {

FILE: components/stage.tsx
  type StageProps (line 4) | type StageProps = {
  function Stage (line 13) | function Stage({

FILE: components/stat.tsx
  type StatProps (line 4) | type StatProps = {

FILE: components/winter/breakdown-box.tsx
  function BreakdownBox (line 6) | function BreakdownBox({

FILE: components/winter/breakdown.tsx
  function Breakdown (line 6) | function Breakdown() {

FILE: components/winter/info.tsx
  function InfoGrid (line 16) | function InfoGrid() {
  function BulletItem (line 169) | function BulletItem({ children, iconGlyph, iconColor, iconSize }) {

FILE: components/winter/landing.tsx
  function Landing (line 6) | function Landing() {

FILE: components/winter/projects.tsx
  function Projects (line 163) | function Projects() {

FILE: components/winter/recap.tsx
  function Recap (line 6) | function Recap() {

FILE: components/winter/timeline.tsx
  function TimelineStep (line 6) | function TimelineStep({ children }) {
  function Circle (line 39) | function Circle({ children }) {
  function Step (line 61) | function Step({ icon, name, duration, href }) {
  function RealTimeline (line 112) | function RealTimeline() {

FILE: lib/cached-hcb-orgs.ts
  constant CACHE_FILENAME (line 1) | const CACHE_FILENAME = 'hcb-orgs-cache.json'
  function fetchAllOrganizations (line 3) | async function fetchAllOrganizations() {

FILE: lib/dates.ts
  function formatChunk (line 54) | function formatChunk(type, date) {
  type FormatDate (line 104) | type FormatDate = {

FILE: lib/fetcher.ts
  function fetcher (line 4) | async function fetcher(...args: Parameters<typeof fetch>) {

FILE: lib/helpers.ts
  function formatChunk (line 131) | function formatChunk(type, date) {

FILE: lib/organization.ts
  class Organization (line 5) | class Organization {
    method constructor (line 12) | constructor(rawOrganization: any) {
    method id (line 24) | get id() {
    method name (line 32) | get name() {
    method slug (line 40) | get slug() {
    method isTransparent (line 48) | get isTransparent() {
    method isDemo (line 56) | get isDemo() {
    method users (line 64) | get users() {
    method acceptsDonations (line 72) | get acceptsDonations() {
    method branding (line 84) | get branding() {
    method tags (line 102) | get tags() {
    method createdAt (line 114) | get createdAt() {
    method links (line 125) | get links() {
    method location (line 145) | get location() {
    method update (line 157) | async update() {

FILE: lib/slackData.ts
  type SlackData (line 1) | type SlackData = {

FILE: lib/use-has-mounted.ts
  function useHasMounted (line 4) | function useHasMounted() {

FILE: lib/use-media.ts
  function useMedia (line 3) | function useMedia(query) {

FILE: lib/use-prefers-motion.ts
  constant QUERY (line 4) | const QUERY = '(prefers-reduced-motion: no-preference)'
  function usePrefersMotion (line 15) | function usePrefersMotion() {

FILE: lib/use-prefers-reduced-motion.ts
  constant QUERY (line 4) | const QUERY = '(prefers-reduced-motion: no-preference)'
  function usePrefersReducedMotion (line 15) | function usePrefersReducedMotion() {

FILE: next.config.ts
  method redirects (line 34) | async redirects() {
  method rewrites (line 225) | async rewrites() {
  method headers (line 353) | async headers() {

FILE: pages/_document.tsx
  class MyDocument (line 26) | class MyDocument extends Document {
    method getInitialProps (line 27) | static async getInitialProps(ctx) {
    method render (line 32) | render() {

FILE: pages/acknowledged.tsx
  function Acknowleged (line 11) | function Acknowleged({ team }) {

FILE: pages/amas/geohot.tsx
  function Geohot (line 8) | function Geohot() {

FILE: pages/amas/sal.tsx
  function Sal (line 8) | function Sal() {

FILE: pages/amas/vitalik.tsx
  function Vitalik (line 9) | function Vitalik() {

FILE: pages/api/arcade/hack-hour/inventory.ts
  type InventoryRecord (line 25) | type InventoryRecord = {
  type FlavorRecord (line 38) | type FlavorRecord = {
  function handler (line 51) | async function handler(req, res) {

FILE: pages/api/arcade/shop.ts
  function handler (line 31) | async function handler(req, res) {

FILE: pages/api/bin/gallery/posts.ts
  function handler (line 34) | async function handler(req, res) {

FILE: pages/api/bin/gallery/tags.ts
  function handler (line 28) | async function handler(req, res) {

FILE: pages/api/bin/rsvp.ts
  function handler (line 19) | async function handler(req, res) {

FILE: pages/api/bin/wokwi/new/[parts].ts
  function handler (line 3) | async function handler(req, res) {

FILE: pages/api/bin/wokwi/new/index.ts
  function handler (line 155) | async function handler(req, res) {

FILE: pages/api/bin/wokwi/parts.ts
  function handler (line 26) | async function handler(req, res) {

FILE: pages/api/bucky.ts
  function handler (line 3) | async function handler(

FILE: pages/api/channels/resolve.ts
  function handler (line 1) | async function handler(req, res) {

FILE: pages/api/contribute.ts
  type OrgQueryResponse (line 5) | interface OrgQueryResponse {
  function handler (line 15) | async function handler(

FILE: pages/api/first-team.ts
  function handler (line 3) | async function handler(

FILE: pages/api/games.ts
  function getGames (line 3) | async function getGames() {
  function Games (line 16) | async function Games(

FILE: pages/api/github.ts
  function fetchGitHub (line 35) | async function fetchGitHub() {
  function github (line 59) | async function github(

FILE: pages/api/join.ts
  function postData (line 14) | async function postData(url = '', data = {}, headers = {}) {
  function handler (line 31) | async function handler(

FILE: pages/api/mailing-list.ts
  function submit (line 3) | async function submit(

FILE: pages/api/onboard/p/[project]/index.ts
  function getReadmeData (line 5) | async function getReadmeData(url) {
  function handler (line 47) | async function handler(req, res) {

FILE: pages/api/onboard/p/count.ts
  function onboardProjectCount (line 3) | async function onboardProjectCount() {
  function handler (line 8) | async function handler(req, res) {

FILE: pages/api/onboard/p/index.ts
  function handler (line 60) | async function handler(req, res) {

FILE: pages/api/onboard/svg/[board_url]/bottom.ts
  function handler (line 5) | async function handler(req, res) {

FILE: pages/api/onboard/svg/[board_url]/index.ts
  function handler (line 80) | async function handler(req, res) {

FILE: pages/api/onboard/svg/[board_url]/top.ts
  function handler (line 5) | async function handler(req, res) {

FILE: pages/api/replit/signup.ts
  function handler (line 1) | async function handler(req, res) {

FILE: pages/api/sprig-console.ts
  function check (line 3) | function check(val: any) {
  function getConsoles (line 7) | async function getConsoles() {
  function SprigConsoles (line 30) | async function SprigConsoles(

FILE: pages/api/stars.ts
  type GitHubStarsResponse (line 4) | interface GitHubStarsResponse {
  function fetchStars (line 16) | async function fetchStars() {
  function Stars (line 76) | async function Stars(

FILE: pages/api/stickers.ts
  function handler (line 15) | async function handler(

FILE: pages/api/stuff.ts
  function stuff (line 3) | async function stuff(

FILE: pages/api/team.ts
  type TeamMember (line 5) | interface TeamMember {
  function fetchTeam (line 21) | async function fetchTeam() {
  function fetchAcknowledged (line 25) | async function fetchAcknowledged() {
  function handler (line 29) | async function handler(

FILE: pages/api/winter-rsvp.ts
  function handler (line 10) | async function handler(

FILE: pages/arcade/index.tsx
  function generateProjectIdea (line 769) | async function generateProjectIdea() {
  function getStaticProps (line 1835) | async function getStaticProps() {

FILE: pages/bin/gallery.tsx
  function getStaticProps (line 11) | async function getStaticProps() {
  function Gallery (line 35) | function Gallery({ posts = [], tags = [] }) {

FILE: pages/bin/prelaunch.tsx
  function crunch (line 98) | function crunch() {
  function spinIt (line 121) | function spinIt(el) {
  function Bin (line 126) | function Bin() {

FILE: pages/deprecated/[deprecated].tsx
  type DeprecatedPageProps (line 8) | type DeprecatedPageProps = {

FILE: pages/fiscal-sponsorship/about.tsx
  type BulletProps (line 13) | type BulletProps = {
  function Bullet (line 20) | function Bullet({ glow = true, icon, href, children }: BulletProps) {
  function BulletBox (line 131) | function BulletBox({ padding = '2rem', children }) {
  function Section (line 149) | function Section({ id, children }) {
  function FiscalSponsorship (line 157) | function FiscalSponsorship() {

FILE: pages/fiscal-sponsorship/climate/[region].tsx
  function ClimateRegionalPage (line 12) | function ClimateRegionalPage({ rawOrganizations, pageRegion }) {

FILE: pages/fiscal-sponsorship/climate/index.tsx
  function getBadgesForOrg (line 49) | function getBadgesForOrg(org: Organization): typeof badges {
  function getTagsForOrg (line 68) | function getTagsForOrg(org: Organization): typeof tags {
  type RegionPanelProps (line 293) | type RegionPanelProps = {
  type FilteringProps (line 459) | type FilteringProps = {
  function ClimatePage (line 476) | function ClimatePage({ rawOrganizations, pageRegion }) {
  function fetchRawClimateOrganizations (line 1157) | async function fetchRawClimateOrganizations() {

FILE: pages/fiscal-sponsorship/directory/[category]/[region].tsx
  function DirectoryRegionalPage (line 14) | function DirectoryRegionalPage({

FILE: pages/fiscal-sponsorship/directory/[category]/index.tsx
  function DirectoryRegionalPage (line 9) | function DirectoryRegionalPage({

FILE: pages/fiscal-sponsorship/directory/index.tsx
  type Region (line 31) | type Region = {
  type FilteringProps (line 331) | type FilteringProps = {
  function Directory (line 364) | function Directory({ rawOrganizations, pageRegion, category }) {
  function fetchRawOrganizations (line 666) | async function fetchRawOrganizations() {

FILE: pages/fiscal-sponsorship/first.tsx
  function First (line 19) | function First({ stats }) {
  function getStaticProps (line 205) | async function getStaticProps(context) {

FILE: pages/fiscal-sponsorship/index.tsx
  function MobileAppAlert (line 76) | function MobileAppAlert() {
  function Page (line 178) | function Page() {

FILE: pages/hackathons/grant.tsx
  type RequirementProps (line 23) | type RequirementProps = {

FILE: pages/hackathons/index.tsx
  function Hackathons (line 16) | function Hackathons({ data }) {
  function getStaticProps (line 47) | async function getStaticProps() {

FILE: pages/index.tsx
  type Window (line 52) | interface Window {
  function Page (line 65) | function Page({
  function getStaticProps (line 1324) | async function getStaticProps() {

FILE: pages/jobs/index.tsx
  function getStaticProps (line 193) | async function getStaticProps() {

FILE: pages/onboard/board/[slug].tsx
  type ProjectType (line 13) | type ProjectType = {
  type BoardPageProps (line 24) | type BoardPageProps = {
  function getStaticPaths (line 223) | async function getStaticPaths(_context) {
  function getStaticProps (line 238) | async function getStaticProps(context: any) {

FILE: pages/onboard/gallery/index.tsx
  function Index (line 6) | function Index({ projects, itemCount }) {
  function getStaticProps (line 16) | async function getStaticProps() {

FILE: pages/opensource.tsx
  function getStaticProps (line 244) | async function getStaticProps() {

FILE: pages/philanthropy/index.tsx
  type PropPilled (line 209) | type PropPilled = {
  constant FIRST_IMAGE (line 275) | const FIRST_IMAGE = {
  constant SECOND_IMAGE (line 278) | const SECOND_IMAGE = {

FILE: pages/philanthropy/supporters.tsx
  function Donate (line 100) | function Donate() {

FILE: pages/philosophy.tsx
  function Philosophy (line 100) | function Philosophy() {

FILE: pages/santa.tsx
  function Base (line 139) | function Base({ children, action, target, method }) {
  function Field (line 165) | function Field({ placeholder, label, name, type, value, onChange }) {
  type valuesType (line 189) | type valuesType = {
  function Signup (line 195) | function Signup() {

FILE: pages/sharkbank/index.tsx
  function DesktopMode (line 7) | function DesktopMode({ billboardBottom }) {
  function TabletMode (line 318) | function TabletMode() {
  function MobileMode (line 621) | function MobileMode() {
  type SectionProps (line 935) | type SectionProps = {
  function Section (line 942) | function Section({ bg, minHeight, minWidth, children }: SectionProps) {
  function SharkBank (line 981) | function SharkBank() {

FILE: pages/sitemap.xml.tsx
  constant SITE_URL (line 5) | const SITE_URL = 'https://hackclub.com'
  function getPages (line 7) | function getPages(dir: string, base = ''): string[] {
  function e (line 31) | function e(s: string): string {
  function generateSitemap (line 40) | function generateSitemap(pages: string[]): string {
  function Sitemap (line 67) | function Sitemap() {

FILE: pages/stickers.tsx
  function customStartCase (line 14) | function customStartCase(st) {

FILE: pages/team.tsx
  function Team (line 45) | function Team({ team }) {

FILE: pages/winter.tsx
  function Winter (line 16) | function Winter() {

FILE: public/bin/data-loading.js
  function pullFromStorage (line 3) | async function pullFromStorage() {
  function setToStorage (line 20) | async function setToStorage(data) {
  function fetchPartsData (line 25) | async function fetchPartsData() {
  function removeItemByAttribute (line 35) | function removeItemByAttribute(arr, attr, value) {
  function partsDataLoader (line 39) | async function partsDataLoader() {
  function partsData (line 59) | async function partsData() {

FILE: public/bin/landing-new/gambling.js
  function removeItemByAttribute (line 5) | function removeItemByAttribute(arr, attr, value) {
  function addComponentsToPage (line 8) | function addComponentsToPage(data) {
  function sample (line 59) | function sample(arr) {
  function rollPartsAnimation (line 63) | function rollPartsAnimation(ms = 1000) {
  function randomizeParts (line 77) | function randomizeParts() {
  function rollParts (line 121) | function rollParts(el) {
  function generateBuildLink (line 138) | async function generateBuildLink(e) {
  function generateProjectIdea (line 160) | async function generateProjectIdea() {

FILE: public/bin/landing-new/script.js
  function init (line 1) | function init() {
  function getRandomInt (line 8) | function getRandomInt(max) {
  function opf (line 12) | function opf(number) {
  function onScroll (line 16) | function onScroll() {
  function fetchAndLogTextFile (line 23) | async function fetchAndLogTextFile(url) {
  function recalculateSectionHeight (line 39) | function recalculateSectionHeight() {

FILE: public/bin/landing/script.js
  function rainbowColor (line 1) | function rainbowColor(index, total) {
  function rainbow (line 6) | function rainbow(element) {

FILE: public/bin/selector/script.js
  function getSelectedItems (line 16) | function getSelectedItems() {
  function recalculateSelected (line 19) | function recalculateSelected() {
  function addPartToPage (line 48) | function addPartToPage(part) {
Condensed preview — 274 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,441K chars).
[
  {
    "path": ".github/dependabot.yml",
    "chars": 529,
    "preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
  },
  {
    "path": ".github/workflows/attachment-warn.yml",
    "chars": 3650,
    "preview": "name: Perhaps You Should Upload To CDN Instead?\n\non:\n  pull_request:\n    types: [opened, synchronize]\n\njobs:\n  warn:\n   "
  },
  {
    "path": ".github/workflows/caniuse-update.yml",
    "chars": 1056,
    "preview": "name: Update Browserslist database\n\non:\n  workflow_dispatch:\n  schedule:\n    - cron: '0 2 1,15 * *'\n\npermissions:\n  cont"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 493,
    "preview": "name: CI\non:\n  - push\n  - pull_request\n\njobs:\n  lint:\n    name: Lint\n    runs-on: ubuntu-latest\n    steps:\n      - uses:"
  },
  {
    "path": ".github/workflows/validate-team-json.yml",
    "chars": 488,
    "preview": "name: Validate Team JSON\n\non:\n  push:\n    paths:\n      - 'public/team.json'\n  pull_request:\n    paths:\n      - 'public/t"
  },
  {
    "path": ".gitignore",
    "chars": 170,
    "preview": ".now\n.env*\n.next\nnode_modules\n.DS_Store\npublic/sitemap.xml\n.vercel\n.vscode\nyarn-error.log\nbun.lockb\n.idea\n.yarn\n.yarnrc."
  },
  {
    "path": ".prettierignore",
    "chars": 5,
    "preview": ".next"
  },
  {
    "path": ".prettierrc",
    "chars": 116,
    "preview": "{\n  \"singleQuote\": true,\n  \"trailingComma\": \"none\",\n  \"arrowParens\": \"avoid\",\n  \"printWidth\": 80,\n  \"semi\": false\n}\n"
  },
  {
    "path": "AGENT.md",
    "chars": 1191,
    "preview": "# AGENT.md - Hack Club Site Development Guide\n\n## Commands\n\n- **Dev**: `bun run dev` (start development server)\n- **Buil"
  },
  {
    "path": "LICENSE.md",
    "chars": 1148,
    "preview": "_Code under MIT License, assets may not be re-used or re-distributed._\n\n### MIT License\n\nCopyright 2026 The Hack Foundat"
  },
  {
    "path": "README.md",
    "chars": 3692,
    "preview": "<p align=\"center\"><img width=\"192\" alt=\"Hack Club logo\" src=\"https://assets.hackclub.com/flag-standalone.svg\"></p>\n<h1 a"
  },
  {
    "path": "components/AButton.ts",
    "chars": 72,
    "preview": "import { Button } from 'theme-ui'\n\nexport const AButton = Button as any\n"
  },
  {
    "path": "components/analytics.tsx",
    "chars": 217,
    "preview": "import Script from 'next/script'\n\nconst Analytics = () => (\n  <Script\n    defer\n    data-domain=\"hackclub.com\"\n    src=\""
  },
  {
    "path": "components/announcement.tsx",
    "chars": 2186,
    "preview": "import { keyframes } from '@emotion/react'\nimport Image from 'next/image'\nimport { Box, Card, Text } from 'theme-ui'\nimp"
  },
  {
    "path": "components/announcements/amount.tsx",
    "chars": 280,
    "preview": "import Sparkles from '../sparkles'\n\nconst Amount = ({ amount }) => (\n  <Sparkles\n    sx={{\n      WebkitTextStroke: 'curr"
  },
  {
    "path": "components/announcements/cta.tsx",
    "chars": 1193,
    "preview": "import { Box, Button, Grid, Heading, Text } from 'theme-ui'\nimport Icon from '@hackclub/icons'\nimport NextLink from 'nex"
  },
  {
    "path": "components/announcements/elon.mdx",
    "chars": 2737,
    "preview": "import Amount from './amount'\nimport Signature from '../signature'\n\n# Today, I’m proud to share: Elon&nbsp;Musk is donat"
  },
  {
    "path": "components/announcements/hcb-mobile.mdx",
    "chars": 3501,
    "preview": "I’m Mohamad, a 17-year-old from the SF Bay Area, and I just shipped the official mobile app for HCB.\n\nIf you haven't hea"
  },
  {
    "path": "components/announcements/hcb-open-source.mdx",
    "chars": 2039,
    "preview": "Hack Club launched HCB in 2018 to enable hackathons to raise and spend money\nthrough [fiscal sponsorship](https://hackcl"
  },
  {
    "path": "components/announcements/hcb_cta.tsx",
    "chars": 1177,
    "preview": "import { Box, Button, Grid, Heading, Text } from 'theme-ui'\nimport Icon from '@hackclub/icons'\nimport NextLink from 'nex"
  },
  {
    "path": "components/announcements/holder.tsx",
    "chars": 553,
    "preview": "import { Container, BaseStyles } from 'theme-ui'\n\nexport default function AnnouncementHolder({ children }) {\n  return (\n"
  },
  {
    "path": "components/announcements/pills.tsx",
    "chars": 961,
    "preview": "import { Avatar, Badge, Flex } from 'theme-ui'\n\nexport function PillHolder({ children }) {\n  return (\n    <Flex\n      sx"
  },
  {
    "path": "components/announcements/preston-werner-2022.mdx",
    "chars": 1394,
    "preview": "This gift means a lot to the Hack Club community, and we are grateful for Tom and Theresa’s continued support.\n\nIn 2014,"
  },
  {
    "path": "components/announcements/preston-werner.mdx",
    "chars": 2579,
    "preview": "import Amount from './amount'\n\n# Today, we're proud to share: Tom and Theresa Preston-Werner are donating <Amount amount"
  },
  {
    "path": "components/announcements/relon.mdx",
    "chars": 2325,
    "preview": "import Signature from '../signature'\nimport Signatures from '../signatures'\nimport Image from 'theme-ui'\n\nIn March 2020,"
  },
  {
    "path": "components/arcade/footer.tsx",
    "chars": 1436,
    "preview": "import { Box, Heading, Text, Link } from 'theme-ui'\nimport Footer from '../footer'\n\nconst Description = () => (\n  <Box s"
  },
  {
    "path": "components/arcade/projects.tsx",
    "chars": 9731,
    "preview": "/** @jsxImportSource theme-ui */\nimport React, { useState } from 'react'\nimport styled from '@emotion/styled'\nimport {\n "
  },
  {
    "path": "components/background-image.tsx",
    "chars": 1191,
    "preview": "import { Box } from 'theme-ui'\nimport Image, { StaticImageData } from 'next/image'\n\n/*\n * Use this component inside a co"
  },
  {
    "path": "components/bin/GalleryPosts.tsx",
    "chars": 2415,
    "preview": "/** @jsxImportSource theme-ui */\nimport Image from 'next/image'\nimport styles from '../../public/bin/style/gallery.modul"
  },
  {
    "path": "components/bin/PartTag.module.css",
    "chars": 387,
    "preview": ".tag {\n  color: e1e1e1;\n  padding: 4px 10px;\n  border-radius: 20px;\n  width: fit-content;\n  max-width: 300px;\n  display:"
  },
  {
    "path": "components/bin/PartTag.tsx",
    "chars": 4164,
    "preview": "import React from 'react'\nimport styles from './PartTag.module.css'\nimport { useState } from 'react'\n\nconst PartTag = ({"
  },
  {
    "path": "components/bin/nav.tsx",
    "chars": 496,
    "preview": "import React from 'react'\nimport styles from '../../public/bin/style/gallery.module.css'\n\nconst Nav = () => {\n  return ("
  },
  {
    "path": "components/bin/rsvp-form.tsx",
    "chars": 2160,
    "preview": "/** @jsxImportSource theme-ui */\n\nimport { Checkbox, Input, Label, Text, Box } from 'theme-ui'\nimport useForm from '../."
  },
  {
    "path": "components/bio.tsx",
    "chars": 5639,
    "preview": "/** @jsxImportSource theme-ui */\nimport Icon from '@hackclub/icons'\nimport { useState } from 'react'\nimport { Box, Card,"
  },
  {
    "path": "components/boardbio.tsx",
    "chars": 7441,
    "preview": "/** @jsxImportSource theme-ui */\nimport Icon from '@hackclub/icons'\nimport { useState } from 'react'\nimport { Avatar, Bo"
  },
  {
    "path": "components/color-switcher.tsx",
    "chars": 993,
    "preview": "import { IconButton, useColorMode } from 'theme-ui'\n\nconst ColorSwitcher = props => {\n  const [mode, setMode] = useColor"
  },
  {
    "path": "components/comma.ts",
    "chars": 139,
    "preview": "export default function Comma({ children }) {\n  return children\n    ? children.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/"
  },
  {
    "path": "components/directoryModal.tsx",
    "chars": 9819,
    "preview": "/** @jsxImportSource theme-ui */\n\nexport const badges = [\n  {\n    label: 'Transparent',\n    id: 'Transparent',\n    toolt"
  },
  {
    "path": "components/donate/donors.json",
    "chars": 6218,
    "preview": "{\n  \"1517\": \"http://www.1517fund.com/\",\n  \"Aakash Adesara\": null,\n  \"Abby Fischler\": null,\n  \"Achal Srinivasan\": null,\n "
  },
  {
    "path": "components/donate/sponsors.tsx",
    "chars": 1237,
    "preview": "/** @jsxImportSource theme-ui */\nimport styled from '@emotion/styled'\nimport { Box, Image, Link } from 'theme-ui'\n\nconst"
  },
  {
    "path": "components/dot.tsx",
    "chars": 717,
    "preview": "import { Text } from 'theme-ui'\nimport { keyframes } from '@emotion/react'\n\nconst flashing = keyframes({\n  from: { opaci"
  },
  {
    "path": "components/elon.mdx",
    "chars": 2768,
    "preview": "Elon Musk holds a special place amongst hackers. After growing up in a difficult\nfamily situation in South Africa, worki"
  },
  {
    "path": "components/fade-in.tsx",
    "chars": 609,
    "preview": "import React from 'react'\nimport { Box } from 'theme-ui'\nimport styled from '@emotion/styled'\nimport { keyframes } from "
  },
  {
    "path": "components/fiscal-sponsorship/contact.tsx",
    "chars": 899,
    "preview": "import Icon from '../icon'\nimport { Flex, Link, Text } from 'theme-ui'\n\nconst phoneNumber = '+1 (844) 237-2290'\nconst ph"
  },
  {
    "path": "components/fiscal-sponsorship/directory/card.tsx",
    "chars": 4219,
    "preview": "import { Card, Badge as ThemeBadge, Box, Heading, Text, Image } from 'theme-ui'\nimport { Organization } from '../../../l"
  },
  {
    "path": "components/fiscal-sponsorship/features.tsx",
    "chars": 4698,
    "preview": "import { Box, Heading, Link, Text, Container, Grid } from 'theme-ui'\nimport Icon from '../icon'\nimport { Balancer } from"
  },
  {
    "path": "components/fiscal-sponsorship/first/apply-button.tsx",
    "chars": 744,
    "preview": "import { Button, Text, Flex } from 'theme-ui'\nimport Icon from '../../icon'\nimport Link from 'next/link'\n\nexport default"
  },
  {
    "path": "components/fiscal-sponsorship/first/features.tsx",
    "chars": 11975,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Heading, Link, Text, Container, Card, Image } from 'theme-ui'\nimport Icon"
  },
  {
    "path": "components/fiscal-sponsorship/first/start.tsx",
    "chars": 1309,
    "preview": "import { Box, Link, Text, Heading, Flex } from 'theme-ui'\nimport Stats from './stats'\nimport ApplyButton from './apply-b"
  },
  {
    "path": "components/fiscal-sponsorship/first/stats.tsx",
    "chars": 2833,
    "preview": "import { Text, Box, Flex } from 'theme-ui'\nimport { useEffect, useState } from 'react'\n\nconst easeInOutExpo = x =>\n  x ="
  },
  {
    "path": "components/fiscal-sponsorship/first/testimonials.tsx",
    "chars": 6877,
    "preview": "import {\n  Box,\n  Image,\n  Text,\n  Heading,\n  Container,\n  Grid,\n  Link,\n  Avatar,\n  Button\n} from 'theme-ui'\nimport { S"
  },
  {
    "path": "components/fiscal-sponsorship/open-source.tsx",
    "chars": 2313,
    "preview": "/** @jsxImportSource theme-ui */\n\nimport { Box, Heading, Button, Text, Container, Grid, Flex } from 'theme-ui'\nimport Ic"
  },
  {
    "path": "components/fiscal-sponsorship/organization-spotlight.tsx",
    "chars": 2185,
    "preview": "/** @jsxImportSource theme-ui */\nimport Tilt from '../tilt'\nimport { Card, Heading, Text } from 'theme-ui'\nimport Image "
  },
  {
    "path": "components/fiscal-sponsorship/sign-in.tsx",
    "chars": 938,
    "preview": "/** @jsxImportSource theme-ui */\nimport { useEffect, useState } from 'react'\nimport { Button, Image } from 'theme-ui'\n\ne"
  },
  {
    "path": "components/fiscal-sponsorship/tooltip.tsx",
    "chars": 3133,
    "preview": "import React from 'react'\n\nconst tooltip = direction =>\n  function Tooltip({ children, text, id }) {\n    const escapedTe"
  },
  {
    "path": "components/flag.tsx",
    "chars": 1480,
    "preview": "import theme from '../lib/theme'\nimport styled from '@emotion/styled'\nimport { css, keyframes } from '@emotion/react'\nim"
  },
  {
    "path": "components/flex-col.tsx",
    "chars": 169,
    "preview": "import { Flex } from 'theme-ui'\n\nexport default function FlexCol({ children, ...props }) {\n  return <Flex sx={{ flexDire"
  },
  {
    "path": "components/footer.tsx",
    "chars": 10365,
    "preview": "import React from 'react'\nimport styled from '@emotion/styled'\nimport { Box, Container, Grid, Heading, Link, Text } from"
  },
  {
    "path": "components/force-theme.ts",
    "chars": 278,
    "preview": "import { useEffect } from 'react'\nimport { useColorMode } from 'theme-ui'\n\nconst ForceTheme = ({ theme }) => {\n  const ["
  },
  {
    "path": "components/hackathons/features/marketing.tsx",
    "chars": 3369,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Button, Box, Container, Heading, Text } from 'theme-ui'\nimport usePrefersMotio"
  },
  {
    "path": "components/hackathons/features/slack.tsx",
    "chars": 4111,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Button, Box, Container, Heading, Text, Link } from 'theme-ui'\nimport usePrefer"
  },
  {
    "path": "components/hackathons/keep-exploring.tsx",
    "chars": 2338,
    "preview": "import { Box, Heading, Button, Text, Grid, Container } from 'theme-ui'\nimport Link from 'next/link'\nimport Icon from '.."
  },
  {
    "path": "components/hackathons/landing.tsx",
    "chars": 4452,
    "preview": "import { Box, Button, Heading, Text, Card } from 'theme-ui'\nimport { Fade } from '../react-reveal-compat'\nimport ScrollH"
  },
  {
    "path": "components/hackathons/overview.tsx",
    "chars": 3069,
    "preview": "import { Box, Heading, Container, Text, Grid } from 'theme-ui'\n\nexport default function Overview() {\n  return (\n    <>\n "
  },
  {
    "path": "components/hackathons/recap.tsx",
    "chars": 2593,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Card, Box, Heading, Grid, Text } from 'theme-ui'\nimport Stage from '../stage'\n"
  },
  {
    "path": "components/hackathons/scrolling-hackathons.tsx",
    "chars": 6343,
    "preview": "/** @jsxImportSource theme-ui */\nimport Ticker from 'react-ticker'\nimport {\n  Box,\n  Card,\n  Text,\n  Heading,\n  Badge,\n "
  },
  {
    "path": "components/icon.tsx",
    "chars": 165,
    "preview": "import React from 'react'\nimport Icon from '@hackclub/icons'\n\nexport default function IconComponent(props: any): React.R"
  },
  {
    "path": "components/index/cards/beest.tsx",
    "chars": 3948,
    "preview": "/** @jsxImportSource theme-ui */\nimport CardModel from './card-model'\nimport { Box, Image, Text } from 'theme-ui'\nimport"
  },
  {
    "path": "components/index/cards/button.tsx",
    "chars": 2509,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Button, Text } from 'theme-ui'\nimport ReactTooltip from '../../react-tool"
  },
  {
    "path": "components/index/cards/card-model.tsx",
    "chars": 4050,
    "preview": "import Icon from '../../icon'\nimport { Box, Card, Flex, Image, Link, Text } from 'theme-ui'\nimport ReactTooltip from '.."
  },
  {
    "path": "components/index/cards/clubs.tsx",
    "chars": 2584,
    "preview": "/** @jsxImportSource theme-ui */\nimport Buttons from './button'\nimport CardModel from './card-model'\nimport { Box, Grid,"
  },
  {
    "path": "components/index/cards/fallout.tsx",
    "chars": 2819,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Text, Image } from 'theme-ui'\nimport CardModel from './card-model'\nimport"
  },
  {
    "path": "components/index/cards/flavortown.tsx",
    "chars": 3637,
    "preview": "/** @jsxImportSource theme-ui */\nimport CardModel from './card-model'\nimport { Box, Flex, Grid, Image, Text } from 'them"
  },
  {
    "path": "components/index/cards/hackathons.tsx",
    "chars": 7506,
    "preview": "/** @jsxImportSource theme-ui */\nimport CardModel from './card-model'\nimport { Box, Flex, Grid, Image, Link, Text } from"
  },
  {
    "path": "components/index/cards/haxidraw.tsx",
    "chars": 2213,
    "preview": "/** @jsxImportSource theme-ui */\nimport CardModel from './card-model'\nimport { Box, Flex, Grid, Text } from 'theme-ui'\ni"
  },
  {
    "path": "components/index/cards/hcb.tsx",
    "chars": 4263,
    "preview": "/** @jsxImportSource theme-ui */\nimport CardModel from './card-model'\nimport { Box, Grid, Heading, Text } from 'theme-ui"
  },
  {
    "path": "components/index/cards/hctg.tsx",
    "chars": 3588,
    "preview": "/** @jsxImportSource theme-ui */\nimport CardModel from './card-model'\nimport { Box, Image, Text } from 'theme-ui'\n\nexpor"
  },
  {
    "path": "components/index/cards/horizons.tsx",
    "chars": 3405,
    "preview": "/** @jsxImportSource theme-ui */\nimport CardModel from './card-model'\nimport { Text, Box, Image, Button } from 'theme-ui"
  },
  {
    "path": "components/index/cards/jackpot.tsx",
    "chars": 4566,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Text, Image, Grid, Flex } from 'theme-ui'\nimport CardModel from './card-m"
  },
  {
    "path": "components/index/cards/macondo.tsx",
    "chars": 2802,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Text, Image } from 'theme-ui'\nimport CardModel from './card-model'\nimport"
  },
  {
    "path": "components/index/cards/mailing-list.tsx",
    "chars": 7736,
    "preview": "import Icon from '@hackclub/icons'\nimport { useEffect, useRef, useState } from 'react'\nimport { Box, Button, Card, Flex,"
  },
  {
    "path": "components/index/cards/sinerider.tsx",
    "chars": 2095,
    "preview": "/** @jsxImportSource theme-ui */\nimport CardModel from './card-model'\nimport { Box, Flex, Grid, Image, Text } from 'them"
  },
  {
    "path": "components/index/cards/slack.tsx",
    "chars": 4796,
    "preview": "/** @jsxImportSource theme-ui */\nimport CardModel from './card-model'\nimport { Box, Flex, Grid, Heading, Image, Link, Te"
  },
  {
    "path": "components/index/cards/sleepover.tsx",
    "chars": 5655,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Image, Text } from 'theme-ui'\nimport CardModel from './card-model'\n\nexpor"
  },
  {
    "path": "components/index/cards/sprig-console.tsx",
    "chars": 3721,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Grid, Image, Text } from 'theme-ui'\nimport Buttons from './button'\nimport"
  },
  {
    "path": "components/index/cards/sprig.tsx",
    "chars": 8935,
    "preview": "/** @jsxImportSource theme-ui */\nimport CardModel from './card-model'\nimport { Box, Flex, Grid, Image, Link, Text } from"
  },
  {
    "path": "components/index/cards/stasis.tsx",
    "chars": 2991,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Flex, Image, Text } from 'theme-ui'\nimport CardModel from './card-model'\n"
  },
  {
    "path": "components/index/cards/workshops.tsx",
    "chars": 3186,
    "preview": "/** @jsxImportSource theme-ui */\nimport CardModel from './card-model'\nimport { Box, Card, Flex, Grid, Heading, Image, Te"
  },
  {
    "path": "components/index/carousel-cards.tsx",
    "chars": 2574,
    "preview": "import { Box, Card, Image, Link, Text } from 'theme-ui'\nimport Icon from '../icon'\n\nexport default function CarouselCard"
  },
  {
    "path": "components/index/carousel.tsx",
    "chars": 1469,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Text } from 'theme-ui'\nimport CarouselCards from './carousel-cards'\nimpor"
  },
  {
    "path": "components/index/ctas.tsx",
    "chars": 8128,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Text, Image, Card } from 'theme-ui'\nimport React, { useState } from 'reac"
  },
  {
    "path": "components/index/events.tsx",
    "chars": 2432,
    "preview": "import { Box, Text, Grid, Badge, Flex, Avatar, Heading } from 'theme-ui'\nimport tt from 'tinytime'\nimport Link from 'nex"
  },
  {
    "path": "components/index/github.tsx",
    "chars": 1958,
    "preview": "import { Badge, Image, Text } from 'theme-ui'\nimport RelativeTime from 'react-relative-time'\n\ntype GitHubProps = {\n  typ"
  },
  {
    "path": "components/letterhead.tsx",
    "chars": 2517,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Avatar, Badge, Box, Container, Flex, Heading } from 'theme-ui'\nimport Head fro"
  },
  {
    "path": "components/mail-card.tsx",
    "chars": 1486,
    "preview": "import { Box, Card, Link, Text } from 'theme-ui'\n\nexport default function MailCard({ body, date, link, issue }) {\n  body"
  },
  {
    "path": "components/marquee.tsx",
    "chars": 1402,
    "preview": "import {\n  useRef,\n  useEffect,\n  useState,\n  Children,\n  cloneElement,\n  isValidElement,\n  type ReactNode,\n  type React"
  },
  {
    "path": "components/mention.tsx",
    "chars": 805,
    "preview": "import Image from 'next/image'\nimport Link from 'next/link'\nimport { memo } from 'react'\n\nconst StaticMention = memo(fun"
  },
  {
    "path": "components/nav.tsx",
    "chars": 6544,
    "preview": "import React, { useEffect, useState } from 'react'\nimport styled from '@emotion/styled'\nimport { css, keyframes } from '"
  },
  {
    "path": "components/onboard/gallery-paginated.tsx",
    "chars": 4153,
    "preview": "/** @jsxImportSource theme-ui */\nimport { useEffect, useRef } from 'react'\nimport PaginationButtons from './pagination-b"
  },
  {
    "path": "components/onboard/item.tsx",
    "chars": 723,
    "preview": "/** @jsxImportSource theme-ui */\nimport Image from 'next/image'\nimport { Heading, Card } from 'theme-ui'\n\nconst Item = ("
  },
  {
    "path": "components/onboard/pagination-buttons.tsx",
    "chars": 1239,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Button, Text } from 'theme-ui'\n\nconst PaginationButtons = ({ currentPage,"
  },
  {
    "path": "components/onboard/recap.tsx",
    "chars": 12198,
    "preview": "/** @jsxImportSource theme-ui */\nimport { useEffect, useRef } from 'react'\nimport usePrefersReducedMotion from '../../li"
  },
  {
    "path": "components/onboard/youtube-video.tsx",
    "chars": 777,
    "preview": "import { useMemo } from 'react'\n\nconst YoutubeVideo = ({\n  'youtube-id': youtubeID = 'dQw4w9WgXcQ',\n  list,\n  title = 'Y"
  },
  {
    "path": "components/particles.tsx",
    "chars": 1750,
    "preview": "import Particles from 'react-tsparticles'\nimport React from 'react'\n\nconst Particle = React.memo(function Particle() {\n "
  },
  {
    "path": "components/photo.tsx",
    "chars": 1932,
    "preview": "import styled from '@emotion/styled'\nimport { Card, Text } from 'theme-ui'\nimport Image, { StaticImageData } from 'next/"
  },
  {
    "path": "components/posts/emoji.tsx",
    "chars": 1452,
    "preview": "import { memo, useState, useEffect } from 'react'\nimport Image from 'next/image'\n\nconst stripColons = str => {\n  const c"
  },
  {
    "path": "components/posts/index.tsx",
    "chars": 5566,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Button, Box, Card, Text, Grid, Avatar, Flex } from 'theme-ui'\nimport { formatD"
  },
  {
    "path": "components/posts/mention.tsx",
    "chars": 902,
    "preview": "import { Link, Avatar } from 'theme-ui'\nimport { memo, useState, useEffect } from 'react'\nimport { trim } from 'lodash'\n"
  },
  {
    "path": "components/press.mdx",
    "chars": 1479,
    "preview": "import { Grid } from 'theme-ui'\n\nHack Club is a global nonprofit network of high school makers & student-led coding club"
  },
  {
    "path": "components/react-reveal-compat.tsx",
    "chars": 3522,
    "preview": "import React from 'react'\nimport styled from '@emotion/styled'\nimport { keyframes } from '@emotion/react'\n\nconst kFade ="
  },
  {
    "path": "components/react-tooltip.ts",
    "chars": 143,
    "preview": "import dynamic from 'next/dynamic'\n\nconst ReactTooltip = dynamic(() => import('react-tooltip'), {\n  ssr: false\n})\n\nexpor"
  },
  {
    "path": "components/replit/scale-up.tsx",
    "chars": 1135,
    "preview": "import React, { useState, useEffect, useRef } from 'react'\n\nconst easeInOutExpo = x =>\n  x === 0\n    ? 0\n    : x === 1\n "
  },
  {
    "path": "components/replit/token-instructions.tsx",
    "chars": 3343,
    "preview": "'use client'\n\nimport Icon from '@hackclub/icons'\nimport { useState } from 'react'\nimport { Box, Card, Text, Image, Headi"
  },
  {
    "path": "components/scroll-hint.tsx",
    "chars": 914,
    "preview": "import { Box } from 'theme-ui'\nimport { animate } from 'animejs'\n\nconst handleClick = () => {\n  const scroll = { x: docu"
  },
  {
    "path": "components/secret.tsx",
    "chars": 3736,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Text } from 'theme-ui'\nimport { useState, useEffect } from 'react'\nimport"
  },
  {
    "path": "components/ship/why.mdx",
    "chars": 493,
    "preview": "import { Card } from 'theme-ui'\n\n<Card>\n\n## Your first ship your first day.\n\nStudents in many traditional computer scien"
  },
  {
    "path": "components/signature.tsx",
    "chars": 497,
    "preview": "import { Image, useColorMode } from 'theme-ui'\n\nconst Signature = ({ fname, lname, width }) => {\n  // enforce a sane col"
  },
  {
    "path": "components/signatures.tsx",
    "chars": 483,
    "preview": "import { Image, useColorMode } from 'theme-ui'\n\nconst Signatures = ({ fileName, width }) => {\n  // enforce a sane color "
  },
  {
    "path": "components/slack.tsx",
    "chars": 4246,
    "preview": "import { Button, Box, Container, Heading, Text } from 'theme-ui'\nimport styled from '@emotion/styled'\nimport usePrefersM"
  },
  {
    "path": "components/slide-down.tsx",
    "chars": 685,
    "preview": "import React from 'react'\nimport { Box } from 'theme-ui'\nimport styled from '@emotion/styled'\nimport { keyframes } from "
  },
  {
    "path": "components/slide-up.tsx",
    "chars": 676,
    "preview": "import React from 'react'\nimport { Box } from 'theme-ui'\nimport styled from '@emotion/styled'\nimport { keyframes } from "
  },
  {
    "path": "components/sparkles/index.tsx",
    "chars": 3235,
    "preview": "// Full credit to https://joshwcomeau.com/react/animated-sparkles-in-react/\nimport { useState } from 'react'\nimport styl"
  },
  {
    "path": "components/sparkles/money.tsx",
    "chars": 3882,
    "preview": "// Full credit to https://joshwcomeau.com/react/animated-sparkles-in-react/\nimport { useState } from 'react'\nimport styl"
  },
  {
    "path": "components/stage.tsx",
    "chars": 1286,
    "preview": "import { Box, Heading, Text, ThemeUIStyleObject } from 'theme-ui'\nimport Icon from './icon'\n\ntype StageProps = {\n  icon:"
  },
  {
    "path": "components/stat.tsx",
    "chars": 2057,
    "preview": "import { Flex, Text } from 'theme-ui'\nimport { isEmpty } from 'lodash'\n\ntype StatProps = {\n  value: string | number\n  la"
  },
  {
    "path": "components/submit.tsx",
    "chars": 1326,
    "preview": "import { Button } from 'theme-ui'\nimport theme from '../lib/theme'\n\nconst bg = {\n  default: {\n    bg: 'blue',\n    backgr"
  },
  {
    "path": "components/tilt.tsx",
    "chars": 778,
    "preview": "import React, { useEffect, useRef } from 'react'\nimport VanillaTilt from 'vanilla-tilt'\nimport useMedia from '../lib/use"
  },
  {
    "path": "components/winter/breakdown-box.tsx",
    "chars": 1861,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Card, Heading, Text } from 'theme-ui'\nimport { Zoom } from '../react-reve"
  },
  {
    "path": "components/winter/breakdown.tsx",
    "chars": 2754,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Container, Heading, Grid } from 'theme-ui'\nimport { Fade, Slide } from '."
  },
  {
    "path": "components/winter/footer.tsx",
    "chars": 1377,
    "preview": "import { Box, Heading, Text, Link } from 'theme-ui'\nimport Footer from '../footer'\n\nconst Description = () => (\n  <Box s"
  },
  {
    "path": "components/winter/info.tsx",
    "chars": 5484,
    "preview": "/** @jsxImportSource theme-ui */\nimport {\n  Card,\n  Grid,\n  Box,\n  Container,\n  Heading,\n  Text,\n  Flex,\n  Avatar\n} from"
  },
  {
    "path": "components/winter/landing.tsx",
    "chars": 2926,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Heading, Button, Link, Text, Container } from 'theme-ui'\nimport Snowfall "
  },
  {
    "path": "components/winter/projects.tsx",
    "chars": 9453,
    "preview": "/** @jsxImportSource theme-ui */\nimport { useState } from 'react'\nimport styled from '@emotion/styled'\nimport {\n  Box,\n "
  },
  {
    "path": "components/winter/recap.tsx",
    "chars": 2346,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Button, Container, Heading, Grid, Card, Text } from 'theme-ui'\nimport { Slide,"
  },
  {
    "path": "components/winter/timeline.tsx",
    "chars": 3492,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Flex, Container, Text, Badge, Link } from 'theme-ui'\nimport { Slide } fro"
  },
  {
    "path": "eslint.config.mts",
    "chars": 914,
    "preview": "import { defineConfig, globalIgnores } from 'eslint/config'\nimport nextVitals from 'eslint-config-next/core-web-vitals'\n"
  },
  {
    "path": "lib/cached-hcb-orgs.ts",
    "chars": 864,
    "preview": "const CACHE_FILENAME = 'hcb-orgs-cache.json'\n\nexport async function fetchAllOrganizations() {\n  const fs = require('fs')"
  },
  {
    "path": "lib/countries.json",
    "chars": 5903,
    "preview": "{\n  \"countries\": [\n    \"United States of America (US)\",\n    \"Canada (CA)\",\n    \"United Kingdom of Great Britain and Nort"
  },
  {
    "path": "lib/cta.json",
    "chars": 4310,
    "preview": "[\n  {\n    \"title\": \"Flavortown\",\n    \"logo\": \"https://cdn.hackclub.com/019c76b8-4f54-7de9-ae34-90b2190c2440/TeQ27w.png\","
  },
  {
    "path": "lib/dates.ts",
    "chars": 3149,
    "preview": "export const dt = d => new Date(d).toLocaleDateString()\n\nconst year = new Date().getFullYear()\nexport const tinyDt = d ="
  },
  {
    "path": "lib/fetcher.ts",
    "chars": 166,
    "preview": "/**\n * useSWR() fetcher\n */\nexport default async function fetcher(...args: Parameters<typeof fetch>) {\n  const res = awa"
  },
  {
    "path": "lib/git-info.ts",
    "chars": 235,
    "preview": "export const getGitSha = (): string => {\n  return process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA || 'dev'\n}\n\nexport const"
  },
  {
    "path": "lib/helpers.ts",
    "chars": 6180,
    "preview": "export const dt = d => new Date(d).toLocaleDateString()\n\nconst year = new Date().getFullYear()\nexport const tinyDt = d ="
  },
  {
    "path": "lib/members.ts",
    "chars": 220,
    "preview": "// this could use the slackData lib, but apparently top level awaits are risky\nexport const count: number = 103897\nexpor"
  },
  {
    "path": "lib/organization.ts",
    "chars": 3950,
    "preview": "import GeoPattern from 'geopattern'\n/**\n * Represents an organization.\n */\nexport class Organization {\n  public raw: any"
  },
  {
    "path": "lib/slackData.ts",
    "chars": 354,
    "preview": "type SlackData = {\n  active_users_28d?: number\n  full_members_count?: number\n  total_members_count?: number\n  ds?: strin"
  },
  {
    "path": "lib/sleep.ts",
    "chars": 139,
    "preview": "// Beloved classic utility function :3\nconst sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))\n\nex"
  },
  {
    "path": "lib/theme.ts",
    "chars": 334,
    "preview": "import base from '@hackclub/theme'\nimport { merge } from 'lodash'\n\nconst theme = base\n\ntheme.config.useColorSchemeMediaQ"
  },
  {
    "path": "lib/use-form.ts",
    "chars": 2138,
    "preview": "import { useState, useEffect } from 'react'\n\nconst useForm = (\n  submitURL = '/',\n  callback,\n  options = { clearOnSubmi"
  },
  {
    "path": "lib/use-has-mounted.ts",
    "chars": 304,
    "preview": "// Full credit to https://joshwcomeau.com/snippets/react-hooks/use-has-mounted\nimport React from 'react'\n\nfunction useHa"
  },
  {
    "path": "lib/use-media.ts",
    "chars": 414,
    "preview": "import { useState, useEffect } from 'react'\n\nexport default function useMedia(query) {\n  const [matches, setMatches] = u"
  },
  {
    "path": "lib/use-prefers-motion.ts",
    "chars": 1028,
    "preview": "// Inspired by https://joshwcomeau.com/snippets/react-hooks/use-prefers-reduced-motion\nimport React from 'react'\n\nconst "
  },
  {
    "path": "lib/use-prefers-reduced-motion.ts",
    "chars": 1077,
    "preview": "// Full credit to https://joshwcomeau.com/snippets/react-hooks/use-prefers-reduced-motion\nimport React from 'react'\n\ncon"
  },
  {
    "path": "lib/use-random-interval.ts",
    "chars": 1075,
    "preview": "// Full credit to https://joshwcomeau.com/snippets/react-hooks/use-random-interval\nimport React from 'react'\n\n// Utility"
  },
  {
    "path": "next.config.ts",
    "chars": 11332,
    "preview": "import withMDX from '@next/mdx'\nimport type { NextConfig } from 'next'\n\nconst nextConfig: NextConfig = {\n  reactStrictMo"
  },
  {
    "path": "package.json",
    "chars": 2427,
    "preview": "{\n  \"name\": \"@hackclub/v3\",\n  \"version\": \"0.0.1\",\n  \"author\": \"Lachlan Campbell <lachlan@hackclub.com>\",\n  \"license\": \"M"
  },
  {
    "path": "pages/404.tsx",
    "chars": 4635,
    "preview": "import React from 'react'\nimport styled from '@emotion/styled'\nimport { keyframes } from '@emotion/react'\nimport { Headi"
  },
  {
    "path": "pages/_app.tsx",
    "chars": 866,
    "preview": "import Head from 'next/head'\n\nimport Analytics from '../components/analytics'\nimport { Analytics as VercelAnalytics } fr"
  },
  {
    "path": "pages/_document.tsx",
    "chars": 1249,
    "preview": "import Document, { Html, Head, Main, NextScript } from 'next/document'\n\nconst org = {\n  '@context': 'http://schema.org',"
  },
  {
    "path": "pages/acknowledged.tsx",
    "chars": 3233,
    "preview": "/** @jsxImportSource theme-ui */\nimport { Box, Container, Grid, Text } from 'theme-ui'\nimport Meta from '@hackclub/meta'"
  },
  {
    "path": "pages/amas/geohot.tsx",
    "chars": 10885,
    "preview": "import { Box, Button, Image, Grid, Text, Link } from 'theme-ui'\nimport Head from 'next/head'\nimport Meta from '@hackclub"
  },
  {
    "path": "pages/amas/index.tsx",
    "chars": 7361,
    "preview": "import { Box, Button, Card, Flex, Grid, Heading, Link, Text } from 'theme-ui'\nimport Meta from '@hackclub/meta'\nimport H"
  },
  {
    "path": "pages/amas/sal.tsx",
    "chars": 9515,
    "preview": "import { Box, Button, Image, Grid, Text, Link } from 'theme-ui'\nimport Head from 'next/head'\nimport Meta from '@hackclub"
  },
  {
    "path": "pages/amas/vitalik.tsx",
    "chars": 10516,
    "preview": "import { Box, Button, Image, Grid, Text, Link } from 'theme-ui'\nimport Head from 'next/head'\nimport Meta from '@hackclub"
  },
  {
    "path": "pages/api/arcade/hack-hour/inventory.ts",
    "chars": 2972,
    "preview": "import AirtablePlus from 'airtable-plus'\n\nconst flavorText = async () => {\n  const airtable = new AirtablePlus({\n    api"
  },
  {
    "path": "pages/api/arcade/shop.ts",
    "chars": 1206,
    "preview": "import AirtablePlus from 'airtable-plus'\n\nexport const shopParts = async () => {\n  const baseID = 'app4kCWulfB02bV8Q'\n  "
  },
  {
    "path": "pages/api/bin/gallery/posts.ts",
    "chars": 1062,
    "preview": "import AirtablePlus from 'airtable-plus'\n\nconst fetchPosts = async () => {\n  try {\n    const airtable = new AirtablePlus"
  },
  {
    "path": "pages/api/bin/gallery/tags.ts",
    "chars": 779,
    "preview": "import AirtablePlus from 'airtable-plus'\n\nconst fetchTags = async () => {\n  try {\n    const airtable = new AirtablePlus("
  },
  {
    "path": "pages/api/bin/rsvp.ts",
    "chars": 1127,
    "preview": "// https://airtable.com/appKjALSnOoA0EmPk/tblYYhxN9TaPPMMRV/viwJFvTlmRNHj0Toh?blocks=hide\nimport AirtablePlus from 'airt"
  },
  {
    "path": "pages/api/bin/wokwi/new/[parts].ts",
    "chars": 215,
    "preview": "import { findOrCreateProject } from '.'\n\nexport default async function handler(req, res) {\n  const parts = req.query.par"
  },
  {
    "path": "pages/api/bin/wokwi/new/index.ts",
    "chars": 4368,
    "preview": "import AirtablePlus from 'airtable-plus'\n\nexport const findOrCreateProject = async (partsList = []) => {\n  const airtabl"
  },
  {
    "path": "pages/api/bin/wokwi/parts.ts",
    "chars": 689,
    "preview": "import AirtablePlus from 'airtable-plus'\nimport camelcase from 'camelcase'\n\nconst camelizeObject = obj => {\n  Object.key"
  },
  {
    "path": "pages/api/bucky.ts",
    "chars": 379,
    "preview": "import { NextApiRequest, NextApiResponse } from 'next'\n\nexport default async function handler(\n  req: NextApiRequest,\n  "
  },
  {
    "path": "pages/api/channels/resolve.ts",
    "chars": 618,
    "preview": "export default async function handler(req, res) {\n  // get a public channel name by id\n  const channelDataReq = await fe"
  },
  {
    "path": "pages/api/contribute.ts",
    "chars": 1952,
    "preview": "import { graphql } from '@octokit/graphql'\nimport { createAppAuth } from '@octokit/auth-app'\nimport { NextApiRequest, Ne"
  },
  {
    "path": "pages/api/first-team.ts",
    "chars": 574,
    "preview": "import { NextApiRequest, NextApiResponse } from 'next'\n\nexport default async function handler(\n  req: NextApiRequest,\n  "
  },
  {
    "path": "pages/api/games.ts",
    "chars": 428,
    "preview": "import { NextApiRequest, NextApiResponse } from 'next'\n\nexport async function getGames() {\n  try {\n    const games = awa"
  },
  {
    "path": "pages/api/github.ts",
    "chars": 1745,
    "preview": "import { NextApiRequest, NextApiResponse } from 'next/dist/shared/lib/utils'\nimport { normalizeGitHubCommitUrl } from '."
  },
  {
    "path": "pages/api/join.ts",
    "chars": 3761,
    "preview": "import AirtablePlus from 'airtable-plus'\nimport { NextApiRequest, NextApiResponse } from 'next/dist/shared/lib/utils'\n\nc"
  },
  {
    "path": "pages/api/mailing-list.ts",
    "chars": 651,
    "preview": "import { NextApiRequest, NextApiResponse } from 'next'\n\nexport default async function submit(\n  req: NextApiRequest,\n  r"
  },
  {
    "path": "pages/api/onboard/p/[project]/index.ts",
    "chars": 1489,
    "preview": "// return a project's metadata\n\nimport { getAllOnboardProjects } from '..'\n\nasync function getReadmeData(url) {\n  const "
  },
  {
    "path": "pages/api/onboard/p/count.ts",
    "chars": 285,
    "preview": "import { getAllOnboardProjects } from '.'\n\nexport async function onboardProjectCount() {\n  const projects = await getAll"
  },
  {
    "path": "pages/api/onboard/p/index.ts",
    "chars": 2036,
    "preview": "// returns a list of all projects\n\nexport const getAllOnboardProjects = async () => {\n  const url = 'https://api.github."
  },
  {
    "path": "pages/api/onboard/svg/[board_url]/bottom.ts",
    "chars": 662,
    "preview": "// test me with: curl http://localhost:3000/api/board/svg/https%3A%2F%2Fgithub.com%2Fhackclub%2FOnBoard%2Fraw%2Fmain%2Fp"
  },
  {
    "path": "pages/api/onboard/svg/[board_url]/index.ts",
    "chars": 2807,
    "preview": "import JSZip from 'jszip'\nimport {\n  read,\n  plot,\n  renderLayers,\n  renderBoard,\n  stringifySvg\n} from '@tracespace/cor"
  },
  {
    "path": "pages/api/onboard/svg/[board_url]/top.ts",
    "chars": 729,
    "preview": "// test me with: curl http://localhost:3000/api/board/svg/https%3A%2F%2Fgithub.com%2Fhackclub%2FOnBoard%2Fraw%2Fmain%2Fp"
  },
  {
    "path": "pages/api/replit/signup.ts",
    "chars": 944,
    "preview": "export default async function handler(req, res) {\n  if (req.method === 'POST') {\n    try {\n      const { token, email } "
  },
  {
    "path": "pages/api/sprig-console.ts",
    "chars": 873,
    "preview": "import { NextApiRequest, NextApiResponse } from 'next'\n\nfunction check(val: any) {\n  return val === 'Pending' || val ==="
  },
  {
    "path": "pages/api/stars.ts",
    "chars": 2160,
    "preview": "import { graphql } from '@octokit/graphql'\nimport { NextApiRequest, NextApiResponse } from 'next/dist/shared/lib/utils'\n"
  },
  {
    "path": "pages/api/steve.ts",
    "chars": 2286,
    "preview": "import type { NextApiRequest, NextApiResponse } from 'next'\n\nconst steveApiHandler = async (_req: NextApiRequest, res: N"
  },
  {
    "path": "pages/api/stickers.ts",
    "chars": 2429,
    "preview": "import AirtablePlus from 'airtable-plus'\nimport { NextApiRequest, NextApiResponse } from 'next'\n\nconst peopleTable = new"
  },
  {
    "path": "pages/api/stuff.ts",
    "chars": 925,
    "preview": "import type { NextApiRequest, NextApiResponse } from 'next'\n\nexport default async function stuff(\n  _req: NextApiRequest"
  },
  {
    "path": "pages/api/team.ts",
    "chars": 762,
    "preview": "import teamMembers from '../../public/team.json'\nimport acknowledgedMembers from '../../public/acknowledged.json'\nimport"
  },
  {
    "path": "pages/api/winter-rsvp.ts",
    "chars": 1062,
    "preview": "import type { NextApiRequest, NextApiResponse } from 'next'\nimport AirtablePlus from 'airtable-plus'\n\nconst airtable = n"
  },
  {
    "path": "pages/arcade/index.tsx",
    "chars": 53691,
    "preview": "/** @jsxImportSource theme-ui */\nimport React, { useState } from 'react'\nimport { useRouter } from 'next/router'\nimport "
  },
  {
    "path": "pages/bin/gallery.tsx",
    "chars": 3643,
    "preview": "/** @jsxImportSource theme-ui */\n\nimport BinPost from '../../components/bin/GalleryPosts'\nimport styles from '../../publ"
  },
  {
    "path": "pages/bin/prelaunch.tsx",
    "chars": 15655,
    "preview": "/** @jsxImportSource theme-ui */\nimport {\n  Box,\n  Container,\n  Text,\n  Heading,\n  Card,\n  Flex,\n  Image,\n  Link,\n  Butt"
  },
  {
    "path": "pages/brand.tsx",
    "chars": 9471,
    "preview": "import {\n  Box,\n  Card,\n  Container,\n  Flex,\n  Grid,\n  Heading,\n  Image as ThemeImage,\n  Input,\n  Link as A,\n  Text\n} fr"
  },
  {
    "path": "pages/clubs.tsx",
    "chars": 22801,
    "preview": "import {\n  Badge,\n  Box,\n  Button,\n  Card,\n  Container,\n  Grid,\n  Heading,\n  Link,\n  Text\n} from 'theme-ui'\nimport style"
  },
  {
    "path": "pages/content/covid19.mdx",
    "chars": 3371,
    "preview": "import Letterhead from '../../components/letterhead'\n\n<Letterhead\ntitle=\"COVID-19\"\ndesc=\"An update from Hack Club HQ on "
  }
]

// ... and 74 more files (download for full content)

About this extraction

This page contains the full source code of the hackclub/site GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 274 files (1.3 MB), approximately 358.9k tokens, and a symbol index with 287 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!