Merge branch 'main' into main

This commit is contained in:
Toby Brown 2024-05-20 20:53:18 +01:00 committed by GitHub
commit 72edf8fefa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 853 additions and 356 deletions

View file

@ -1,3 +1,4 @@
import { getCookie, hasCookie } from 'cookies-next'
import {
Box,
Card,
@ -11,7 +12,6 @@ import {
} from 'theme-ui'
import useForm from '../../lib/use-form'
import Submit from '../submit'
import { getCookie, hasCookie } from 'cookies-next'
import { withRouter } from 'next/router'
@ -23,10 +23,10 @@ const JoinForm = ({ sx = {}, router }) => {
method: 'POST',
initData: hasCookie('continent')
? {
continent: getCookie('continent'),
reason: router.query.reason,
event: router.query.event
}
continent: getCookie('continent'),
reason: router.query.reason,
event: router.query.event
}
: { reason: router.query.reason, event: router.query.event }
})
@ -77,7 +77,7 @@ const JoinForm = ({ sx = {}, router }) => {
/>
</Label>
<Label>
Education level
School level
<Select
{...useField('year')}
required
@ -93,10 +93,10 @@ const JoinForm = ({ sx = {}, router }) => {
</Label>
</Grid>
<Label>
Why do you want to join the Hack Club Slack?
How did you hear about us/the Slack? What are you most looking forward to?
<Textarea
{...useField('reason')}
placeholder="Write a few sentences."
placeholder="I heard about Hack Club from..."
required
/>
</Label>
@ -120,7 +120,7 @@ const JoinForm = ({ sx = {}, router }) => {
status={status}
mt={'0px!important'}
labels={{
default: useWaitlist ? 'Join Waitlist' : 'Get Invite',
default: useWaitlist ? 'Join Waitlist' : 'Join Now',
error: 'Something went wrong',
success: useWaitlist
? "You're on the Waitlist!"

View file

@ -34,7 +34,7 @@ const projects = [
{
title: 'A chat app and cell phone carrier.',
description:
'The teenage PurpleBubble team are building a private, secure and open source chat app and cell phone carrier',
'The teenage PurpleBubble team are building a private, secure and open source chat app',
img: 'purplebubble',
color: ['#5bc0de', '#88e5f8'],
itemId: 4

View file

@ -17,6 +17,15 @@
"img": "https://cloud-eg2ex8nol-hack-club-bot.vercel.app/0favicon-on-light-removebg-preview.png",
"link": "https://cpu.land"
},
{
"background": "#e5e6da",
"titleColor": "black",
"descriptionColor": "black",
"title": "The Bin",
"description": "A free electronics starter kit for high schoolers, shipped to your door.",
"img": "https://cloud-e3pxf7bt9-hack-club-bot.vercel.app/0ezgif.com-resize.gif",
"link": "https://hackclub.com/bin"
},
{
"background": "#000",
"titleColor": "green",

View file

@ -274,6 +274,18 @@ const nextConfig = {
{
source: '/how-to-organize-a-hackathon/style.css',
destination: 'https://expandables.hackclub.dev/style.css'
},
{
source: '/bin/',
destination: '/bin/index.html'
},
{
source: '/bin/:path*',
destination: '/bin/:path*'
},
{
source: '/bin/selector/',
destination: '/bin/selector/index.html'
}
]
},

View file

@ -1,4 +1,18 @@
import OpenAI from 'openai';
import AirtablePlus from "airtable-plus"
const saveProject = async (parts = [], idea) => {
const airtable = new AirtablePlus({
apiKey: process.env.AIRTABLE_API_KEY,
baseID: 'appKjALSnOoA0EmPk',
tableName: 'Cached Ideas'
})
const cacheName = parts.sort().join(',')
airtable.create({
"Name": cacheName,
"Recommendation": idea
})
}
const sample = (arr) => arr[Math.floor(Math.random() * arr.length)]
@ -9,7 +23,7 @@ const messageStarters = [
"how about a",
"you could make a",
"as a raccoon, i'd build a",
"i live in the trash and i'd build a",
// "i live in the trash and i'd build a",
]
const generateProjectIdea = async (parts) => {
@ -47,6 +61,7 @@ export default async function handler(req, res) {
})
const recommendation = await generateProjectIdea(parts)
await saveProject(parts, recommendation)
res.send({ recommendation, parts })
}

View file

@ -0,0 +1,7 @@
import { findOrCreateProject } from "."
export default async function handler(req, res) {
const parts = req.query.parts.split('|')
const shareLink = await findOrCreateProject(parts)
res.redirect(shareLink)
}

View file

@ -1,6 +1,36 @@
import AirtablePlus from "airtable-plus"
const createProject = async (partsList=[]) => {
export const findOrCreateProject = async (partsList = []) => {
const airtable = new AirtablePlus({
apiKey: process.env.AIRTABLE_API_KEY,
baseID: 'appKjALSnOoA0EmPk',
tableName: 'Cached Projects'
})
const cacheName = partsList.sort().join(',')
const existingProject = await airtable.read({
filterByFormula: `{Name}="${cacheName}"`,
maxRecords: 1
})
if (existingProject.length > 0) {
return existingProject[0].fields['Share Link']
} else {
const shareLink = await createProject(partsList)
if (shareLink) {
await airtable.create({
"Name": cacheName,
"Share Link": shareLink
})
return shareLink
} else {
return null
}
}
}
const createProject = async (partsList = []) => {
const airtable = new AirtablePlus({
apiKey: process.env.AIRTABLE_API_KEY,
baseID: 'appKjALSnOoA0EmPk',
@ -11,7 +41,7 @@ const createProject = async (partsList=[]) => {
const PADDING = 30;
const MAX_WIDTH = 320; // big question mark on this one
const ROW_HEIGHT = 215; // close enough for jazz, keypad is too big for this but ¯\_(ツ)_/¯
const parts = [
{ "type": "board-pi-pico-w", "id": "pico", "top": 0, "left": 0, "attrs": {} }
]
@ -24,7 +54,7 @@ const createProject = async (partsList=[]) => {
})
return airPart[0].fields['Wokwi Name'].split(',').forEach((name, i) => {
const width = airPart[0].fields['Wokwi X-Offset'];
if((x + width + PADDING) > MAX_WIDTH) {
if ((x + width + PADDING) > MAX_WIDTH) {
x = 0;
y += ROW_HEIGHT;
}
@ -40,29 +70,32 @@ const createProject = async (partsList=[]) => {
const body = JSON.stringify({
name: "The Bin!",
unlisted: false,
unlisted: true,
files: [{
name: "help.md",
content: `# Welcome to The Bin! 🦝
Now that you've thrown some parts into The Bin, it's time to turn that trash into treasure! 🗑💎
Wire up your parts and write some code to make them work together.
Wire up your parts and write some code to make them work together. If you need
help with a part, click the "?" above it.
If you'd like a tutorial, check out this short explainer on making a blinking LED:
https://github.com/hackclub/hackclub/pull/1860/files?short_path=0494126
If you want to see examples, check here:
https://hack.club/bin-example
You can get help by chatting with other high schoolers on the Hack Club Slack in the #electronics channel:
You can get help by chatting with other high schoolers on the Hack Club Slack in
the #electronics channel:
👉 https://hackclub.com/slack 👈
Once you're ready build your design IRL, click the "Share" button and submit your design:
https://forms.hackclub.com/t/adnj7zfgTyus
Once you're ready build your design IRL, click the "Share" button and submit
your design:
https://hack.club/bin-submit
`
},
{
name: "sketch.ino",
content: `// Now turn this trash into treasure!
// Want some help? You can chat with us on the Hack Club Slack in the #electronics channel
void setup() {
// put your setup code here, to run once:
Serial1.begin(115200);
@ -107,7 +140,7 @@ export default async function handler(req, res) {
if (req.method === 'POST') {
const { parts } = req.body
const shareLink = await createProject(parts)
const shareLink = await findOrCreateProject(parts)
if (shareLink) {
res.status(200).json({ shareLink })
} else {

View file

@ -55,7 +55,8 @@ export default async function handler(req, res) {
'HCB account URL': `https://hcb.hackclub.com/${r.slug}`,
'Contact Option': data.contactOption,
'Slack Username': data.slackUsername,
Accommodations: data.accommodations
Accommodations: data.accommodations,
'HCB ID': r.id
})
res.writeHead(302, { Location: '/hcb/apply/success' }).end()
})

View file

@ -12,17 +12,17 @@ import {
} from 'theme-ui'
import Head from 'next/head'
import Meta from '@hackclub/meta'
import Nav from '../components/nav'
import Nav from '../../components/nav'
import { useEffect, useState, useRef } from 'react'
import Footer from '../components/footer'
import Footer from '../../components/footer'
import { keyframes } from '@emotion/react'
import RsvpForm from '../components/bin/rsvp-form'
import RsvpForm from '../../components/bin/rsvp-form'
import { Fade } from 'react-reveal'
import ForceTheme from '../components/force-theme'
import ForceTheme from '../../components/force-theme'
import JSConfetti from 'js-confetti'
import Sparkles from '../components/sparkles'
import Sparkles from '../../components/sparkles'
import Icon from "@hackclub/icons"
import Announcement from '../components/announcement'
import Announcement from '../../components/announcement'
import { TypeAnimation } from 'react-type-animation'
const RsvpCount = () => {

View file

@ -204,9 +204,9 @@ function Page({
gradient="linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.45))"
/>
<Announcement
copy="Hop OnBoard and create your first PCB"
caption="Join 1,000 others to create your first circuit board."
href="https://hackclub.com/onboard/"
copy="Get a free hardware starter kit!"
caption="Join 100s of other high schoolers to create your first electronics project."
href="/bin/"
iconLeft="idea"
/>
<Box

View file

@ -0,0 +1,3 @@
<svg width="41" height="45" viewBox="0 0 41 45" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.8614 16.1009H0V29.3119H17.8614V45L40.5 23L17.8614 0.5V16.1009Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 195 B

View file

@ -1,4 +1,4 @@
<svg width="94" height="93" viewBox="0 0 94 93" fill="none" xmlns="http://www.w3.org/2000/svg">
<ellipse cx="47" cy="46.5" rx="46.5" ry="47" transform="rotate(90 47 46.5)" fill="#9FEEB5"/>
<path d="M70 39.5932L62.95 32L46.5 47.1864L30.05 32L23 39.5932L46.5 60L70 39.5932Z" fill="#1E1E1E"/>
<?xml version="1.0" encoding="UTF-8"?>
<svg width="47" height="28" fill="none" version="1.1" viewBox="0 0 47 28" xmlns="http://www.w3.org/2000/svg">
<path d="M 47,7.5932 39.95,0 23.5,15.1864 7.05,0 0,7.5932 23.5,28 Z" fill="#fff"/>
</svg>

Before

Width:  |  Height:  |  Size: 297 B

After

Width:  |  Height:  |  Size: 240 B

View file

@ -5,9 +5,9 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The Bin</title>
<link rel="stylesheet" href="../style/common.css">
<link rel="stylesheet" href="./style.css">
<link rel="stylesheet" href="../style/footer.css">
<link rel="stylesheet" href="./style/common.css">
<link rel="stylesheet" href="./landing-new/style.css">
<link rel="stylesheet" href="./style/footer.css">
<link rel="icon" type="image/png" sizes="32x32" href="https://assets.hackclub.com/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="https://assets.hackclub.com/favicons/favicon-16x16.png">
<script src="https://awdev.codes/utils/smoothScroll.js"></script>
@ -15,46 +15,97 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.2.4/howler.core.min.js"
integrity="sha512-d00Brs/+XQUUaO0Y9Uo8Vw63o7kS6ZcLM2P++17kALrI8oihAfL4pl1jQObeRBgv06j7xG0GHOhudAW0BdrycA=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="./script.js"></script>
<script src="./landing-new/script.js"></script>
<script src="./data-loading.js"></script>
<script defer data-domain="hackclub.com" src="https://plausible.io/js/script.js"></script>
<script>
window['_fs_host'] = 'fullstory.com';
window['_fs_script'] = 'edge.fullstory.com/s/fs.js';
window['_fs_org'] = 'ARN0J';
window['_fs_namespace'] = 'FS';
!function(m,n,e,t,l,o,g,y){var s,f,a=function(h){
return!(h in m)||(m.console&&m.console.log&&m.console.log('FullStory namespace conflict. Please set window["_fs_namespace"].'),!1)}(e)
;function p(b){var h,d=[];function j(){h&&(d.forEach((function(b){var d;try{d=b[h[0]]&&b[h[0]](h[1])}catch(h){return void(b[3]&&b[3](h))}
d&&d.then?d.then(b[2],b[3]):b[2]&&b[2](d)})),d.length=0)}function r(b){return function(d){h||(h=[b,d],j())}}return b(r(0),r(1)),{
then:function(b,h){return p((function(r,i){d.push([b,h,r,i]),j()}))}}}a&&(g=m[e]=function(){var b=function(b,d,j,r){function i(i,c){
h(b,d,j,i,c,r)}r=r||2;var c,u=/Async$/;return u.test(b)?(b=b.replace(u,""),"function"==typeof Promise?new Promise(i):p(i)):h(b,d,j,c,c,r)}
;function h(h,d,j,r,i,c){return b._api?b._api(h,d,j,r,i,c):(b.q&&b.q.push([h,d,j,r,i,c]),null)}return b.q=[],b}(),y=function(b){function h(h){
"function"==typeof h[4]&&h[4](new Error(b))}var d=g.q;if(d){for(var j=0;j<d.length;j++)h(d[j]);d.length=0,d.push=h}},function(){
(o=n.createElement(t)).async=!0,o.crossOrigin="anonymous",o.src="https://"+l,o.onerror=function(){y("Error loading "+l)}
;var b=n.getElementsByTagName(t)[0];b&&b.parentNode?b.parentNode.insertBefore(o,b):n.head.appendChild(o)}(),function(){function b(){}
function h(b,h,d){g(b,h,d,1)}function d(b,d,j){h("setProperties",{type:b,properties:d},j)}function j(b,h){d("user",b,h)}function r(b,h,d){j({
uid:b},d),h&&j(h,d)}g.identify=r,g.setUserVars=j,g.identifyAccount=b,g.clearUserCookie=b,g.setVars=d,g.event=function(b,d,j){h("trackEvent",{
name:b,properties:d},j)},g.anonymize=function(){r(!1)},g.shutdown=function(){h("shutdown")},g.restart=function(){h("restart")},
g.log=function(b,d){h("log",{level:b,msg:d})},g.consent=function(b){h("setIdentity",{consent:!arguments.length||b})}}(),s="fetch",
f="XMLHttpRequest",g._w={},g._w[f]=m[f],g._w[s]=m[s],m[s]&&(m[s]=function(){return g._w[s].apply(this,arguments)}),g._v="2.0.0")
}(window,document,window._fs_namespace,"script",window._fs_script);
</script>
</head>
<body>
<img src="https://awdev.codes/images/ww.gif" style="display:none;">
<section class="landing-section section">
<div class="landing-header">
<img src="../icons/icon.svg" class="landing-logo">
<img src="./icons/icon.svg" class="landing-logo">
<span class="landing-tagline">The beginner hardware kit designed just for you</span>
<span class="landing-tagline">Free for high schoolers</span>
<img src="../parts/pico.png" class="landing-main-image">
<img src="./parts/pico.png" class="landing-main-image">
</div>
<img id="floaty" src="../parts/relay.png" style="top: 20%; left: 7%;">
<img id="floaty" src="../parts/mic.png" style="top: 80%; left: 20%;animation-delay: -2500ms;">
<img id="floaty-left" src="../parts/humidity.png"
style="top: 80%; right:10%;animation-delay: -1000ms;"><!---animation-delay: -2s;-->
<img id="floaty-left" src="../parts/laser.png"
style="top: 30%; right:10%;animation-delay: -1500ms;"><!---animation-delay: -2s;-->
<img src="../icons/scrolldown.svg" class="scroll-prompt" onclick="smoothScroll('.timeline')">
<img src="../images/idea.png" class="huh floaty" style="animation-delay: -3000ms;">
<a class="floaty" style="top: 20%; left: 7%;" href="https://wokwi.com/projects/398014537125976065" target="_blank">
<img src="https://cloud-ofybe0euz-hack-club-bot.vercel.app/00oky3527-max7219-dot-matrix-module-single-3.png">
</a>
<a class="floaty" style="top: 80%; left: 20%; animation-delay: -2500ms;" href="https://wokwi.com/projects/346178932556431954" target="_blank">
<img src="https://cloud-6hdo013ly-hack-club-bot.vercel.app/0buzzer.png">
</a>
<a class="floaty" style="top: 80%; right:10%;animation-delay: -1000ms;" href="https://wokwi.com/projects/383628008466438145" target="_blank">
<img src="./parts/humidity.png">
</a>
<a class="floaty" style="top: 30%; right:10%;animation-delay: -1500ms;" href="https://wokwi.com/projects/390119173913012225" target="_blank">
<img src="./parts/led.png">
</a>
<div class="scroll-prompt" onclick="smoothScroll('.timeline')">
<img src="./icons/scrolldown.svg">
</div>
<a href="" id="meme" target="_blank" class="huh floaty hoverable" style="animation-delay: -3000ms;">
<img src="./images/idea.png" width="100%">
</a>
</section>
<section class="section container timeline">
<section class="section container timeline" style="max-width:71em;">
<!-- timeline of project -->
<h1>What will you make<br/><em>before summer break?</em></h1>
<h1 class="timeline-header">
What will you make
</h1>
<h2 class="timeline-subheader">
before summer break?
</h2>
<div class="timeline-list">
<div class="timeline-item" onclick="smoothScroll('.gambling-section')" style="cursor: pointer;">
<em class="muted">Right now...</em>
<h2>Rummage for parts</h2>
<p>Dig up some parts from our part picker or choose your own! Don't have an idea yet? Ask the raccoon for some inspiration!</p>
<div class="timeline-item hoverable greenbutton" onclick="smoothScroll('.gambling-section')"
style="cursor: pointer;">
<div class="timeline-info">
<em class="muted">Right now...</em>
<h2>Rummage for parts</h2>
<p>Dig up some parts from our part picker or choose your own! Don't have an idea yet? Ask the
raccoon
for some inspiration!</p>
</div>
</div>
<div class="timeline-item">
<em class="muted">over 3-4 days...</em>
<h2>Design your project</h2>
<p>Build a project in the online editor and program it! Get support from <a href="https://hackclub.com/slack" target="_blank">other high schoolers in an online community</a>.</p>
<div class="timeline-item hoverable bluebutton">
<div class="timeline-info">
<em class="muted">over 3-4 days...</em>
<h2>Design your project</h2>
<p>Build a project in the online editor and program it! Get support from <a
href="https://hackclub.com/slack" target="_blank">other high schoolers in an online
community</a>.</p>
</div>
</div>
<div class="timeline-item">
<em class="muted">in 1 week...</em>
<h2>Get it IRL</h2>
<p><a href="https://hack.club/bin-submit" target="_blank">Submit your design to the gallery</a> of projects so other high schoolers can learn from your project.</p>
<div class="timeline-item hoverable redbutton">
<div class="timeline-info">
<em class="muted">in 1 week...</em>
<h2>Get it IRL</h2>
<p><a href="https://hack.club/bin-submit" target="_blank">Submit your design to the gallery</a> of
projects so other high schoolers can learn from your project.</p>
</div>
</div>
</div>
</section>
@ -62,93 +113,140 @@
<div class="gambling-header">
<div class="gambling-header-text">
<h1 class="gambling-title">Rummage!</h1>
<h2 class="gambling-subheader">Let's get you your parts!</h2>
<h2 class="gambling-subheader">Let's get those parts!</h2>
</div>
<img src="./rummaging.png" class="gambling-header-rummage">
<img src="./landing-new/rummaging.png" class="gambling-header-rummage">
</div>
<button onclick="rollParts(this)" class="gambling-roll hoverable disabled redbutton">Roll!</button>
<div class="gambling-ui">
<div class="gambling-spinner">
<div class="gambling-item-wrapper">
<img class="gambling-placeholder" src="./qmark.svg">
<img class="gambling-placeholder" src="./landing-new/qmark.svg">
</div>
</div>
<div class="spinner-separator">+</div>
<div class="gambling-spinner">
<div class="gambling-item-wrapper">
<img class="gambling-placeholder" src="./qmark.svg">
<img class="gambling-placeholder" src="./landing-new/qmark.svg">
</div>
</div>
<div class="spinner-separator">+</div>
<div class="gambling-spinner">
<div class="gambling-item-wrapper">
<img class="gambling-placeholder" src="./qmark.svg">
<img class="gambling-placeholder" src="./landing-new/qmark.svg">
</div>
</div>
</div>
<div class="gambling-controls">
<button onclick="rollParts(this)" class="gambling-roll hoverable disabled">Roll!</button>
<span class="flex-lb"></span>
<button onclick="location.href='../selector/index.html'" class="gambling-select hoverable">Manual
<!-- <button onclick="location.href='./selector/'" class="gambling-select hoverable bluebutton">Manual
Selection</button>
<button onclick="generateBuildLink(this)" class="gambling-build hoverable disabled">Continue<img
src="../icons/arrow.svg"></button>
<button onclick="generateBuildLink(this)" class="gambling-build hoverable disabled greenbutton">Continue<img
src="./icons/arrow.svg"></button> -->
</div>
</section>
<section class="project-idea-section section">
<section class="project-idea-section section container">
<div class="project-idea-container">
<h1>What are we building today?</h1>
<textarea id="project-name" placeholder="I'm going to build a..."></textarea>
<h1>💡 Need an idea? Click the raccoon!</h1>
<h1 class="project-idea-title">
What are you waiting for?
</h1>
<div class="hidden" style="text-align: center;">
<h3>Get started or click the raccoon for project ideas!</h3>
<p><em>(It doesn't know much about electronics, but it'll try its best.)</em></p>
<div style="justify-content: center; display: grid;">
<p id="project-idea" class="thought">🗑️</p>
<img src="./images/idea.png" class="hoverable"
style="margin: 0 auto; display: inline; max-width: 10em; height: auto;"
id="generate-project-idea" onclick="generateProjectIdea()">
</div>
</div>
<div class="cta-container">
<button onclick="location.href='./selector/'" class="gambling-select hoverable bluebutton">Manual
Selection
</button>
<button onclick="generateBuildLink(this)" class="gambling-build hoverable greenbutton disabled"
style="margin-top: 1em; margin-bottom: 1em">
Open the editor
<img src="./icons/arrow_white.svg">
</button>
</div>
<!-- <div class="project-idea-images">
<img src="./parts/humidity.png">
<img src="./parts/humidity.png">
<img src="./parts/humidity.png">
</div>
<h1>Need an idea?<br>Tap the raccoon!</h1>
<p><em>(It doesn't know much about electronics, but it'll try its best.)</em></p>
<div style="display: flex;">
<div>
<img src="../images/idea.png" class="hoverable"
<img src="./images/idea.png" class="hoverable"
style="margin: 0 auto; display: inline; max-width: 10em; height: auto;"
id="generate-project-idea" onclick="generateProjectIdea()">
</div>
<p id="project-idea" class="thought">🗑️</p>
</div>
<textarea id="project-name" placeholder="I'm going to build a..."></textarea>
<button id="project-idea-build" class="hoverable">
Let's build!
<img src="./icons/arrow.svg">
</button> -->
</div>
</section>
<section class="section container">
<h1>Readme</h1>
<section class="faq-section section container">
<h1>Any questions?</h1>
<div class="faq-grid">
<div class="faq-item">
<h3>How many projects can I build?</h3>
<p>You can submit as many projects as you want! For second submissions, well ship the parts you dont have for example, your first project will get a pico included and subsequent projects wont ship with it.</p>
<h1>How many projects can I build?</h1>
<p>You can submit <a href="https://cloud-mymt66p99-hack-club-bot.vercel.app/5screenshot_2024-05-16_at_00.17.34.png">as many projects as you make</a>! For second submissions, well ship the parts you dont
have for example, your first project will get a pico included and subsequent projects wont ship
with it.</p>
</div>
<div class="faq-item">
<h3>How much does it cost?</h3>
<p>100% free well also give a breadboard and the jumper wires you need to build your project too! The whole program is funded by <a href="https://hcb.hackclub.com/donations/start/the-bin">donations to a non-profit</a>.</p>
<h1>How much does it cost?</h1>
<p>100% free well also give a breadboard and the jumper wires you need to build your project too! The
whole program is funded by <a href="https://hcb.hackclub.com/donations/start/the-bin">donations to a
non-profit</a>.</p>
</div>
<div class="faq-item">
<h3>Who is eligible?</h3>
<p>You need to be a high schooler (or younger) in the United States. Submissions need to be in by June 1st to qualify.</p>
<h1>Who is eligible?</h1>
<p>You need to be a high schooler (or younger) in the United States. Submissions need to be in by June
1st to qualify.</p>
</div>
<div class="faq-item">
<h3>What do I need?</h3>
<p>Just a browser simulate & computer to upload your code to the pico well give you all the equipment you need for your circuit.</p>
<h1>What do I need?</h1>
<p>Just a browser simulator & computer to upload your code to the pico well give you all the equipment
you need for your circuit.</p>
</div>
<div class="faq-item">
<h3>I need help!</h3>
<p>Get it in the #electronics channel of the <a href="https://hackclub.com/slack">Hack&nbsp;Club&nbsp;Slack</a>.</p>
<h1>I need help!</h1>
<p>Get it in the #electronics channel of the <a
href="https://hackclub.com/slack">Hack&nbsp;Club&nbsp;Slack</a>.</p>
</div>
<div class="faq-item">
<h3>What designs are allowed?</h3>
<p>Check out the <a href="">list of eligible parts</a>! Each design can have up to 8 modules, and need at least 1 module.</p>
<h1>What designs are allowed?</h1>
<p>Check out the <a href="/bin/selector">list of eligible parts</a>! Each design can have up to 8 modules, and need
at least 1 module.</p>
</div>
</div>
</section>
<footer>
<div class="footer-wrapper">
<div class="footer-information">
<h3 class="footer-information-header">
<p class="footer-information-header">
A project by
<a href="https://hackclub.com">Hack Club</a>. Always <a href="https://github.com/hackclub/site">open
source</a>.
</p>
<p>
<a href="https://hackclub.com/bin/prelaunch">< Prelaunch site</a>
Thank you:
<a href="https://awdev.codes" target="_blank">Aaron Wong</a>,
<a href="https://github.com/kvnyng" target="_blank">Kevin Yang</a>,
<a href="https://maxwofford.com" target="_blank">Max Wofford</a>
and
<a href="https://awdev.codes" target="_blank">Aaron Wong</a>.
</h3>
Caleb Denio,
Charlie 24c02,
& <a href="https://maxwofford.com" target="_blank">Max Wofford</a>
</p>
<p>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 removing barriers
to hardware access so any teenager can explore. In the past few years, we
@ -310,7 +408,8 @@
<p class="footer-cr-info">© 2024 Hack&nbsp;Club. 501(c)(3) nonprofit (EIN: 81-2908499)</p>
</div>
</footer>
<script src="./gambling.js"></script>
<script src="./landing-new/gambling.js"></script>
<script src="./memes.js"></script>
</body>
</html>

View file

@ -119,36 +119,41 @@ function addComponentsToPage(data) {
})
}
function rollParts(el) {
if (el.classList.contains("disabled")) {
return
function sample(arr) {
return arr[Math.floor(Math.random() * arr.length)]
}
function rollPartsAnimation(ms = 1000) {
for (let i = 0; i < ms; i += 100) {
setTimeout(() => {
randomizeParts()
}, i)
}
if (!rolled) {
document.querySelectorAll(".gambling-item-wrapper").forEach((element) => {
element.removeChild(element.firstElementChild)
})
addComponentsToPage(fetchedParts)
}
rolled = true
document.querySelector(".gambling-build").classList.remove("disabled")
setTimeout(() => {
randomizeParts()
}, ms + 200)
setTimeout(() => {
randomizeParts()
}, ms + 500)
}
function randomizeParts() {
let chosenParts = []
const numPartsNeeded = document.querySelectorAll(".gambling-item-wrapper").length
// for the first one, pick an input component
const inputParts = fetchedParts.filter((part) => part.type == "Input");
const inputPartIndex = Math.floor(Math.random() * inputParts.length)
chosenParts.push(inputParts[inputPartIndex])
console.log(`For the input part, we picked ${inputParts[inputPartIndex].name}`)
const inputPart = sample(inputParts)
chosenParts.push(inputPart)
console.log(`For the input part, we picked ${inputPart.name}`)
// for the second one, pick an output component
const outputParts = fetchedParts.filter((part) => part.type == "Output");
const outputPartIndex = Math.floor(Math.random() * outputParts.length)
chosenParts.push(outputParts[outputPartIndex])
console.log(`For the output part, we picked ${outputParts[outputPartIndex].name}`)
const outputPart = sample(outputParts)
chosenParts.push(outputPart)
console.log(`For the output part, we picked ${outputPart.name}`)
// for the rest, pick any component
for (let i = 2; i < numPartsNeeded; i++) {
let partIndex = Math.floor(Math.random() * fetchedParts.length)
chosenParts.push(fetchedParts[partIndex])
console.log(`For the ${i}th part, we picked ${fetchedParts[partIndex].name}`)
}
const unusedParts = fetchedParts.filter((part) => part.name != inputPart.name && part.name != outputPart.name)
const thirdPart = sample(unusedParts)
chosenParts.push(thirdPart)
console.log(`For the third part, we picked ${thirdPart.name}`)
let chosenPartNames = []
document.querySelectorAll(".gambling-item-wrapper").forEach((element, key) => {
let thisPart = chosenParts[key]
@ -165,6 +170,25 @@ function rollParts(el) {
selectedParts = chosenPartNames
}
const rollSound = new Howl({ src: 'https://cloud-eclxkeatl-hack-club-bot.vercel.app/0mario-kart-item-box-sound-mp3cut_audio.mp4'})
function rollParts(el) {
if (el.classList.contains("disabled")) {
return
}
if (!rolled) {
document.querySelectorAll(".gambling-item-wrapper").forEach((element) => {
element.removeChild(element.firstElementChild)
})
addComponentsToPage(fetchedParts)
rolled = true
}
document.querySelector(".gambling-build").classList.remove("disabled")
rollSound.play()
rollPartsAnimation(1200)
}
async function generateBuildLink(e) {
if (!rolled) {
@ -172,39 +196,23 @@ async function generateBuildLink(e) {
}
e.classList.add("disabled")
e.classList.add("loading")
const payload = {
parts: selectedParts
};
try {
const response = await fetch('/api/bin/wokwi/new/', {
mode: 'cors',
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
})
if (!response.ok) {
throw new Error('Network response was not ok');
}
const json = await response.json()
const shareLink = json.shareLink
const parts = encodeURI(selectedParts.join('|'))
const origin = window.location.origin
const url = new URL(`${origin}/api/bin/wokwi/new/${parts}`)
window.open(url, '_blank').focus()
window.open(shareLink, '_blank').focus()
} catch (error) {
console.error('Error:', error)
// e.classList.add("error")
}
e.classList.remove("disabled")
e.classList.remove("loading")
}
window.addEventListener("load", async (e) => {
fetchedParts = await partsData()
fetchedParts = (await partsData()).filter(p => p.rollable)
document.querySelector(".gambling-roll").classList.remove("disabled")
})
async function yap(text) {
async function yap(text, letterCallback) {
text = text.toLowerCase();
const yap_queue = [];
for (let i = 0; i < text.length; i++) {
@ -217,28 +225,31 @@ async function yap(text) {
yap_queue.push(yap_sounds.talking['th']);
continue;
} else if (char === 'h' && (text[i - 1] === 's' || text[i - 1] === 't')) { // test if previous letter was 's' or 't' and current letter is 'h'
yap_queue.push(yap_sounds.talking['_']);
continue;
} else if (char === ',' || char === '?' || char === '.') {
yap_queue.push(yap_sounds.talking['_']);
continue;
} else if (char === text[i - 1]) { // skip repeat letters
yap_queue.push(yap_sounds.talking['_']);
continue;
}
} catch (e) {
// who cares. pick up a foot ball
}
if (!char.match(/[a-zA-Z.]/)) {
yap_queue.push(yap_sounds.talking['_']);
continue; // skip characters that are not letters or periods
}
yap_queue.push(yap_sounds.talking[char]);
}
function next_yap() {
letterCallback(yap_queue.length)
if (yap_queue.length === 0) return;
let noise = yap_queue.shift();
noise.rate(2 * (Math.random() * .50 + 1.9));
noise.once('end', next_yap)
console.log(noise)
noise.play();
}
@ -253,18 +264,26 @@ async function generateProjectIdea() {
document.querySelector('#generate-project-idea').classList.add('disabled')
document.querySelector('#project-idea').innerHTML = "<em>" + thinkingWords() + "..." + "</em>"
document.querySelector('#generate-project-idea').src = "https://cloud-80eg2m8id-hack-club-bot.vercel.app/0thinking_rac.png"
const res = await fetch('/api/bin/openai/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ parts: selectedParts })
})
const json = await res.json()
document.querySelector('#project-idea').innerHTML = json.recommendation
let text = ""
if (selectedParts.length == 0) {
text = "You need to rummage for some parts first!"
} else {
const res = await fetch('/api/bin/openai/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ parts: selectedParts })
})
const json = await res.json()
text = json.recommendation
}
document.querySelector('#project-idea').innerHTML = ""
document.querySelector('#generate-project-idea').src = "https://cloud-cyo3pqn0f-hack-club-bot.vercel.app/0statement_rac.png"
document.querySelector('#generate-project-idea').classList.remove('disabled')
yap(json.recommendation)
yap(text, i => {
document.querySelector('#project-idea').innerHTML = text.slice(0, Math.max(text.length - i + 1, 0))
})
}
function thinkingWords() {
@ -272,8 +291,6 @@ function thinkingWords() {
"thinking",
"single neuron activated",
"2 braincells rubbing together",
"processing",
"calculating",
"pondering",
"contemplating",
"rackin' my brain",

View file

@ -33,11 +33,12 @@ async function fetchAndLogTextFile(url) {
console.error('Error fetching the file:', error);
}
}
fetchAndLogTextFile('./ascii-art.txt');
window.addEventListener("load", (e) => {
function recalculateSectionHeight() {
document.querySelectorAll(".section").forEach(element => {
element.style.minHeight = element.getBoundingClientRect().height + "px"
})
})
}
fetchAndLogTextFile('./landing-new/ascii-art.txt');
window.addEventListener("load", recalculateSectionHeight())
window.addEventListener("resize", recalculateSectionHeight())

View file

@ -3,8 +3,9 @@
width: 100%;
box-sizing: border-box;
}
.container {
max-width: 52em;
max-width: 62em;
margin: auto;
}
@ -14,6 +15,7 @@
.hoverable {
transition: 500ms transform;
cursor: pointer;
}
.hoverable:hover {
@ -63,10 +65,22 @@
.scroll-prompt {
cursor: pointer;
position: absolute;
display: block;
display: flex;
justify-content: center;
align-items: center;
left: 50%;
bottom: 20px;
transform: translateX(-50%);
background: linear-gradient(#63CE61, #ADEA00);
height: 50px;
width: 50px;
padding: 20px;
border-radius: 50%;
transition: transform 300ms;
}
.scroll-prompt:hover {
transform: translateX(-50%) scale(1.05);
}
.landing-main-image {
@ -75,28 +89,22 @@
width: 65%;
}
#floaty,
#floaty-left {
width: 300px;
position: absolute;
.floaty img {
width: 100%;
}
#floaty,
.floaty {
width: 17vw;
position: absolute;
animation: float 6s ease-in-out infinite;
}
#floaty-left,
.float-left {
animation: float-left 6s ease-in-out infinite;
}
.gambling-section {
padding: 50px;
display: flex;
flex-direction: column;
gap: 30px;
max-width: 75em;
/* display: flex; */
/* flex-direction: column; */
/* gap: 30px; */
/* max-width: 75em; */
margin: auto;
}
@ -131,8 +139,9 @@
.gambling-ui {
display: flex;
flex-direction: row;
justify-content: center;
justify-content: space-between;
align-items: center;
margin-top: 2em;
}
.gambling-spinner {
@ -182,7 +191,7 @@
.spinner-item {
width: 100%;
height: 100%;
aspect-ratio: 1;
/* aspect-ratio: 1; */
padding: 15px;
box-sizing: border-box;
background-color: #D9D9D9;
@ -203,12 +212,12 @@
}
.spinner-item-name {
font-size: 35px;
font-size: 1.5em;
text-align: center;
}
.spinner-item-description {
font-size: 25px;
font-size: 1.2em;
text-align: center;
}
@ -224,7 +233,7 @@
gap: 10px;
}
.gambling-controls button {
/* .gambling-section button {
font-weight: bolder;
box-sizing: border-box;
border: none;
@ -238,36 +247,61 @@
flex-grow: 1;
gap: 30px;
align-items: center;
}
} */
.gambling-controls button img {
height: 30px;
}
button {
border-radius: 0.5em;
font-size: 40px;
font-weight: bolder;
box-sizing: border-box;
color: white;
border: none;
padding: 10px 30px;
margin: 1em;
}
.gambling-roll {
background-color: #ee9f9f;
flex-grow: 1;
flex-basis: 100%;
margin-bottom: -10px;
display: inherit;
margin: 0 auto;
}
.gambling-controls:first-child {
margin-left: 0px;
margin-right: 0px;
}
/*
.gambling-select {
background-color: #7D96EC;
}
} */
.gambling-build {
background-color: #9FEEB5;
filter: saturate(1) brightness(1);
transition: filter 500ms;
display: flex;
gap: 20px;
}
.gambling-build.disabled {
filter: saturate(0.4) brightness(0.6);
filter: saturate(0.5) brightness(0.7);
}
.cta-container {
display: flex;
}
@media screen and (max-width: 900px) {
.cta-container {
flex-direction: column-reverse;
}
}
.gambling-placeholder {
@ -276,6 +310,253 @@
margin: auto;
}
#generate-project-idea {
cursor: pointer;
}
.project-idea-section {
margin-bottom: 30px;
}
#project-name {
resize: none;
width: 70%;
border: none;
padding: 20px;
font-size: 20px;
margin-bottom: 30px;
border-radius: 30px;
}
.project-idea-buttons {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
column-gap: 20px;
row-gap: 5px;
}
.gambling-build {
margin: auto;
}
.project-idea-buttons button {
margin: 0;
}
.project-idea-container {
margin: auto;
padding: 50px;
width: inherit;
box-sizing: border-box;
}
.project-idea-container h1 {
font-size: 50px;
margin-bottom: 10px;
}
.project-idea-images {
display: flex;
flex-direction: row;
width: 100%;
justify-content: space-evenly;
gap: 5px;
display: none;
height: 90px;
}
.project-idea-images img {
height: 100%;
width: auto;
}
#project-idea-build {
font-size: 30px;
font-weight: bolder;
border: none;
background-color: #9FEEB5;
padding: 10px 30px;
border-radius: 30px;
height: min-content;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 10px;
}
#project-idea-build img {
height: 25px;
}
/* CSS from https://codepen.io/quadbaup/details/rKOKQv */
.thought {
display: flex;
background-color: #fff;
padding: 20px;
border-radius: 30px;
min-width: 40px;
max-width: 220px;
min-height: 40px;
margin: 20px;
position: relative;
align-items: center;
justify-content: center;
/* text-align:center; */
}
.thought:before,
.thought:after {
content: "";
background-color: #fff;
border-radius: 50%;
display: block;
position: absolute;
z-index: -1;
}
.thought:before {
width: 44px;
height: 44px;
top: -12px;
left: 28px;
box-shadow: -50px 30px 0 -12px #fff;
}
.thought:after {
bottom: -10px;
right: 26px;
width: 30px;
height: 30px;
box-shadow: 40px -34px 0 0 #fff,
-28px -6px 0 -2px #fff,
-24px 17px 0 -6px #fff,
-5px 25px 0 -10px #fff;
}
.disabled {
cursor: not-allowed;
}
.loading {
cursor: wait;
}
#generate-project-idea {
cursor: pointer;
}
#project-name {
resize: none;
width: 70%;
border: none;
padding: 20px;
font-size: 20px;
margin-bottom: 30px;
border-radius: 30px;
}
.faq-section {
padding: 50px;
}
.faq-section h1 {
font-size: 50px;
}
.faq-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin-top: 2em;
margin-bottom: 2em;
}
.faq-item {
padding: 20px;
border-radius: 20px;
background-color: #EEEDED;
backdrop-filter: blur(10px);
filter: saturate(0.9);
}
.faq-item a {
color: black;
}
.faq-item p {
margin-top: 1em;
}
.faq-item h1 {
font-size: 1.5em;
}
.timeline-header {
font-size: 70px;
width: fit-content;
margin: auto;
}
.timeline-subheader {
font-weight: normal;
font-style: italic;
margin: auto;
width: fit-content;
font-size: 50px;
}
.timeline-list {
margin: auto;
grid-template-columns: 1fr 1fr 1fr;
height: min-content;
display: grid;
gap: 20px;
width: 100%;
box-sizing: border-box;
padding: 50px;
max-width: 62em;
}
.timeline-item {
padding: 10px;
background-color: black;
border-radius: 20px;
box-sizing: border-box;
height: 100%;
}
.timeline-info {
background-color: #EEEDED;
height: 100%;
border-radius: 12px;
padding: 20px;
box-sizing: border-box;
}
.timeline-info a {
color: black;
}
.muted {
opacity: 0.5;
}
.greenbutton {
background: linear-gradient(to bottom right, #63CE61, #ADEA00);
}
.bluebutton {
background: linear-gradient(to bottom right, #7A97FC, #7AEDFC);
}
.redbutton {
background: linear-gradient(to bottom right, #FC7A7A, #FCA97A);
}
@keyframes float {
from,
@ -296,33 +577,12 @@
}
}
@keyframes float-left {
from,
to {
transform: translate(0%, -47%) rotate(-2deg);
}
25% {
transform: translate(-2%, -50%) rotate(2deg);
}
50% {
transform: translate(-0%, -53%) rotate(-1deg);
}
75% {
transform: translate(-1%, -50%) rotate(-1deg);
}
}
@media screen and (aspect-ratio: 4/3) {
.landing-header {
width: 50%;
}
#floaty,
#floaty-left {
.floaty {
width: 200px;
}
@ -347,10 +607,11 @@
}
}
@media only screen and (hover: none) and (pointer: coarse) {
@media only screen and (max-width: 900px) {
body {
overflow-x: hidden;
}
#floaty,
#floaty-left,
.floaty {
display: none;
}
@ -419,6 +680,7 @@
flex-direction: row;
border-radius: 20px;
gap: 10px;
overflow: hidden;
}
.spinner-item-name,
@ -442,131 +704,106 @@
height: auto;
width: 100px;
}
}
/* CSS from https://codepen.io/quadbaup/details/rKOKQv */
.thought {
display: flex;
background-color: #fff;
padding: 20px;
border-radius: 30px;
min-width: 40px;
max-width: 220px;
min-height: 40px;
margin: 20px;
position: relative;
align-items: center;
justify-content: center;
/* text-align:center; */
}
.thought:before,
.thought:after {
content: "";
background-color: #fff;
border-radius: 50%;
display: block;
position: absolute;
z-index: -1;
}
.thought:before {
width: 44px;
height: 44px;
top: -12px;
left: 28px;
box-shadow: -50px 30px 0 -12px #fff;
}
.thought:after {
bottom: -10px;
right: 26px;
width: 30px;
height: 30px;
box-shadow: 40px -34px 0 0 #fff,
-28px -6px 0 -2px #fff,
-24px 17px 0 -6px #fff,
-5px 25px 0 -10px #fff;
}
.disabled {
cursor: not-allowed !important;
}
.loading {
cursor: wait !important;
}
#generate-project-idea {
cursor: pointer;
}
#project-name {
resize: none;
width: 70%;
border: none;
padding: 20px;
font-size: 20px;
margin-bottom: 30px;
border-radius: 30px;
}
.project-idea-container {
margin: auto;
padding: 0 20px;
max-width: 52em;
}
.project-idea-container h1 {
font-size: 40px;
margin-bottom: 10px;
}
.faq-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin-top: 2em;
margin-bottom: 2em;
}
.faq-item {
padding: 20px;
border: 1px solid rgba(255,255,255,0.4);
border-radius: 20px;
background-color: rgba(255,255,255,0.2);
backdrop-filter: blur(10px);
}
.faq-item p {
margin-top: 1em;
}
.timeline-list {
margin: 2em auto;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 300px 300px;
display: grid;
gap: 10px;
}
@media only screen and (max-width: 768px) {
.timeline-list {
/* display: grid; */
grid-template-columns: 1fr;
/* padding: 1em; */
/* grid-row-gap: 100px; */
.project-idea-section {
padding-top: 20px;
}
}
.timeline-item {
padding: 20px;
border: 1px solid rgba(255,255,255,0.4);
border-radius: 20px;
background-color: rgba(255,255,255,0.2);
backdrop-filter: blur(10px);
.project-idea-container {
height: 100%;
display: flex;
flex-direction: column;
gap: 10px;
padding: 30px;
padding-top: 20px;
padding-bottom: 10px;
box-sizing: border-box;
align-items: center;
}
.project-idea-buttons {
gap: 10px;
}
.project-idea-buttons button {
width: 100%;
}
.project-idea-title {
font-size: 48px;
}
#project-name {
margin: auto;
width: 90%;
display: block;
border-radius: 20px;
flex-grow: 1;
}
.project-idea-images {
display: flex;
}
.timeline {
padding: 30px;
}
.timeline-list {
padding: 0px;
}
.timeline-header {
font-size: 40px;
margin: 0;
}
.timeline-subheader {
font-size: 30px;
margin: 0;
margin-bottom: 20px;
}
.faq-section {
padding: 30px;
}
.hideonmobile {
display: none;
}
}
.muted {
opacity: 0.5;
/*who is even using this*/
@media only screen and (max-width: 300px) {
.spinner-item-image {
display: none;
}
}
@media only screen and (max-width: 52em) {
.timeline-list {
grid-template-columns: 1fr;
}
}
.talking {
animation: talking 1s infinite;
}
@keyframes talking {
0% {
transform: translateY(0px);
}
50% {
transform: translateY(-10px);
}
100% {
transform: translateY(0px);
}
}
.project-idea-title {
text-align: center;
}

35
public/bin/memes.js Normal file
View file

@ -0,0 +1,35 @@
const raccoonMemes = [
"https://cloud-mymt66p99-hack-club-bot.vercel.app/0screenshot_2024-05-16_at_00.18.39.png",
"https://cloud-mymt66p99-hack-club-bot.vercel.app/1screenshot_2024-05-16_at_00.18.23.png",
"https://cloud-mymt66p99-hack-club-bot.vercel.app/2screenshot_2024-05-16_at_00.18.10.png",
"https://cloud-mymt66p99-hack-club-bot.vercel.app/3screenshot_2024-05-16_at_00.18.01.png",
"https://cloud-mymt66p99-hack-club-bot.vercel.app/4screenshot_2024-05-16_at_00.17.47.png",
"https://cloud-mymt66p99-hack-club-bot.vercel.app/5screenshot_2024-05-16_at_00.17.34.png",
// "https://cloud-mymt66p99-hack-club-bot.vercel.app/6screenshot_2024-05-16_at_00.17.03.png",
"https://cloud-mymt66p99-hack-club-bot.vercel.app/7screenshot_2024-05-16_at_00.16.55.png",
"https://cloud-mymt66p99-hack-club-bot.vercel.app/8screenshot_2024-05-16_at_00.16.47.png",
"https://cloud-mymt66p99-hack-club-bot.vercel.app/9screenshot_2024-05-16_at_00.16.41.png",
"https://cloud-15w2altd8-hack-club-bot.vercel.app/063583bc6dfeca75c4fa5b4a9f777de8ac736131f.jpg",
"https://cloud-15w2altd8-hack-club-bot.vercel.app/423cfcde338b5918beda111113e119aebcbf47c90.jpg",
"https://cloud-15w2altd8-hack-club-bot.vercel.app/7my-favorite-raccoon-memes-on-insta-v0-rnfh1ut4kpca1.jpg",
"https://cloud-15w2altd8-hack-club-bot.vercel.app/6eed531fa624a62ad59ff6a3fdce9a3a7_945977333666952908.webp",
"https://cloud-15w2altd8-hack-club-bot.vercel.app/57e6914854ab1b45f5c1c0ed49ae2165a.jpg",
"https://cloud-b8au5gtkn-hack-club-bot.vercel.app/0raccoon-nocturnaltrashposts-live-like-every-day-is-trash-day.jpg",
"https://cloud-b8au5gtkn-hack-club-bot.vercel.app/1raccoon-memes4.jpg",
"https://cloud-b8au5gtkn-hack-club-bot.vercel.app/2raccoon-memes-instagram-624ae8c78c21d__700.jpg",
"https://cloud-b8au5gtkn-hack-club-bot.vercel.app/371uzrob1zfl._ac_uf1000_1000_ql80_.jpg",
"https://cloud-b8au5gtkn-hack-club-bot.vercel.app/42629715d15647a5c70d2cbb9ec43b489.jpg",
]
const getMeme = () => {
return sample(raccoonMemes)
}
window.addEventListener("load", async (e) => {
const el = document.querySelector("#meme")
el.src = getMeme()
el.onclick = () => {
el.href = getMeme()
}
})

View file

@ -12,6 +12,30 @@
<link rel="icon" type="image/png" sizes="16x16" href="https://assets.hackclub.com/favicons/favicon-16x16.png">
<script src="https://awdev.codes/utils/smoothScroll.js"></script>
<script src="https://awdev.codes/utils/hackclub/orph.js"></script>
<script src="../data-loading.js"></script>
<script defer data-domain="hackclub.com" src="https://plausible.io/js/script.js"></script>
<script>
window['_fs_host'] = 'fullstory.com';
window['_fs_script'] = 'edge.fullstory.com/s/fs.js';
window['_fs_org'] = 'ARN0J';
window['_fs_namespace'] = 'FS';
!function(m,n,e,t,l,o,g,y){var s,f,a=function(h){
return!(h in m)||(m.console&&m.console.log&&m.console.log('FullStory namespace conflict. Please set window["_fs_namespace"].'),!1)}(e)
;function p(b){var h,d=[];function j(){h&&(d.forEach((function(b){var d;try{d=b[h[0]]&&b[h[0]](h[1])}catch(h){return void(b[3]&&b[3](h))}
d&&d.then?d.then(b[2],b[3]):b[2]&&b[2](d)})),d.length=0)}function r(b){return function(d){h||(h=[b,d],j())}}return b(r(0),r(1)),{
then:function(b,h){return p((function(r,i){d.push([b,h,r,i]),j()}))}}}a&&(g=m[e]=function(){var b=function(b,d,j,r){function i(i,c){
h(b,d,j,i,c,r)}r=r||2;var c,u=/Async$/;return u.test(b)?(b=b.replace(u,""),"function"==typeof Promise?new Promise(i):p(i)):h(b,d,j,c,c,r)}
;function h(h,d,j,r,i,c){return b._api?b._api(h,d,j,r,i,c):(b.q&&b.q.push([h,d,j,r,i,c]),null)}return b.q=[],b}(),y=function(b){function h(h){
"function"==typeof h[4]&&h[4](new Error(b))}var d=g.q;if(d){for(var j=0;j<d.length;j++)h(d[j]);d.length=0,d.push=h}},function(){
(o=n.createElement(t)).async=!0,o.crossOrigin="anonymous",o.src="https://"+l,o.onerror=function(){y("Error loading "+l)}
;var b=n.getElementsByTagName(t)[0];b&&b.parentNode?b.parentNode.insertBefore(o,b):n.head.appendChild(o)}(),function(){function b(){}
function h(b,h,d){g(b,h,d,1)}function d(b,d,j){h("setProperties",{type:b,properties:d},j)}function j(b,h){d("user",b,h)}function r(b,h,d){j({
uid:b},d),h&&j(h,d)}g.identify=r,g.setUserVars=j,g.identifyAccount=b,g.clearUserCookie=b,g.setVars=d,g.event=function(b,d,j){h("trackEvent",{
name:b,properties:d},j)},g.anonymize=function(){r(!1)},g.shutdown=function(){h("shutdown")},g.restart=function(){h("restart")},
g.log=function(b,d){h("log",{level:b,msg:d})},g.consent=function(b){h("setIdentity",{consent:!arguments.length||b})}}(),s="fetch",
f="XMLHttpRequest",g._w={},g._w[f]=m[f],g._w[s]=m[s],m[s]&&(m[s]=function(){return g._w[s].apply(this,arguments)}),g._v="2.0.0")
}(window,document,window._fs_namespace,"script",window._fs_script);
</script>
</head>
<body>

View file

@ -1,3 +1,4 @@
const partsLimit = 8
var fetchedParts;
async function fetchParts() {
const response = await fetch('https://hackclub.com/api/bin/wokwi/parts/');
@ -32,9 +33,8 @@ function recalculateSelected() {
let numSelectedItems = getSelectedItems().length
let selections = []
items = document.querySelectorAll(".selector-item")
items = document.querySelectorAll(".selector-item")
document.querySelector(".selector-number").innerText = `${3 - numSelectedItems} choices remaining.`
if (3 - numSelectedItems == 0) {
document.querySelector(".selector-number").innerText = `${partsLimit - numSelectedItems} choices remaining.`
if (partsLimit - numSelectedItems == 0) {
items.forEach(item => {
let isSelected = item.className.includes("selected")
if (!isSelected) {
@ -54,8 +54,7 @@ function recalculateSelected() {
getSelectedItems().forEach(item => {
selections.push(item.getAttribute("part_name"))
})
console.log(selections)
return numSelectedItems
return selections
}
function addPartToPage(part) {
@ -92,7 +91,7 @@ function addPartToPage(part) {
if (isSelected) {
selectorItem.classList.remove("selected")
} else {
if (getSelectedItems().length < 3) {
if (getSelectedItems().length < partsLimit) {
selectorItem.classList.add("selected")
}
}
@ -100,17 +99,22 @@ function addPartToPage(part) {
})
}
window.addEventListener("load", (e) => {
window.addEventListener("load", async (e) => {
recalculateSelected();
fetchParts().then(parts => {
fetchedParts = parts;
fetchedParts.forEach(part => {
if (!(part.imageUrl == undefined)) {
console.log(part.wokwiName)
//saveImageToCache(part);
addPartToPage(part)
}
const fetchedParts = await partsData()
fetchedParts.forEach(part => {
if (!(part.imageUrl == undefined)) {
addPartToPage(part)
}
})
document.querySelector(".selector-continue").onclick = () => {
let selectedItems = getSelectedItems()
let selectedItemsArray = []
selectedItems.forEach(item => {
selectedItemsArray.push(item.getAttribute("part_name"))
})
//saveImageToCache({ wokwiName: "wokwi-pedro", imageUrl: "https://awdev.codes/images/ww.gif" })
});
const partsList = encodeURI(recalculateSelected().sort().join("|"))
window.location.href = `/api/bin/wokwi/new/${partsList}`
}
})

View file

@ -21,7 +21,7 @@ footer {
}
.footer-information a {
color: #338eda;
color: inherit;
}
.footer-information-header {