Merge branch 'hackclub:main' into main
|
|
@ -1,4 +1,5 @@
|
|||
AIRTABLE_API_KEY=your_airtable_api_key_here
|
||||
AIRTABLE_BASE_ID=your_airtable_base_id_here
|
||||
AIRTABLE_EMAILS_TABLE=your_airtable_emails_table_here
|
||||
GEOCODER_API_KEY=your_geocoder_api_key_here
|
||||
AIRTABLE_RSVPS_TABLE=your_airtable_rsvps_table_here
|
||||
GEOCODER_API_KEY=your_geocoder_api_key_here
|
||||
41
bun.lock
|
|
@ -5,6 +5,7 @@
|
|||
"name": "site",
|
||||
"dependencies": {
|
||||
"@fontsource/atkinson-hyperlegible": "^5.2.6",
|
||||
"@fontsource/jersey-15": "^5.2.6",
|
||||
"@sveltejs/adapter-node": "^5.2.13",
|
||||
"@sveltejs/adapter-static": "^3.0.8",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
|
|
@ -93,6 +94,8 @@
|
|||
|
||||
"@fontsource/atkinson-hyperlegible": ["@fontsource/atkinson-hyperlegible@5.2.6", "", {}, "sha512-Kfh6/UlHhotKuv4Oi9PXQIsmzwbtJIR442sSJnEHsO7TDZaDczK8cY0AlTNOB0XMDZj1j35nAlgbi2HZCdNg/Q=="],
|
||||
|
||||
"@fontsource/jersey-15": ["@fontsource/jersey-15@5.2.6", "", {}, "sha512-3zkkEnu91esusWLqAK/AN1uc6jNtWT8idfO0UfYLqNlbMBKkbbiIVXtq6UbQsyegxnmRMppVV1J2t1zrJ36VgA=="],
|
||||
|
||||
"@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.12", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg=="],
|
||||
|
|
@ -231,10 +234,6 @@
|
|||
|
||||
"@types/triple-beam": ["@types/triple-beam@1.3.5", "", {}, "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="],
|
||||
|
||||
"@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
||||
|
||||
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
|
||||
|
||||
"abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="],
|
||||
|
||||
"abortcontroller-polyfill": ["abortcontroller-polyfill@1.7.8", "", {}, "sha512-9f1iZ2uWh92VcrU9Y8x+LdM4DLj75VE0MJB8zuF1iUnroEptStw+DQ8EQPMUdfe5k+PkB1uUfDQfWbhstH8LrQ=="],
|
||||
|
|
@ -385,20 +384,6 @@
|
|||
|
||||
"magic-string": ["magic-string@0.30.17", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA=="],
|
||||
|
||||
"mdast-util-to-hast": ["mdast-util-to-hast@13.2.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA=="],
|
||||
|
||||
"mdsvex": ["mdsvex@0.12.6", "", { "dependencies": { "@types/mdast": "^4.0.4", "@types/unist": "^2.0.3", "prism-svelte": "^0.4.7", "prismjs": "^1.17.1", "unist-util-visit": "^2.0.1", "vfile-message": "^2.0.4" }, "peerDependencies": { "svelte": "^3.56.0 || ^4.0.0 || ^5.0.0-next.120" } }, "sha512-pupx2gzWh3hDtm/iDW4WuCpljmyHbHi34r7ktOqpPGvyiM4MyfNgdJ3qMizXdgCErmvYC9Nn/qyjePy+4ss9Wg=="],
|
||||
|
||||
"micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="],
|
||||
|
||||
"micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="],
|
||||
|
||||
"micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ=="],
|
||||
|
||||
"micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="],
|
||||
|
||||
"micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="],
|
||||
|
||||
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
||||
|
||||
"minizlib": ["minizlib@3.0.2", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA=="],
|
||||
|
|
@ -435,12 +420,6 @@
|
|||
|
||||
"prettier-plugin-svelte": ["prettier-plugin-svelte@3.4.0", "", { "peerDependencies": { "prettier": "^3.0.0", "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" } }, "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ=="],
|
||||
|
||||
"prism-svelte": ["prism-svelte@0.4.7", "", {}, "sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ=="],
|
||||
|
||||
"prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="],
|
||||
|
||||
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
|
||||
|
||||
"readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
|
||||
|
||||
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||
|
|
@ -505,22 +484,8 @@
|
|||
|
||||
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
||||
|
||||
"unist-util-is": ["unist-util-is@4.1.0", "", {}, "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg=="],
|
||||
|
||||
"unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="],
|
||||
|
||||
"unist-util-stringify-position": ["unist-util-stringify-position@2.0.3", "", { "dependencies": { "@types/unist": "^2.0.2" } }, "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g=="],
|
||||
|
||||
"unist-util-visit": ["unist-util-visit@2.0.3", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0", "unist-util-visit-parents": "^3.0.0" } }, "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q=="],
|
||||
|
||||
"unist-util-visit-parents": ["unist-util-visit-parents@3.1.1", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0" } }, "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg=="],
|
||||
|
||||
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||
|
||||
"vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
|
||||
|
||||
"vfile-message": ["vfile-message@2.0.4", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-stringify-position": "^2.0.0" } }, "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ=="],
|
||||
|
||||
"vite": ["vite@7.0.4", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.6", "picomatch": "^4.0.2", "postcss": "^8.5.6", "rollup": "^4.40.0", "tinyglobby": "^0.2.14" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-SkaSguuS7nnmV7mfJ8l81JGBFV7Gvzp8IzgE8A8t23+AxuNX61Q5H1Tpz5efduSN7NHC8nQXD3sKQKZAu5mNEA=="],
|
||||
|
||||
"vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="],
|
||||
|
|
|
|||
10
package-lock.json
generated
|
|
@ -9,6 +9,7 @@
|
|||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@fontsource/atkinson-hyperlegible": "^5.2.6",
|
||||
"@fontsource/jersey-15": "^5.2.6",
|
||||
"@sveltejs/adapter-node": "^5.2.13",
|
||||
"@sveltejs/adapter-static": "^3.0.8",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
|
|
@ -493,6 +494,15 @@
|
|||
"url": "https://github.com/sponsors/ayuhito"
|
||||
}
|
||||
},
|
||||
"node_modules/@fontsource/jersey-15": {
|
||||
"version": "5.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource/jersey-15/-/jersey-15-5.2.6.tgz",
|
||||
"integrity": "sha512-3zkkEnu91esusWLqAK/AN1uc6jNtWT8idfO0UfYLqNlbMBKkbbiIVXtq6UbQsyegxnmRMppVV1J2t1zrJ36VgA==",
|
||||
"license": "OFL-1.1",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ayuhito"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/fs-minipass": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@fontsource/atkinson-hyperlegible": "^5.2.6",
|
||||
"@fontsource/jersey-15": "^5.2.6",
|
||||
"@sveltejs/adapter-node": "^5.2.13",
|
||||
"@sveltejs/adapter-static": "^3.0.8",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
@import 'tailwindcss';
|
||||
@plugin '@tailwindcss/typography';
|
||||
@import '@fontsource/atkinson-hyperlegible';
|
||||
@import '@fontsource/jersey-15';
|
||||
|
||||
@font-face {
|
||||
font-family: 'Expensify New Kansas';
|
||||
font-family: 'Daydream New';
|
||||
font-display: swap;
|
||||
src: url('/fonts/serif.woff') format('woff');
|
||||
font-weight: 400;
|
||||
|
|
@ -11,7 +12,7 @@
|
|||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Expensify New Kansas';
|
||||
font-family: 'Daydream New';
|
||||
font-display: swap;
|
||||
src: url('/fonts/serif-italic.woff') format('woff');
|
||||
font-weight: 400;
|
||||
|
|
@ -20,7 +21,8 @@
|
|||
|
||||
@theme {
|
||||
--font-sans: 'Atkinson Hyperlegible', ui-sans-serif, sans-serif;
|
||||
--font-serif: 'Expensify New Kansas', ui-serif, serif;
|
||||
--font-serif: 'Daydream New', ui-serif, serif;
|
||||
--font-pixel: 'Jersey 15', monospace;
|
||||
--color-gradient-daydream: linear-gradient(to bottom, #487DAB, #3F709A);
|
||||
--color-daydream: #44DBC8;
|
||||
--color-daydream-hover: #3CC2AF;
|
||||
|
|
|
|||
50
src/lib/components/Footer.svelte
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<div class="w-full bg-[#FFFFF8] relative min-h-80">
|
||||
<div
|
||||
class="absolute top-0 left-0 w-full h-full bg-[url('/noise.png')] bg-repeat opacity-10 pointer-events-none z-0"
|
||||
></div>
|
||||
<div
|
||||
class="opacity-60 absolute w-full h-32 bg-[url('brushstroking.png')] bg-repeat-x z-10 bg-size-[100vw_100vh] mix-blend-overlay"
|
||||
style="mask-image: url(/footer-clouds.png); mask-size: contain; mask-repeat: repeat-x; -webkit-mask-image: url(/footer-clouds.png); -webkit-mask-size: contain; -webkit-mask-repeat: repeat-x;"
|
||||
></div>
|
||||
<div
|
||||
class="w-full h-32 bg-[#e99cce] z-5"
|
||||
style="mask-image: url(/footer-clouds.png); mask-size: contain; mask-repeat: repeat-x; -webkit-mask-image: url(/footer-clouds.png); -webkit-mask-size: contain; -webkit-mask-repeat: repeat-x;"
|
||||
></div>
|
||||
|
||||
<!-- Footer Text -->
|
||||
<div
|
||||
class="absolute bottom-20 left-32 text-center z-20 max-md:bottom-12 max-md:left-8 max-md:right-4 max-md:text-left"
|
||||
>
|
||||
<p class="text-gray-700 mb-2">Made with ♡ by teenagers, for teenagers at Hack Club</p>
|
||||
<div class="flex space-x-4 max-md:flex-col max-md:space-x-0 max-md:space-y-2">
|
||||
<a
|
||||
href="https://hackclub.com"
|
||||
class="underline text-gray-700 hover:text-gray-900 transition-colors">Hack Club</a
|
||||
>
|
||||
<span class="text-gray-700 max-md:hidden">・</span>
|
||||
<a
|
||||
href="https://hackclub.com/slack"
|
||||
class="underline text-gray-700 hover:text-gray-900 transition-colors">Slack</a
|
||||
>
|
||||
<span class="text-gray-700 max-md:hidden">・</span>
|
||||
<a
|
||||
href="https://hackclub.com/clubs"
|
||||
class="underline text-gray-700 hover:text-gray-900 transition-colors">Clubs</a
|
||||
>
|
||||
<span class="text-gray-700 max-md:hidden">・</span>
|
||||
<a
|
||||
href="https://hackclub.com/hackathons"
|
||||
class="underline text-gray-700 hover:text-gray-900 transition-colors">Hackathons</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="max-sm:hidden absolute bottom-2 right-16 h-2/3 aspect-square bg-[url('brushstroking.png')] bg-repeat z-10 bg-size-[100vw_100vh] mix-blend-overlay"
|
||||
style="mask-image: url(/thought-bubbles.png); mask-size: contain; mask-repeat: no-repeat; -webkit-mask-image: url(/thought-bubbles.png); -webkit-mask-size: contain; -webkit-mask-repeat: no-repeat;"
|
||||
></div>
|
||||
<div
|
||||
class="max-sm:hidden absolute bottom-2 right-16 h-2/3 aspect-square bg-[#e99cce]"
|
||||
style="mask-image: url(/thought-bubbles.png); mask-size: contain; mask-repeat: no-repeat; -webkit-mask-image: url(/thought-bubbles.png); -webkit-mask-size: contain; -webkit-mask-repeat: no-repeat;"
|
||||
></div>
|
||||
</div>
|
||||
107
src/lib/components/ParticipantSignUp.svelte
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
<script lang="ts">
|
||||
let submitted = false;
|
||||
let fadeOut = false;
|
||||
|
||||
function handleFormSubmit(event: Event) {
|
||||
event.preventDefault();
|
||||
const form = event.target as HTMLFormElement;
|
||||
const emailInput = form.querySelector('input[name="email"]') as HTMLInputElement;
|
||||
const email = emailInput.value;
|
||||
|
||||
fetch('/api/rsvp', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ email })
|
||||
}).catch(error => {
|
||||
console.warn('Failed to save email:', error);
|
||||
});
|
||||
|
||||
submitted = true;
|
||||
|
||||
// Clear the input box while the green overlay is showing
|
||||
emailInput.value = '';
|
||||
|
||||
setTimeout(() => {
|
||||
fadeOut = true;
|
||||
}, 1500);
|
||||
|
||||
// Reset to original position after fade out completes
|
||||
setTimeout(() => {
|
||||
submitted = false;
|
||||
fadeOut = false;
|
||||
}, 1500 + 500);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@keyframes slide-in {
|
||||
from {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.animate-slide-in {
|
||||
animation: slide-in 0.3s cubic-bezier(0, 0.55, 0.45, 1);
|
||||
}
|
||||
|
||||
.animate-fade-out {
|
||||
animation: fade-out 0.5s ease-out forwards;
|
||||
}
|
||||
|
||||
@keyframes fade-out {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="mt-8 flex flex-col items-center gap-3 z-5 max-md:scale-90">
|
||||
<div class="relative rounded-full overflow-hidden" style="padding: 2px 2px 5px 2px;">
|
||||
<form on:submit={handleFormSubmit} class="rounded-full bg-white border-2 border-dark font-sans p-2 flex flex-row items-center gap-2 shadow-[0_3px_0_0_theme(colors.dark)] focus-within:border-pink focus-within:shadow-[0_3px_0_0_#E472AB] has-[button:active]:border-dark has-[button:active]:shadow-[0_3px_0_0_theme(colors.dark)] has-[button:focus]:border-dark has-[button:focus]:shadow-[0_3px_0_0_theme(colors.dark)]">
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="Enter email to RSVP"
|
||||
class="w-80 px-3 py-1 text-dark focus:outline-none flex-1"
|
||||
required
|
||||
/>
|
||||
<input type="hidden" name="mailingLists" value="cmd3c94kz0hvz0iwt7ps28cyd" />
|
||||
<button type="submit" class="bg-light h-full px-5 py-[0.45rem] rounded-full border-b-2 border-[#B3866A] cursor-pointer hover:border-b-4 hover:transform active:border-b-0 active:transform active:translate-y-0.5 focus:outline-none transition-all duration-100 flex-shrink-0">
|
||||
<img src="submit.svg" alt="Go">
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<!-- Success overlay that slides in from left -->
|
||||
{#if submitted}
|
||||
<div class="absolute inset-0 -top-4 -bottom-4 bg-[#44DBC8] rounded-full flex items-center justify-center z-20 animate-slide-in {fadeOut ? 'animate-fade-out' : ''}">
|
||||
<span class="text-white font-sans text-lg">RSVPed!</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<a
|
||||
href="https://forms.hackclub.com/daydream-stickers"
|
||||
target="_blank"
|
||||
class="w-max px-4 py-2 bg-pink border-b-2 border-b-pink-dark text-white rounded-full active:transform active:translate-y-0.5 transition-all duration-100 font-sans cursor-pointer mx-auto relative overflow-visible hover:shadow-[0_2px_0_0_theme(colors.pink.dark)] hover:-translate-y-[2px] active:border-transparent active:shadow-none active: mt-4 md:hidden"
|
||||
>
|
||||
Get free stickers
|
||||
<img
|
||||
src="button-clouds.svg"
|
||||
alt=""
|
||||
class="absolute bottom-0 left-1/2 -translate-x-1/2 w-auto object-contain pointer-events-none"
|
||||
>
|
||||
<img
|
||||
src="rock-sticker.png"
|
||||
alt=""
|
||||
class="absolute bottom-2 right-3 translate-2/3 w-18 h-18 object-contain pointer-events-none"
|
||||
style="transform: rotate(-15deg);"
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
59
src/lib/components/Ticker.svelte
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<script lang="ts">
|
||||
export let tickerText: string;
|
||||
</script>
|
||||
|
||||
<!-- Animated text ticker along curvy line -->
|
||||
<div
|
||||
class="absolute top-0 left-1/2 -translate-x-1/2 w-full h-full pointer-events-none lg:-translate-y-35 -translate-y-20 overflow-hidden max-md:w-200 max-lg:w-[125%]"
|
||||
>
|
||||
<svg
|
||||
width="1280"
|
||||
height="464"
|
||||
viewBox="0 0 1280 464"
|
||||
class="w-full h-max pt-32 object-contain"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<defs>
|
||||
<path
|
||||
id="curvy-path"
|
||||
d="M-41 274.995C91.5 229.995 203.5 64.4946 483.5 39.9946C763.5 15.4946 892.5 151.495 1165 196.495C1383 232.495 1462.5 263.828 1475 274.995"
|
||||
/>
|
||||
<mask id="reveal-mask">
|
||||
<rect x="0" y="0" width="0" height="464" fill="white">
|
||||
<animate
|
||||
attributeName="width"
|
||||
values="0;1280"
|
||||
dur="2s"
|
||||
calcMode="spline"
|
||||
keySplines="0.05,0.7,0.3,1"
|
||||
keyTimes="0;1"
|
||||
begin="0.75s"
|
||||
fill="freeze"
|
||||
/>
|
||||
</rect>
|
||||
</mask>
|
||||
</defs>
|
||||
<g mask="url(#reveal-mask)">
|
||||
<!-- Background path stroke -->
|
||||
<path
|
||||
d="M-41 268.495C91.5 223.495 203.5 57.9946 483.5 33.4946C763.5 8.9946 892.5 144.995 1165 189.995C1383 225.995 1462.5 257.328 1475 268.495"
|
||||
stroke="#9EE4F2"
|
||||
stroke-width="28"
|
||||
fill="none"
|
||||
stroke-linecap="round"
|
||||
/>
|
||||
<text font-family="sans-serif" fill="#EDFCFF" font-weight="bold" font-size="18">
|
||||
<textPath href="#curvy-path" startOffset="-100%">
|
||||
{@html Array(2).fill(tickerText).join(' • ')} •
|
||||
<animate
|
||||
id="ticker-animation"
|
||||
attributeName="startOffset"
|
||||
values="-100%;0%"
|
||||
dur="30s"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
</textPath>
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
34
src/routes/+error.svelte
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { dev } from '$app/environment';
|
||||
|
||||
$: status = $page.status;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Error {status}</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="min-h-screen w-full relative bg-gradient-to-b from-[#639DEB] to-[#8EC7F0] flex items-center justify-center">
|
||||
<div class="absolute bottom-0 left-1/2 -translate-x-1/2 w-full h-[80vh] bg-[url(/cloudy-bg.png)] opacity-10 bg-cover bg-no-repeat bg-position-[0_10vh] pointer-events-none"></div>
|
||||
|
||||
<div class="absolute inset-0 bg-[url('/brushstroking.png')] bg-size-[100vw_100vh] bg-repeat mix-blend-overlay opacity-60 pointer-events-none"></div>
|
||||
|
||||
<div class="relative z-10 text-center text-white flex flex-col">
|
||||
|
||||
<h1 class="text-8xl font-serif text-white drop-shadow-lg">{status}</h1>
|
||||
<p class="text-2xl font-sans text-white mt-1">Something went wrong.</p>
|
||||
|
||||
<a
|
||||
href="/"
|
||||
class="w-max px-4 py-2 bg-pink border-b-2 border-b-pink-dark text-white rounded-full active:translate-y-0.5 transition-all duration-100 font-sans cursor-pointer mx-auto relative overflow-visible hover:shadow-[0_2px_0_0_theme(colors.pink.dark)] hover:-translate-y-[2px] active:border-transparent active:shadow-none mt-12"
|
||||
>
|
||||
Take me somewhere safe
|
||||
<img
|
||||
src="/button-clouds.svg"
|
||||
alt=""
|
||||
class="absolute bottom-0 left-1/2 -translate-x-1/2 w-auto object-contain pointer-events-none"
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
import { onMount } from "svelte";
|
||||
import { gsap } from "gsap";
|
||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||
import Ticker from "$lib/components/Ticker.svelte";
|
||||
import Footer from "$lib/components/Footer.svelte";
|
||||
|
||||
/** @type {import('./$types').PageData} */
|
||||
export let data;
|
||||
|
|
@ -581,11 +583,41 @@ Mumbai`.split("\n")
|
|||
}
|
||||
</style>
|
||||
|
||||
|
||||
<svelte:head>
|
||||
<title>Daydream</title>
|
||||
<title>Daydream - Teen Game Jam by Hack Club</title>
|
||||
<meta name="description" content="Join Daydream, the worldwide teen-led game jam by Hack Club! 4,000+ hackers building games in 100+ cities. Sign up to organize or participate in your city." />
|
||||
<meta name="keywords" content="game jam, hackathon, teen coding, Hack Club, game development, teen programming, high school coding" />
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://daydream.hackclub.com" />
|
||||
<meta property="og:title" content="Daydream - Teen Game Jam by Hack Club" />
|
||||
<meta property="og:description" content="Join Daydream, the worldwide teen-led game jam by Hack Club! 4,000+ hackers building games in 100+ cities. Sign up to organize or participate in your city." />
|
||||
<meta property="og:image" content="https://daydream.hackclub.com/og-image.png" />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:site_name" content="Daydream" />
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:url" content="https://daydream.hackclub.com" />
|
||||
<meta property="twitter:title" content="Daydream - Teen Game Jam by Hack Club" />
|
||||
<meta property="twitter:description" content="Join Daydream, the worldwide teen-led game jam by Hack Club! 4,000+ hackers building games in 100+ cities. Sign up to organize or participate in your city." />
|
||||
<meta property="twitter:image" content="https://daydream.hackclub.com/og-image.png" />
|
||||
<meta property="twitter:creator" content="@hackclub" />
|
||||
<meta property="twitter:site" content="@hackclub" />
|
||||
|
||||
<!-- Additional SEO -->
|
||||
<meta name="robots" content="index, follow" />
|
||||
<meta name="author" content="Hack Club" />
|
||||
<link rel="canonical" href="https://daydream.hackclub.com" />
|
||||
|
||||
<!-- Analytics -->
|
||||
<script defer data-domain="daydream.hackclub.com" src="https://plausible.io/js/script.js"></script>
|
||||
</svelte:head>
|
||||
|
||||
|
||||
<div class="absolute top-0 left-0 w-full h-full bg-[url('brushstroking.png')] bg-size-[100vw_100vh] bg-repeat mix-blend-overlay opacity-60 pointer-events-none"></div>
|
||||
|
||||
<div class="flex flex-col items-center justify-center h-screen text-center bg-gradient-to-b from-[#CCF4FD] to-[#B8D9F8] bg-blend-overlay relative">
|
||||
|
|
@ -596,30 +628,7 @@ Mumbai`.split("\n")
|
|||
|
||||
<div class="buildings-back-parallax absolute top-0 left-0 w-full h-full bg-[url(/buildings-back.png)] bg-no-repeat bg-contain pointer-events-none lg:-translate-y-15"></div>
|
||||
|
||||
<!-- Animated text ticker along curvy line -->
|
||||
<div class="absolute top-0 left-1/2 -translate-x-1/2 w-full h-full pointer-events-none lg:-translate-y-35 -translate-y-20 overflow-hidden max-md:w-200 max-lg:w-[125%]">
|
||||
<svg width="1280" height="464" viewBox="0 0 1280 464" class="w-full h-max pt-32 object-contain" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<path id="curvy-path" d="M-41 274.995C91.5 229.995 203.5 64.4946 483.5 39.9946C763.5 15.4946 892.5 151.495 1165 196.495C1383 232.495 1462.5 263.828 1475 274.995"/>
|
||||
<mask id="reveal-mask">
|
||||
<rect x="0" y="0" width="0" height="464" fill="white">
|
||||
<animate attributeName="width" values="0;1280" dur="2s" calcMode="spline" keySplines="0.05,0.7,0.3,1" keyTimes="0;1" begin="0.75s" fill="freeze"/>
|
||||
</rect>
|
||||
</mask>
|
||||
</defs>
|
||||
<g mask="url(#reveal-mask)">
|
||||
<!-- Background path stroke -->
|
||||
<path d="M-41 268.495C91.5 223.495 203.5 57.9946 483.5 33.4946C763.5 8.9946 892.5 144.995 1165 189.995C1383 225.995 1462.5 257.328 1475 268.495"
|
||||
stroke="#9EE4F2" stroke-width="28" fill="none" stroke-linecap="round"/>
|
||||
<text font-family="sans-serif" fill="#EDFCFF" font-weight="bold" font-size="18">
|
||||
<textPath href="#curvy-path" startOffset="-100%">
|
||||
{@html Array(2).fill(tickerText).join(" • ")} •
|
||||
<animate id="ticker-animation" attributeName="startOffset" values="-100%;0%" dur="30s" repeatCount="indefinite"/>
|
||||
</textPath>
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<Ticker {tickerText} />
|
||||
|
||||
<!-- brush texture clipped to back buildings -->
|
||||
<div class="absolute top-0 left-0 w-full h-full bg-[url('brushstroking.png')] bg-size-[100vw_100vh] bg-repeat pointer-events-none opacity-100 lg:-translate-y-15 bg-center mix-blend-overlay" style="mask-image: url('/buildings-back.png'); mask-size: contain; mask-repeat: no-repeat; mask-position: center top; -webkit-mask-image: url('/buildings-back.png'); -webkit-mask-size: contain; -webkit-mask-repeat: no-repeat; -webkit-mask-position: center top;"></div>
|
||||
|
|
@ -1100,28 +1109,7 @@ Mumbai`.split("\n")
|
|||
<div class="absolute top-0 left-0 w-full h-full bg-[url('brushstroking.png')] bg-size-[100vw_100vh] bg-repeat mix-blend-overlay opacity-60 pointer-events-none"></div>
|
||||
</div>
|
||||
|
||||
<div class="w-full bg-[#FFFFF8] relative min-h-80">
|
||||
<div class="absolute top-0 left-0 w-full h-full bg-[url('/noise.png')] bg-repeat opacity-10 pointer-events-none z-0"></div>
|
||||
<div class="opacity-60 absolute w-full h-32 bg-[url('brushstroking.png')] bg-repeat-x z-10 bg-size-[100vw_100vh] mix-blend-overlay" style="mask-image: url(/footer-clouds.png); mask-size: contain; mask-repeat: repeat-x; -webkit-mask-image: url(/footer-clouds.png); -webkit-mask-size: contain; -webkit-mask-repeat: repeat-x;"></div>
|
||||
<div class="w-full h-32 bg-[#e99cce] z-5" style="mask-image: url(/footer-clouds.png); mask-size: contain; mask-repeat: repeat-x; -webkit-mask-image: url(/footer-clouds.png); -webkit-mask-size: contain; -webkit-mask-repeat: repeat-x;"></div>
|
||||
|
||||
<!-- Footer Text -->
|
||||
<div class="absolute bottom-20 left-32 text-center z-20 max-md:bottom-12 max-md:left-8 max-md:right-4 max-md:text-left">
|
||||
<p class="text-gray-700 mb-2">Made with ♡ by teenagers, for teenagers at Hack Club</p>
|
||||
<div class="flex space-x-4 max-md:flex-col max-md:space-x-0 max-md:space-y-2">
|
||||
<a href="https://hackclub.com" class="underline text-gray-700 hover:text-gray-900 transition-colors ">Hack Club</a>
|
||||
<span class="text-gray-700 max-md:hidden">・</span>
|
||||
<a href="https://hackclub.com/slack" class="underline text-gray-700 hover:text-gray-900 transition-colors ">Slack</a>
|
||||
<span class="text-gray-700 max-md:hidden">・</span>
|
||||
<a href="https://hackclub.com/clubs" class="underline text-gray-700 hover:text-gray-900 transition-colors ">Clubs</a>
|
||||
<span class="text-gray-700 max-md:hidden">・</span>
|
||||
<a href="https://hackclub.com/hackathons" class="underline text-gray-700 hover:text-gray-900 transition-colors ">Hackathons</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="max-sm:hidden absolute bottom-2 right-16 h-2/3 aspect-square bg-[url('brushstroking.png')] bg-repeat z-10 bg-size-[100vw_100vh] mix-blend-overlay" style="mask-image: url(/thought-bubbles.png); mask-size: contain; mask-repeat: no-repeat; -webkit-mask-image: url(/thought-bubbles.png); -webkit-mask-size: contain; -webkit-mask-repeat: no-repeat;"></div>
|
||||
<div class="max-sm:hidden absolute bottom-2 right-16 h-2/3 aspect-square bg-[#e99cce]" style="mask-image: url(/thought-bubbles.png); mask-size: contain; mask-repeat: no-repeat; -webkit-mask-image: url(/thought-bubbles.png); -webkit-mask-size: contain; -webkit-mask-repeat: no-repeat;"></div>
|
||||
</div>
|
||||
<Footer />
|
||||
|
||||
<!-- Video Popup Modal -->
|
||||
{#if showVideoPopup}
|
||||
|
|
|
|||
99
src/routes/api/idea/+server.ts
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
import { json } from '@sveltejs/kit';
|
||||
|
||||
export async function POST() {
|
||||
try {
|
||||
// Create a varied, creative prompt using multiple techniques
|
||||
const randomElements = getRandomPromptElements();
|
||||
|
||||
const prompt = `Create a simple game idea for a beginner game jam.
|
||||
|
||||
GAME TYPE: ${randomElements.gameType}
|
||||
THEME: ${randomElements.theme}
|
||||
SETTING: ${randomElements.setting}
|
||||
|
||||
Turn these three elements into a single sentence game idea. Start with "A [game type] where you..." or "An [game type] where you..." and keep it simple and clear. Use normal words, no fancy language.`;
|
||||
|
||||
const response = await fetch('https://ai.hackclub.com/chat/completions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content: 'You are a practical game designer. Respond with ONLY a single sentence game idea. Use simple, plain language. One basic mechanic only. No fancy words, no poetry, no flowery descriptions.'
|
||||
},
|
||||
{ role: 'user', content: prompt }
|
||||
]
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`AI API request failed: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
let idea = data.choices[0]?.message?.content?.trim();
|
||||
|
||||
if (!idea) {
|
||||
throw new Error('No idea generated from AI response');
|
||||
}
|
||||
|
||||
// Clean up the response - remove any thinking tags or extra formatting
|
||||
idea = idea.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
|
||||
idea = idea.replace(/^["']/g, '').replace(/["']$/g, '').trim();
|
||||
|
||||
return json({ idea });
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error generating game idea:', error);
|
||||
return json({ error: 'Failed to generate game idea' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
function getRandomPromptElements() {
|
||||
const gameTypes = [
|
||||
"puzzle game", "arcade game", "platformer", "racing game", "rhythm game",
|
||||
"physics game", "strategy game", "tower defense", "stealth game", "adventure game",
|
||||
"simulation", "management game", "survival game", "exploration game", "maze game",
|
||||
"matching game", "building game", "collecting game", "jumping game", "flying game",
|
||||
"shooting game", "defense game", "escape game", "rescue game", "cooking game",
|
||||
"drawing game", "music game", "word game", "memory game", "reaction game",
|
||||
"sorting game", "stacking game", "rolling game", "sliding game", "rotating game",
|
||||
"growing game", "shrinking game", "merging game", "splitting game", "timing game"
|
||||
];
|
||||
|
||||
const themes = [
|
||||
"animals", "space", "underwater", "robots", "magic", "pirates", "ninjas", "knights",
|
||||
"zombies", "aliens", "dinosaurs", "dragons", "ghosts", "monsters", "superheroes", "wizards",
|
||||
"cats", "dogs", "birds", "fish", "insects", "plants", "flowers", "trees",
|
||||
"food", "candy", "pizza", "ice cream", "vegetables", "fruits", "cooking", "baking",
|
||||
"music", "dancing", "art", "painting", "drawing", "colors", "shapes", "patterns",
|
||||
"weather", "seasons", "rain", "snow", "sun", "clouds", "storms", "rainbows",
|
||||
"vehicles", "cars", "trains", "planes", "boats", "rockets", "bicycles", "trucks",
|
||||
"sports", "soccer", "basketball", "tennis", "golf", "baseball", "swimming", "running",
|
||||
"school", "library", "playground", "home", "garden", "park", "beach", "mountain",
|
||||
"friendship", "family", "helping", "sharing", "learning", "growing", "exploring", "discovering"
|
||||
];
|
||||
|
||||
const settings = [
|
||||
"forest", "castle", "spaceship", "underwater city", "desert", "mountain", "cave", "laboratory",
|
||||
"school", "playground", "park", "beach", "farm", "circus", "carnival", "zoo",
|
||||
"kitchen", "bakery", "restaurant", "garden", "greenhouse", "library", "museum", "theater",
|
||||
"factory", "workshop", "garage", "basement", "attic", "treehouse", "island", "village",
|
||||
"city", "town", "neighborhood", "street", "alley", "rooftop", "bridge", "tower",
|
||||
"maze", "dungeon", "temple", "pyramid", "ruins", "volcano", "glacier", "jungle",
|
||||
"swamp", "meadow", "valley", "hill", "cliff", "river", "lake", "pond",
|
||||
"space station", "alien planet", "moon base", "asteroid", "comet", "black hole", "nebula", "galaxy",
|
||||
"pirate ship", "treasure island", "haunted house", "magic realm", "fairy tale land", "dreamworld", "candy land", "toy store"
|
||||
];
|
||||
|
||||
const randomChoice = (array: any[]) => array[Math.floor(Math.random() * array.length)];
|
||||
|
||||
return {
|
||||
gameType: randomChoice(gameTypes),
|
||||
theme: randomChoice(themes),
|
||||
setting: randomChoice(settings)
|
||||
};
|
||||
}
|
||||
49
src/routes/api/rsvp/+server.js
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import Airtable from 'airtable';
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { AIRTABLE_API_KEY, AIRTABLE_BASE_ID, AIRTABLE_RSVPS_TABLE } from '$env/static/private';
|
||||
|
||||
if (!AIRTABLE_API_KEY || !AIRTABLE_BASE_ID) {
|
||||
console.warn('Airtable environment variables not configured, email saving will be skipped');
|
||||
}
|
||||
|
||||
const base = AIRTABLE_API_KEY && AIRTABLE_BASE_ID
|
||||
? new Airtable({
|
||||
apiKey: AIRTABLE_API_KEY
|
||||
}).base(AIRTABLE_BASE_ID)
|
||||
: null;
|
||||
|
||||
export async function POST({ request, getClientAddress }) {
|
||||
try {
|
||||
const { email } = await request.json();
|
||||
|
||||
if (!email) {
|
||||
return json({ error: 'Email is required' }, { status: 400 });
|
||||
}
|
||||
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(email)) {
|
||||
return json({ error: 'Invalid email format' }, { status: 400 });
|
||||
}
|
||||
|
||||
// get IP address
|
||||
const ip = request.headers.get('x-forwarded-for')?.split(',')[0] || getClientAddress();
|
||||
|
||||
if (base) {
|
||||
await base(AIRTABLE_RSVPS_TABLE || 'participant_rsvps').create([
|
||||
{
|
||||
fields: {
|
||||
email,
|
||||
ip,
|
||||
}
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
return new Response(null, { status: 200 });
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error saving email to Airtable:', error);
|
||||
|
||||
return new Response(null, { status: 418 });
|
||||
}
|
||||
}
|
||||
|
|
@ -26,11 +26,10 @@ export async function POST({ request, getClientAddress }) {
|
|||
}
|
||||
|
||||
// get IP address
|
||||
const ip = getClientAddress();
|
||||
const ip = request.headers.get('x-forwarded-for')?.split(',')[0] || getClientAddress();
|
||||
|
||||
let recordId = null;
|
||||
if (base) {
|
||||
const record = await base(AIRTABLE_EMAILS_TABLE || 'email_addresses').create([
|
||||
await base(AIRTABLE_EMAILS_TABLE || 'email_addresses').create([
|
||||
{
|
||||
fields: {
|
||||
email,
|
||||
|
|
@ -38,7 +37,6 @@ export async function POST({ request, getClientAddress }) {
|
|||
}
|
||||
}
|
||||
]);
|
||||
recordId = record[0].id;
|
||||
}
|
||||
|
||||
return new Response(null, { status: 200 });
|
||||
|
|
|
|||
42
src/routes/event-map/+page.server.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import { GEOCODER_API_KEY } from '$env/static/private';
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
/** @type {import('./$types').PageServerLoad} */
|
||||
export async function load({ url }) {
|
||||
const location = url.searchParams.get('location');
|
||||
|
||||
if (!GEOCODER_API_KEY || !location) {
|
||||
return {
|
||||
location: null,
|
||||
geocoded: null
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
// Geocode the provided location
|
||||
const geocodeUrl = `https://geocoder.hackclub.com/v1/geocode?address=${encodeURIComponent(location)}&key=${GEOCODER_API_KEY}`;
|
||||
const geocodeResponse = await fetch(geocodeUrl);
|
||||
|
||||
if (geocodeResponse.ok) {
|
||||
const geocodeData = await geocodeResponse.json();
|
||||
return {
|
||||
location,
|
||||
geocoded: {
|
||||
lat: geocodeData.lat,
|
||||
lng: geocodeData.lng,
|
||||
address: location
|
||||
}
|
||||
};
|
||||
} else {
|
||||
console.error(`Failed to geocode ${location}: ${geocodeResponse.status}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to geocode ${location}:`, error);
|
||||
}
|
||||
|
||||
return {
|
||||
location,
|
||||
geocoded: null
|
||||
};
|
||||
}
|
||||
396
src/routes/event-map/+page.svelte
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
/** @type {import('./$types').PageData} */
|
||||
export let data;
|
||||
|
||||
let mapContainer: HTMLElement;
|
||||
let map: any;
|
||||
|
||||
onMount(() => {
|
||||
if (browser) {
|
||||
// Mouse trail setup
|
||||
let mouseTrailPoints: Array<{ x: number; y: number }> = [];
|
||||
const maxTrailLength = 15;
|
||||
let animationId: number;
|
||||
|
||||
// Rainbow trail configuration - adjust these to tune the effect
|
||||
const colorChangeSpeed = 400; // Lower = faster color changes (was 800)
|
||||
const trailColorSpan = 25; // Degrees of color variation across trail length (was 15)
|
||||
const trailThicknessStart = 3; // Path thickness at tail (oldest points)
|
||||
const trailThicknessEnd = 8; // Path thickness at mouse (newest points)
|
||||
|
||||
function getHueFromIndex(index: number): number {
|
||||
return (index * 24) % 360; // Rainbow cycle through hues
|
||||
}
|
||||
|
||||
function updateMouseTrail(e: MouseEvent) {
|
||||
// Get fresh references to all SVG containers
|
||||
const svgs = [
|
||||
document.querySelector('#trail-svg-blur'),
|
||||
// document.querySelector('#trail-svg-main')
|
||||
];
|
||||
if (svgs.find(svg => !svg)) return;
|
||||
|
||||
const x = e.clientX;
|
||||
const y = e.clientY;
|
||||
|
||||
mouseTrailPoints.push({ x, y });
|
||||
|
||||
// Keep trail at max length
|
||||
if (mouseTrailPoints.length > maxTrailLength) {
|
||||
mouseTrailPoints.shift();
|
||||
}
|
||||
|
||||
// Clear existing paths and gradients
|
||||
if (mouseTrailPoints.length > 1) {
|
||||
svgs.forEach((svg: any) => {
|
||||
// Clear old elements
|
||||
const oldPaths = svg.querySelectorAll('.trail-segment');
|
||||
const oldGradients = svg.querySelectorAll('.segment-gradient');
|
||||
oldPaths.forEach((path: any) => path.remove());
|
||||
oldGradients.forEach((grad: any) => grad.remove());
|
||||
|
||||
// Ensure defs exists
|
||||
let defs = svg.querySelector('defs');
|
||||
if (!defs) {
|
||||
defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
|
||||
svg.appendChild(defs);
|
||||
}
|
||||
});
|
||||
|
||||
// Create individual path segments with gradient colors
|
||||
for (let i = 0; i < mouseTrailPoints.length - 1; i++) {
|
||||
const progress = i / (mouseTrailPoints.length - 1);
|
||||
const nextProgress = (i + 1) / (mouseTrailPoints.length - 1);
|
||||
|
||||
// Base color changes slowly over time, with subtle variations along trail
|
||||
const baseHue = getHueFromIndex(Date.now() / colorChangeSpeed);
|
||||
const hue1 = baseHue - (progress * trailColorSpan);
|
||||
const hue2 = baseHue - (nextProgress * trailColorSpan);
|
||||
|
||||
// Create paths in all SVGs
|
||||
svgs.forEach((svg: any, svgIndex: number) => {
|
||||
if (!svg) return;
|
||||
|
||||
const defs = svg.querySelector('defs');
|
||||
if (!defs) return;
|
||||
|
||||
// Create gradient for this segment (unique ID per SVG)
|
||||
const gradient = document.createElementNS('http://www.w3.org/2000/svg', 'linearGradient');
|
||||
gradient.classList.add('segment-gradient');
|
||||
gradient.setAttribute('id', `segment-gradient-${svgIndex}-${i}`);
|
||||
gradient.setAttribute('x1', '0%');
|
||||
gradient.setAttribute('y1', '0%');
|
||||
gradient.setAttribute('x2', '100%');
|
||||
gradient.setAttribute('y2', '0%');
|
||||
|
||||
const stop1 = document.createElementNS('http://www.w3.org/2000/svg', 'stop');
|
||||
stop1.setAttribute('offset', '0%');
|
||||
stop1.setAttribute('stop-color', `hsl(${hue1}, 70%, 60%)`);
|
||||
|
||||
const stop2 = document.createElementNS('http://www.w3.org/2000/svg', 'stop');
|
||||
stop2.setAttribute('offset', '100%');
|
||||
stop2.setAttribute('stop-color', `hsl(${hue2}, 70%, 60%)`);
|
||||
|
||||
gradient.appendChild(stop1);
|
||||
gradient.appendChild(stop2);
|
||||
defs.appendChild(gradient);
|
||||
|
||||
// Create path with gradient stroke - bigger at mouse (newest), smaller at tail (oldest)
|
||||
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
||||
path.classList.add('trail-segment');
|
||||
path.setAttribute('d', `M${mouseTrailPoints[i].x},${mouseTrailPoints[i].y} L${mouseTrailPoints[i + 1].x},${mouseTrailPoints[i + 1].y}`);
|
||||
path.setAttribute('stroke', `url(#segment-gradient-${svgIndex}-${i})`);
|
||||
path.setAttribute('stroke-width', `${trailThicknessStart + (trailThicknessEnd - trailThicknessStart) * progress}`);
|
||||
path.setAttribute('stroke-linecap', 'round');
|
||||
path.setAttribute('stroke-linejoin', 'round');
|
||||
path.setAttribute('fill', 'none');
|
||||
|
||||
svg.appendChild(path);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearMouseTrail() {
|
||||
mouseTrailPoints = [];
|
||||
const svgs = [
|
||||
document.querySelector('#trail-svg-blur'),
|
||||
// document.querySelector('#trail-svg-main')
|
||||
];
|
||||
svgs.forEach((svg: any) => {
|
||||
if (svg) {
|
||||
const oldPaths = svg.querySelectorAll('.trail-segment');
|
||||
oldPaths.forEach((path: any) => path.remove());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Trail fade animation - only remove points every few frames
|
||||
let frameCount = 0;
|
||||
function animateTrail() {
|
||||
frameCount++;
|
||||
|
||||
// Only remove points every 3 frames to slow down the fade
|
||||
if (frameCount % 3 === 0 && mouseTrailPoints.length > 0) {
|
||||
mouseTrailPoints.shift();
|
||||
|
||||
// Redraw trail segments with updated colors
|
||||
const svgs = [
|
||||
document.querySelector('#trail-svg-blur'),
|
||||
// document.querySelector('#trail-svg-main')
|
||||
];
|
||||
if (mouseTrailPoints.length > 1 && !svgs.find(svg => !svg)) {
|
||||
svgs.forEach((svg: any) => {
|
||||
// Clear old elements
|
||||
const oldPaths = svg.querySelectorAll('.trail-segment');
|
||||
const oldGradients = svg.querySelectorAll('.segment-gradient');
|
||||
oldPaths.forEach((path: any) => path.remove());
|
||||
oldGradients.forEach((grad: any) => grad.remove());
|
||||
|
||||
// Ensure defs exists
|
||||
let defs = svg.querySelector('defs');
|
||||
if (!defs) {
|
||||
defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
|
||||
svg.appendChild(defs);
|
||||
}
|
||||
});
|
||||
|
||||
// Redraw segments with gradients
|
||||
for (let i = 0; i < mouseTrailPoints.length - 1; i++) {
|
||||
const progress = i / (mouseTrailPoints.length - 1);
|
||||
const nextProgress = (i + 1) / (mouseTrailPoints.length - 1);
|
||||
|
||||
// Base color changes slowly over time, with subtle variations along trail
|
||||
const baseHue = getHueFromIndex(Date.now() / colorChangeSpeed);
|
||||
const hue1 = baseHue - (progress * trailColorSpan);
|
||||
const hue2 = baseHue - (nextProgress * trailColorSpan);
|
||||
|
||||
// Create paths in all SVGs
|
||||
svgs.forEach((svg: any, svgIndex: number) => {
|
||||
if (!svg) return;
|
||||
|
||||
const defs = svg.querySelector('defs');
|
||||
if (!defs) return;
|
||||
|
||||
// Create gradient
|
||||
const gradient = document.createElementNS('http://www.w3.org/2000/svg', 'linearGradient');
|
||||
gradient.classList.add('segment-gradient');
|
||||
gradient.setAttribute('id', `segment-gradient-${svgIndex}-${i}`);
|
||||
gradient.setAttribute('x1', '0%');
|
||||
gradient.setAttribute('y1', '0%');
|
||||
gradient.setAttribute('x2', '100%');
|
||||
gradient.setAttribute('y2', '0%');
|
||||
|
||||
const stop1 = document.createElementNS('http://www.w3.org/2000/svg', 'stop');
|
||||
stop1.setAttribute('offset', '0%');
|
||||
stop1.setAttribute('stop-color', `hsl(${hue1}, 70%, 60%)`);
|
||||
|
||||
const stop2 = document.createElementNS('http://www.w3.org/2000/svg', 'stop');
|
||||
stop2.setAttribute('offset', '100%');
|
||||
stop2.setAttribute('stop-color', `hsl(${hue2}, 70%, 60%)`);
|
||||
|
||||
gradient.appendChild(stop1);
|
||||
gradient.appendChild(stop2);
|
||||
defs.appendChild(gradient);
|
||||
|
||||
// Create path - bigger at mouse (newest), smaller at tail (oldest)
|
||||
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
||||
path.classList.add('trail-segment');
|
||||
path.setAttribute('d', `M${mouseTrailPoints[i].x},${mouseTrailPoints[i].y} L${mouseTrailPoints[i + 1].x},${mouseTrailPoints[i + 1].y}`);
|
||||
path.setAttribute('stroke', `url(#segment-gradient-${svgIndex}-${i})`);
|
||||
path.setAttribute('stroke-width', `${trailThicknessStart + (trailThicknessEnd - trailThicknessStart) * progress}`);
|
||||
path.setAttribute('stroke-linecap', 'round');
|
||||
path.setAttribute('stroke-linejoin', 'round');
|
||||
path.setAttribute('fill', 'none');
|
||||
|
||||
svg.appendChild(path);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
animationId = requestAnimationFrame(animateTrail);
|
||||
}
|
||||
|
||||
// Wait for DOM and get elements
|
||||
setTimeout(() => {
|
||||
const svgs = [
|
||||
document.querySelector('#trail-svg-blur'),
|
||||
// document.querySelector('#trail-svg-main')
|
||||
];
|
||||
|
||||
if (!svgs.find(svg => !svg)) {
|
||||
// Event listeners
|
||||
document.addEventListener('mousemove', updateMouseTrail);
|
||||
document.addEventListener('mouseleave', clearMouseTrail);
|
||||
|
||||
// Start animation loop
|
||||
animateTrail();
|
||||
}
|
||||
}, 100);
|
||||
|
||||
// Initialize Leaflet
|
||||
import('leaflet').then((L) => {
|
||||
// Load CSS
|
||||
const link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css';
|
||||
document.head.appendChild(link);
|
||||
|
||||
// Initialize map
|
||||
map = L.map(mapContainer, {
|
||||
minZoom: 2,
|
||||
maxZoom: 18
|
||||
}).setView([20, 0], 2);
|
||||
|
||||
// Add tile layer with custom styling
|
||||
L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
|
||||
attribution: '© OpenStreetMap contributors © CARTO',
|
||||
detectRetina: true
|
||||
}).addTo(map);
|
||||
|
||||
// Create custom icon using map-flag.png
|
||||
const flagIcon = L.icon({
|
||||
iconUrl: '/map-flag.png',
|
||||
iconSize: [32, 32],
|
||||
iconAnchor: [16, 32],
|
||||
popupAnchor: [0, -32]
|
||||
});
|
||||
|
||||
// Add marker for the specified location if geocoded successfully
|
||||
if (data.geocoded && data.geocoded.lat && data.geocoded.lng) {
|
||||
// Set the map view to the geocoded location with higher zoom
|
||||
map.setView([data.geocoded.lat, data.geocoded.lng], 13);
|
||||
|
||||
const marker = L.marker([data.geocoded.lat, data.geocoded.lng], { icon: flagIcon })
|
||||
.addTo(map);
|
||||
|
||||
// Create popup that shows the address
|
||||
const popup = L.popup({
|
||||
closeButton: false,
|
||||
className: 'custom-popup'
|
||||
}).setContent(data.geocoded.address);
|
||||
|
||||
marker.bindPopup(popup);
|
||||
|
||||
// Show popup on hover, hide on mouseout
|
||||
marker.on('mouseover', () => {
|
||||
marker.openPopup();
|
||||
});
|
||||
marker.on('mouseout', () => {
|
||||
marker.closePopup();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Cleanup function
|
||||
return () => {
|
||||
document.removeEventListener('mousemove', updateMouseTrail);
|
||||
document.removeEventListener('mouseleave', clearMouseTrail);
|
||||
if (animationId) {
|
||||
cancelAnimationFrame(animationId);
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Event Location Map</title>
|
||||
</svelte:head>
|
||||
|
||||
<!-- Mouse trailer SVGs -->
|
||||
<!-- Background blurred layer -->
|
||||
<!-- svelte-ignore component_name_lowercase -->
|
||||
<svg id="trail-svg-blur" class="fixed top-0 left-0 w-full h-full pointer-events-none z-[9998]" style="filter: blur(10px); opacity: 0.75">
|
||||
<!-- Individual path segments will be added here dynamically -->
|
||||
</svg>
|
||||
|
||||
<!-- Foreground sharp layer -->
|
||||
<!-- svelte-ignore component_name_lowercase -->
|
||||
<svg id="trail-svg-main" class="fixed top-0 left-0 w-full h-full pointer-events-none z-[9999]" style="filter: blur(3px) saturate(0) brightness(1000); opacity: 0.25">
|
||||
<!-- Individual path segments will be added here dynamically -->
|
||||
</svg>
|
||||
|
||||
<div bind:this={mapContainer} class="w-full h-screen"></div>
|
||||
|
||||
<style>
|
||||
:global(body) {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Map container styling */
|
||||
:global(.leaflet-container) {
|
||||
background: linear-gradient(135deg, #CCF4FD 0%, #B8D9F8 100%) !important;
|
||||
border-radius: 16px !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
/* Map controls styling */
|
||||
:global(.leaflet-control-zoom a) {
|
||||
background: #44DBC8 !important;
|
||||
border: 2px solid #3CC2AF !important;
|
||||
color: white !important;
|
||||
border-radius: 8px !important;
|
||||
box-shadow: 0 4px 12px rgba(68, 219, 200, 0.3) !important;
|
||||
transition: all 0.2s ease-in-out !important;
|
||||
}
|
||||
|
||||
:global(.leaflet-control-zoom a:hover) {
|
||||
background: #3CC2AF !important;
|
||||
transform: translateY(-1px) !important;
|
||||
box-shadow: 0 6px 16px rgba(68, 219, 200, 0.4) !important;
|
||||
}
|
||||
|
||||
:global(.leaflet-control-attribution) {
|
||||
background: rgba(252, 247, 196, 0.9) !important;
|
||||
border: 1px solid #D3B180 !important;
|
||||
border-radius: 8px !important;
|
||||
color: #78531D !important;
|
||||
font-family: 'Atkinson Hyperlegible', system-ui, sans-serif !important;
|
||||
backdrop-filter: blur(8px) !important;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:global(.leaflet-control-attribution a) {
|
||||
color: #4477A3 !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
:global(.leaflet-control-attribution a:hover) {
|
||||
color: #44DBC8 !important;
|
||||
}
|
||||
|
||||
/* Custom popup styling */
|
||||
:global(.custom-popup .leaflet-popup-content-wrapper) {
|
||||
background: #FFFBDF !important;
|
||||
border: 1px solid #D3B180 !important;
|
||||
border-radius: 8px !important;
|
||||
box-shadow: 0 4px 8px rgba(211, 177, 128, 0.15) !important;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif !important;
|
||||
}
|
||||
|
||||
:global(.custom-popup .leaflet-popup-content) {
|
||||
margin: 8px 12px !important;
|
||||
color: #78531D !important;
|
||||
font-size: 14px !important;
|
||||
font-weight: 500 !important;
|
||||
line-height: 1.2 !important;
|
||||
}
|
||||
|
||||
:global(.custom-popup .leaflet-popup-tip) {
|
||||
background: #FFFBDF !important;
|
||||
border: 1px solid #D3B180 !important;
|
||||
border-top: none !important;
|
||||
border-right: none !important;
|
||||
}
|
||||
|
||||
/* Tile layer filter for softer appearance */
|
||||
:global(.leaflet-tile-pane) {
|
||||
filter: hue-rotate(5deg) saturate(0.8) brightness(1.1) !important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -80,9 +80,9 @@ The PoC will get a link to your Daydream event's HCB org, and an onboarding vide
|
|||
|
||||
### **4\) Get a custom email**
|
||||
|
||||
Want a [city@daydream.hackclub.com](mailto:city@daydream.hackclub.com) email? Fill out this form\! This is a shared account that the team can use to send out communications to attendees (especially for quest
|
||||
Want a [city@daydream.hackclub.com](mailto:city@daydream.hackclub.com) email? This will be coming to event PoCs soonTM! This is a shared Google Workspace account that the team can use to send out mass, personalized communications to attendees, and should be the contact email listed on your website so people can ask you questions.
|
||||
|
||||
(also, it's kind of awesome)
|
||||
(it's kind of awesome. Google Workspace ftw)
|
||||
|
||||
<CloudImage src="/guide/email.png" />
|
||||
|
||||
|
|
@ -211,4 +211,4 @@ And we're here to give it to you. Reserve a 10 minute call with Meghana, RenRan,
|
|||
|
||||
You're not just building a hackathon. You're building a space where someone might code their very first game. Meet their best friend. Find their love ♥️ (for tech).
|
||||
|
||||
That's our daydream. And we're so, so excited to see what you'll build.
|
||||
That's our daydream. And we're so, so excited to see what you'll build.
|
||||
|
|
|
|||
|
|
@ -60,6 +60,6 @@ More fancy ones:
|
|||
* Hoodies
|
||||
* Something custom\!
|
||||
|
||||
Note: HCB currently offers a $500 grant for jukebox ([jukebox.com](http://jukebox.com)) if your account has 10+ organizers/people who follows it.
|
||||
Note: HCB currently offers a $500 grant for jukebox ([ukeboxprint.com](http://https://www.jukeboxprint.com/)) if your account has 10+ organizers/people who follows it.
|
||||
|
||||
Jukebox is a custom sticker/postcard/prints shop\!
|
||||
|
|
|
|||
37
src/routes/guide/merch/+page.svx
Normal file
|
|
@ -124,4 +124,4 @@ RenRan
|
|||
|
||||
## Extra: Tips & Advice
|
||||
|
||||
Make the highest tier more than half of your budget. **The lowest tier should also be a significant contribution.** For example: if your budget is $8k, make $5k your highest tier and $1.5k your lowest tier.
|
||||
Make the highest tier more than half of your budget. **The lowest tier should also be a significant contribution.** For example: if your budget is $8k, make $5k your highest tier and $1.5k your lowest tier.
|
||||
|
|
|
|||
|
|
@ -2,10 +2,6 @@
|
|||
|
||||
Your daydream needs its own website. This might be one of the only technical aspects you'll need when organizing your hackathon – and day-of mentoring.
|
||||
|
||||
<div class="font-bold bg-red-500/20 p-4 rounded-md text-red-950">
|
||||
Note: The following guide walks through how to set up the website template. The website template is still currently a work-in-progress. If you'd like to use the website template, please wait until later this week.
|
||||
</div>
|
||||
|
||||
Now… on to how to make your site\!
|
||||
|
||||
First, fork the repository:
|
||||
|
|
|
|||
BIN
static/banner-city.png
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
static/billboard-bars.png
Normal file
|
After Width: | Height: | Size: 628 B |
BIN
static/billboard-bg-texture.png
Normal file
|
After Width: | Height: | Size: 566 B |
BIN
static/billboard-lights.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
static/billboard-pillar.png
Normal file
|
After Width: | Height: | Size: 934 B |
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 62 KiB |
BIN
static/dice/dice-1.png
Normal file
|
After Width: | Height: | Size: 185 B |
BIN
static/dice/dice-2.png
Normal file
|
After Width: | Height: | Size: 195 B |
BIN
static/dice/dice-3.png
Normal file
|
After Width: | Height: | Size: 202 B |
BIN
static/dice/dice-4.png
Normal file
|
After Width: | Height: | Size: 191 B |
BIN
static/dice/dice-5.png
Normal file
|
After Width: | Height: | Size: 200 B |
BIN
static/dice/dice-6.png
Normal file
|
After Width: | Height: | Size: 190 B |
BIN
static/dream-pixel.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
static/example/logo1.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
static/example/logo2.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
static/example/logo3.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
static/example/logo4.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
static/example/logo5.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
static/example/logo6.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
static/example/logo7.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
/* Define the Daydream fonts */
|
||||
@font-face {
|
||||
font-family: 'Expensify New Kansas';
|
||||
font-family: 'Daydream New';
|
||||
font-display: swap;
|
||||
src: url('https://daydream.hackclub.com/fonts/serif.woff') format('woff');
|
||||
font-weight: 400;
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Expensify New Kansas';
|
||||
font-family: 'Daydream New';
|
||||
font-display: swap;
|
||||
src: url('https://daydream.hackclub.com/fonts/serif-italic.woff') format('woff');
|
||||
font-weight: 400;
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
/* Apply serif font to all headers */
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: 'Expensify New Kansas', ui-serif, serif !important;
|
||||
font-family: 'Daydream New', ui-serif, serif !important;
|
||||
color: #833710;
|
||||
font-style: italic;
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ h1, h2, h3, h4, h5, h6 {
|
|||
|
||||
/* Button styling - matching the "get free stickers" button */
|
||||
[data-cy="button-component"] {
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
padding: 8px 16px;
|
||||
background-color: #E472AB;
|
||||
border: none;
|
||||
|
|
@ -61,6 +61,7 @@ h1, h2, h3, h4, h5, h6 {
|
|||
[data-cy="button-component"]:hover {
|
||||
box-shadow: 0 2px 0 0 #A65A80;
|
||||
transform: translateY(-2px);
|
||||
background-color: #E472AB !important;
|
||||
}
|
||||
|
||||
[data-cy="button-component"]:active {
|
||||
|
|
@ -136,8 +137,27 @@ a {
|
|||
color: #548abb;
|
||||
}
|
||||
|
||||
/* the "- Or -" divider */
|
||||
.text-sm > span.px-2 {
|
||||
background-color: #FFFBDF !important;
|
||||
}
|
||||
|
||||
/* make the 'Thank You' text use the header font */
|
||||
.fillout-field-thank-you > div > div > div:not(.mt-\[3px\]) p {
|
||||
font-family: 'Expensify New Kansas', ui-serif, serif !important;
|
||||
font-family: 'Daydream New', ui-serif, serif !important;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* make the checkbox text clickable */
|
||||
div:has(> div > [role="checkbox"]) p {
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
/* 'sign in with google' button */
|
||||
[data-cy="button-component"] .text-blue-500 {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.fillout-field-send-response > div {
|
||||
background: #fffef2;
|
||||
}
|
||||
BIN
static/gamejam-1-alt.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
static/macintosh-frame.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
static/macintosh-hc-logo.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
static/macintosh-keyboard.png
Normal file
|
After Width: | Height: | Size: 606 KiB |
BIN
static/macintosh.png
Normal file
|
After Width: | Height: | Size: 737 KiB |
BIN
static/og-image.png
Normal file
|
After Width: | Height: | Size: 632 KiB |