diff --git a/lib/carousel.json b/lib/carousel.json index b2c1ea05..2456564f 100644 --- a/lib/carousel.json +++ b/lib/carousel.json @@ -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", diff --git a/next.config.mjs b/next.config.mjs index ce03e9a6..b45a5bf1 100755 --- a/next.config.mjs +++ b/next.config.mjs @@ -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' } ] }, diff --git a/pages/api/bin/openai.js b/pages/api/bin/openai.js index 0e419dd4..205112ae 100644 --- a/pages/api/bin/openai.js +++ b/pages/api/bin/openai.js @@ -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)] @@ -47,6 +61,7 @@ export default async function handler(req, res) { }) const recommendation = await generateProjectIdea(parts) + await saveProject(parts, recommendation) res.send({ recommendation, parts }) } diff --git a/pages/api/bin/wokwi/new.js b/pages/api/bin/wokwi/new.js index 9f81391e..b891e182 100644 --- a/pages/api/bin/wokwi/new.js +++ b/pages/api/bin/wokwi/new.js @@ -1,6 +1,36 @@ import AirtablePlus from "airtable-plus" -const createProject = async (partsList=[]) => { +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; } @@ -49,20 +79,23 @@ Now that you've thrown some parts into The Bin, it's time to turn that trash int Wire up your parts and write some code to make them work together. -If you'd like a tutorial, check out this short explainer on making a blinking LED: +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 -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 { diff --git a/pages/bin.js b/pages/bin/prelaunch.js similarity index 98% rename from pages/bin.js rename to pages/bin/prelaunch.js index 490c88e0..8347f0f5 100644 --- a/pages/bin.js +++ b/pages/bin/prelaunch.js @@ -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 = () => { diff --git a/pages/index.js b/pages/index.js index 78ca0c06..6b1707c0 100644 --- a/pages/index.js +++ b/pages/index.js @@ -204,9 +204,9 @@ function Page({ gradient="linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.45))" /> + + diff --git a/public/bin/icons/scrolldown.svg b/public/bin/icons/scrolldown.svg index c2e102a6..64ab9adb 100644 --- a/public/bin/icons/scrolldown.svg +++ b/public/bin/icons/scrolldown.svg @@ -1,4 +1,4 @@ - - - + + + diff --git a/public/bin/landing-new/index.html b/public/bin/index.html similarity index 72% rename from public/bin/landing-new/index.html rename to public/bin/index.html index 47964491..a5a89c7f 100644 --- a/public/bin/landing-new/index.html +++ b/public/bin/index.html @@ -5,9 +5,9 @@ The Bin - - - + + + @@ -15,46 +15,89 @@ - + + +
- + The beginner hardware kit designed just for you Free for high schoolers - +
- - - + + - - - +
+ +
+ +
-
+
-

What will you make
before summer break?

+

+ What will you make +

+

+ before summer break? +

-
- Right now... -

Rummage for parts

-

Dig up some parts from our part picker or choose your own! Don't have an idea yet? Ask the raccoon for some inspiration!

+
+
+ Right now... +

Rummage for parts

+

Dig up some parts from our part picker or choose your own! Don't have an idea yet? Ask the + raccoon + for some inspiration!

+
-
- over 3-4 days... -

Design your project

-

Build a project in the online editor and program it! Get support from other high schoolers in an online community.

+
+
+ over 3-4 days... +

Design your project

+

Build a project in the online editor and program it! Get support from other high schoolers in an online + community.

+
-
- in 1 week... -

Get it IRL

-

Submit your design to the gallery of projects so other high schoolers can learn from your project.

+
+
+ in 1 week... +

Get it IRL

+

Submit your design to the gallery of + projects so other high schoolers can learn from your project.

+
@@ -62,93 +105,141 @@

Rummage!

-

Let's get you your parts!

+

Let's get those parts!

- +
+
- +
+
- +
+
- +
- -
-
+
-

What are we building today?

- -

💡 Need an idea? Click the raccoon!

+

+ What are you waiting for? +

+ + + + + + + +
-
-

Readme

+
+

Any questions?

-

How many projects can I build?

-

You can submit as many projects as you want! For second submissions, we’ll ship the parts you don’t have– for example, your first project will get a pico included and subsequent projects won’t ship with it.

+

How many projects can I build?

+

You can submit as many projects as you want! For second submissions, we’ll ship the parts you don’t + have– for example, your first project will get a pico included and subsequent projects won’t ship + with it.

-

How much does it cost?

-

100% free– we’ll also give a breadboard and the jumper wires you need to build your project too! The whole program is funded by donations to a non-profit.

+

How much does it cost?

+

100% free– we’ll also give a breadboard and the jumper wires you need to build your project too! The + whole program is funded by donations to a + non-profit.

-

Who is eligible?

-

You need to be a high schooler (or younger) in the United States. Submissions need to be in by June 1st to qualify.

+

Who is eligible?

+

You need to be a high schooler (or younger) in the United States. Submissions need to be in by June + 1st to qualify.

-

What do I need?

-

Just a browser simulate & computer to upload your code to the pico– we’ll give you all the equipment you need for your circuit.

+

What do I need?

+

Just a browser simulator & computer to upload your code to the pico– we’ll give you all the equipment + you need for your circuit.

-

I need help!

-

Get it in the #electronics channel of the Hack Club Slack.

+

I need help!

+

Get it in the #electronics channel of the Hack Club Slack.

-

What designs are allowed?

-

Check out the list of eligible parts! Each design can have up to 8 modules, and need at least 1 module.

+

What designs are allowed?

+

Check out the list of eligible parts! Each design can have up to 8 modules, and need + at least 1 module.

- + \ No newline at end of file diff --git a/public/bin/landing-new/gambling.js b/public/bin/landing-new/gambling.js index d2781a8c..b465077f 100644 --- a/public/bin/landing-new/gambling.js +++ b/public/bin/landing-new/gambling.js @@ -119,6 +119,10 @@ function addComponentsToPage(data) { }) } +function sample(arr) { + return arr[Math.floor(Math.random() * arr.length)] +} + function rollParts(el) { if (el.classList.contains("disabled")) { return @@ -128,27 +132,25 @@ function rollParts(el) { element.removeChild(element.firstElementChild) }) addComponentsToPage(fetchedParts) + rolled = true } - rolled = true document.querySelector(".gambling-build").classList.remove("disabled") 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] diff --git a/public/bin/landing-new/script.js b/public/bin/landing-new/script.js index e8e250b2..5001b825 100644 --- a/public/bin/landing-new/script.js +++ b/public/bin/landing-new/script.js @@ -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" }) -}) \ No newline at end of file +} +fetchAndLogTextFile('./landing-new/ascii-art.txt'); + +window.addEventListener("load", recalculateSectionHeight()) +window.addEventListener("resize", recalculateSectionHeight()) \ No newline at end of file diff --git a/public/bin/landing-new/style.css b/public/bin/landing-new/style.css index 7491a942..5922e089 100644 --- a/public/bin/landing-new/style.css +++ b/public/bin/landing-new/style.css @@ -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 { @@ -77,7 +91,7 @@ #floaty, #floaty-left { - width: 300px; + width: 17vw; position: absolute; } @@ -93,10 +107,10 @@ .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 +145,9 @@ .gambling-ui { display: flex; flex-direction: row; - justify-content: center; + justify-content: space-between; align-items: center; + margin-top: 2em; } .gambling-spinner { @@ -203,12 +218,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 +239,7 @@ gap: 10px; } -.gambling-controls button { +/* .gambling-section button { font-weight: bolder; box-sizing: border-box; border: none; @@ -238,17 +253,30 @@ 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 { @@ -264,10 +292,12 @@ 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); } .gambling-placeholder { @@ -276,6 +306,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, @@ -347,7 +624,10 @@ } } -@media only screen and (hover: none) and (pointer: coarse) { +@media only screen and (max-width: 900px) { + body { + overflow-x: hidden; + } #floaty, #floaty-left, @@ -419,6 +699,7 @@ flex-direction: row; border-radius: 20px; gap: 10px; + overflow: hidden; } .spinner-item-name, @@ -442,131 +723,102 @@ 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); + } } \ No newline at end of file diff --git a/public/bin/selector/index.html b/public/bin/selector/index.html index 62fd5535..3e3c388b 100644 --- a/public/bin/selector/index.html +++ b/public/bin/selector/index.html @@ -12,6 +12,30 @@ + + + diff --git a/public/bin/selector/script.js b/public/bin/selector/script.js index 81a05818..d9dd729f 100644 --- a/public/bin/selector/script.js +++ b/public/bin/selector/script.js @@ -1,3 +1,4 @@ +const partsLimit = 8 var fetchedParts; async function fetchParts() { const response = await fetch('https://hackclub.com/api/bin/wokwi/parts/'); @@ -33,8 +34,8 @@ function recalculateSelected() { 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) { @@ -92,7 +93,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 +101,13 @@ 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) - } - }) - //saveImageToCache({ wokwiName: "wokwi-pedro", imageUrl: "https://awdev.codes/images/ww.gif" }) - }); + const fetchedParts = await partsData() + fetchedParts.forEach(part => { + if (!(part.imageUrl == undefined)) { + console.log(part.wokwiName) + addPartToPage(part) + } + }) }) \ No newline at end of file