kinda finished
This commit is contained in:
		
							parent
							
								
									8a37f14a48
								
							
						
					
					
						commit
						11d9b7a0b4
					
				
					 11 changed files with 2706 additions and 162 deletions
				
			
		
							
								
								
									
										5
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.dockerignore
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | ||||||
|  | Dockerfile | ||||||
|  | node_modules/ | ||||||
|  | build/ | ||||||
|  | .svelte-kit/ | ||||||
|  | .idea/ | ||||||
							
								
								
									
										16
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | ||||||
|  | FROM node:23-alpine AS base | ||||||
|  | WORKDIR /app | ||||||
|  | 
 | ||||||
|  | FROM base AS dependencies | ||||||
|  | COPY package*.json /app/ | ||||||
|  | RUN npm ci | ||||||
|  | 
 | ||||||
|  | FROM base AS build | ||||||
|  | COPY --from=dependencies /app/node_modules /app/node_modules | ||||||
|  | COPY . /app | ||||||
|  | RUN npm run build | ||||||
|  | 
 | ||||||
|  | FROM base AS release | ||||||
|  | COPY --from=build /app/build /app/build | ||||||
|  | 
 | ||||||
|  | CMD ["node", "/app/build/index.js"] | ||||||
							
								
								
									
										
											BIN
										
									
								
								bun.lockb
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								bun.lockb
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2501
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										2501
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -14,7 +14,7 @@ | ||||||
| 	}, | 	}, | ||||||
| 	"devDependencies": { | 	"devDependencies": { | ||||||
| 		"@eslint/compat": "^1.2.3", | 		"@eslint/compat": "^1.2.3", | ||||||
| 		"@sveltejs/adapter-static": "^3.0.6", | 		"@sveltejs/adapter-node": "^5.2.11", | ||||||
| 		"@sveltejs/kit": "^2.0.0", | 		"@sveltejs/kit": "^2.0.0", | ||||||
| 		"@sveltejs/vite-plugin-svelte": "^4.0.0", | 		"@sveltejs/vite-plugin-svelte": "^4.0.0", | ||||||
| 		"eslint": "^9.7.0", | 		"eslint": "^9.7.0", | ||||||
|  | @ -28,8 +28,5 @@ | ||||||
| 		"typescript": "^5.0.0", | 		"typescript": "^5.0.0", | ||||||
| 		"typescript-eslint": "^8.0.0", | 		"typescript-eslint": "^8.0.0", | ||||||
| 		"vite": "^5.4.11" | 		"vite": "^5.4.11" | ||||||
| 	}, |  | ||||||
| 	"dependencies": { |  | ||||||
| 		"svelte-adapter-bun": "^0.5.2" |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ | ||||||
| 
 | 
 | ||||||
| <div class="modal"> | <div class="modal"> | ||||||
| 	<div class="modal-content"> | 	<div class="modal-content"> | ||||||
| 		<button class="close" onclick={props.onclose}> X </button> | 		<button class="close" onclick={props.onclose}>X</button> | ||||||
| 		<video autoplay muted> | 		<video autoplay muted> | ||||||
| 			<source src={props.videoUrl} type="video/mp4" /> | 			<source src={props.videoUrl} type="video/mp4" /> | ||||||
| 			Your browser does not support the video tag. | 			Your browser does not support the video tag. | ||||||
|  |  | ||||||
							
								
								
									
										30
									
								
								src/routes/+layout.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/routes/+layout.svelte
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | ||||||
|  | <script lang="ts"> | ||||||
|  | 	let { children } = $props(); | ||||||
|  | </script> | ||||||
|  | <main> | ||||||
|  | 	{@render children()} | ||||||
|  | </main> | ||||||
|  | 
 | ||||||
|  | <style> | ||||||
|  |     :global(body) { | ||||||
|  |         margin: 0; | ||||||
|  |         font-family: 'Arial', sans-serif; | ||||||
|  |         background-color: #f4f4f4; | ||||||
|  |         color: #1c1919; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     main { | ||||||
|  |         display: flex; | ||||||
|  |         flex-direction: column; | ||||||
|  |         justify-content: center; | ||||||
|  |         align-items: center; | ||||||
|  |         height: 100vh; | ||||||
|  |         width: 100vw; | ||||||
|  |         background-color: #a8571c; | ||||||
|  |         color: white; | ||||||
|  |         text-align: center; | ||||||
|  |         overflow: hidden; | ||||||
|  |         padding: 20px; | ||||||
|  |         box-sizing: border-box; | ||||||
|  |     } | ||||||
|  | </style> | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| 	import Modal from '$lib/Modal.svelte'; | 	import Modal from '$lib/Modal.svelte'; | ||||||
| 
 | 	import { page } from '$app/state'; | ||||||
|  | 	 | ||||||
| 	const difficultyClass = 15; | 	const difficultyClass = 15; | ||||||
| 	const skin = 'winter'; | 	const skin = 'winter'; | ||||||
| 
 | 
 | ||||||
|  | @ -23,12 +24,14 @@ | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	const handleRoll = async () => { | 	const handleRoll = async () => { | ||||||
|  | 		if (rollResult) return; | ||||||
| 		rollResult = Math.floor(Math.random() * 20) + 1; | 		rollResult = Math.floor(Math.random() * 20) + 1; | ||||||
| 		rollVideoUrl = await getVideoUrl(skin, 'd20', rollResult); | 		rollVideoUrl = await getVideoUrl(skin, 'd20', rollResult); | ||||||
| 		showModal('roll'); | 		showModal('roll'); | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	const handleGuidance = async () => { | 	const handleGuidance = async () => { | ||||||
|  | 		if (guidanceResult) return; | ||||||
| 		guidanceResult = Math.floor(Math.random() * 4) + 1; | 		guidanceResult = Math.floor(Math.random() * 4) + 1; | ||||||
| 		guidanceVideoUrl = await getVideoUrl(skin, 'd4', guidanceResult); | 		guidanceVideoUrl = await getVideoUrl(skin, 'd4', guidanceResult); | ||||||
| 		showModal('guidance'); | 		showModal('guidance'); | ||||||
|  | @ -49,182 +52,159 @@ | ||||||
| 	}; | 	}; | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <main> | <section> | ||||||
|  | 	<h1>You have received a gift</h1> | ||||||
|  | </section> | ||||||
|  | 
 | ||||||
|  | <section> | ||||||
|  | 	<h2>Investigation</h2> | ||||||
|  | 	<p>Intelligence check</p> | ||||||
|  | </section> | ||||||
|  | 
 | ||||||
|  | <section> | ||||||
|  | 	<h2>Difficulty Class</h2> | ||||||
|  | 	<p>{difficultyClass}</p> | ||||||
|  | </section> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | {#if !pressedContinue} | ||||||
| 	<section> | 	<section> | ||||||
| 		<h1>You have received a gift</h1> | 		{#if !rollResult} | ||||||
|  | 			<button onclick={handleRoll}>Roll Ability</button> | ||||||
|  | 		{/if} | ||||||
|  | 		{#if rollResult && rollClickedExit} | ||||||
|  | 			<h2>Roll Result</h2> | ||||||
|  | 			<p>{rollResult}</p> | ||||||
|  | 		{/if} | ||||||
| 	</section> | 	</section> | ||||||
| 
 | 
 | ||||||
| 	<section> | 	{#if rollModal && rollVideoUrl} | ||||||
| 		<h2>Investigation</h2> | 		<Modal onclose={() => { | ||||||
| 		<p>Intelligence check</p> |  | ||||||
| 	</section> |  | ||||||
| 
 |  | ||||||
| 	<section> |  | ||||||
| 		<h2>Difficulty Class</h2> |  | ||||||
| 		<p>{difficultyClass}</p> |  | ||||||
| 	</section> |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	{#if !pressedContinue} |  | ||||||
| 		<section> |  | ||||||
| 			{#if !rollResult} |  | ||||||
| 				<button onclick={handleRoll}>Roll Ability</button> |  | ||||||
| 			{/if} |  | ||||||
| 			{#if rollResult && rollClickedExit} |  | ||||||
| 				<h2>Roll Result</h2> |  | ||||||
| 				<p>{rollResult}</p> |  | ||||||
| 			{/if} |  | ||||||
| 		</section> |  | ||||||
| 
 |  | ||||||
| 		{#if rollModal && rollVideoUrl} |  | ||||||
| 			<Modal onclose={() => { |  | ||||||
| 				rollModal = false; | 				rollModal = false; | ||||||
| 				rollClickedExit = true; | 				rollClickedExit = true; | ||||||
| 			}} videoUrl={rollVideoUrl} /> | 			}} videoUrl={rollVideoUrl} /> | ||||||
| 		{/if} |  | ||||||
| 		<section> |  | ||||||
| 			{#if !guidanceResult} |  | ||||||
| 				<button onclick={handleGuidance}>Roll Guidance</button> |  | ||||||
| 			{/if} |  | ||||||
| 			{#if guidanceResult && guidanceClickedExit} |  | ||||||
| 				<h2>Guidance Result</h2> |  | ||||||
| 				<p>{guidanceResult}</p> |  | ||||||
| 			{/if} |  | ||||||
| 		</section> |  | ||||||
| 
 |  | ||||||
| 		{#if guidanceModal && guidanceVideoUrl} |  | ||||||
| 			<Modal onclose={() => { |  | ||||||
| 				guidanceModal = false; |  | ||||||
| 				guidanceClickedExit = true; |  | ||||||
| 			}} videoUrl={guidanceVideoUrl} /> |  | ||||||
| 		{/if} |  | ||||||
| 
 |  | ||||||
| 		{#if rollResult && guidanceResult} |  | ||||||
| 			<button class="continue" onclick={() => {pressedContinue = true}}>Continue</button> |  | ||||||
| 		{/if} |  | ||||||
| 	{/if} | 	{/if} | ||||||
| 
 |  | ||||||
| 	<section> | 	<section> | ||||||
| 		{#if rollResult && guidanceResult && pressedContinue} | 		{#if !guidanceResult} | ||||||
| 			<h2>Final Result</h2> | 			<button onclick={handleGuidance}>Roll Guidance</button> | ||||||
| 			<p>{rollResult + guidanceResult}</p> | 		{/if} | ||||||
| 			{#if rollResult + guidanceResult >= difficultyClass} | 		{#if guidanceResult && guidanceClickedExit} | ||||||
| 				<h2 class="success">Success</h2> | 			<h2>Guidance Result</h2> | ||||||
| 				<a href="/present">Collect your gift!</a> | 			<p>{guidanceResult}</p> | ||||||
| 			{:else} |  | ||||||
| 				<h2 class="failure">Failure</h2> |  | ||||||
| 				<button class="reset" onclick={resetPage}> Reset</button> |  | ||||||
| 			{/if} |  | ||||||
| 		{/if} | 		{/if} | ||||||
| 	</section> | 	</section> | ||||||
| 
 | 
 | ||||||
| </main> | 	{#if guidanceModal && guidanceVideoUrl} | ||||||
|  | 		<Modal onclose={() => { | ||||||
|  | 				guidanceModal = false; | ||||||
|  | 				guidanceClickedExit = true; | ||||||
|  | 			}} videoUrl={guidanceVideoUrl} /> | ||||||
|  | 	{/if} | ||||||
|  | 
 | ||||||
|  | 	{#if rollResult && guidanceResult} | ||||||
|  | 		<button class="continue" onclick={() => {pressedContinue = true}}>Continue</button> | ||||||
|  | 	{/if} | ||||||
|  | {/if} | ||||||
|  | 
 | ||||||
|  | <section> | ||||||
|  | 	{#if rollResult && guidanceResult && pressedContinue} | ||||||
|  | 		<h2>Final Result</h2> | ||||||
|  | 		<p>{rollResult + guidanceResult}</p> | ||||||
|  | 		{#if rollResult + guidanceResult >= difficultyClass} | ||||||
|  | 			<h2 class="success">Success</h2> | ||||||
|  | 			<a href="/present{page.url.search}">Collect your gift!</a> | ||||||
|  | 		{:else} | ||||||
|  | 			<h2 class="failure">Failure</h2> | ||||||
|  | 			<button class="reset" onclick={resetPage}> Reset</button> | ||||||
|  | 		{/if} | ||||||
|  | 	{/if} | ||||||
|  | </section> | ||||||
| 
 | 
 | ||||||
| <style> | <style> | ||||||
| 		:global(body) { |  | ||||||
|     margin: 0; |  | ||||||
|     font-family: 'Arial', sans-serif; |  | ||||||
|     background-color: #f4f4f4; |  | ||||||
|     color: #1c1919; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| main { |     h1, h2 { | ||||||
|     display: flex; |         font-size: 2rem; | ||||||
|     flex-direction: column; |         font-weight: bold; | ||||||
|     justify-content: center; |         margin: 20px 0; | ||||||
|     align-items: center; |     } | ||||||
|     height: 100vh; |  | ||||||
|     width: 100vw; |  | ||||||
|     background-color: #a8571c; |  | ||||||
|     color: white; |  | ||||||
|     text-align: center; |  | ||||||
|     overflow: hidden; |  | ||||||
|     padding: 20px; |  | ||||||
|     box-sizing: border-box; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| h1, h2 { |     section { | ||||||
|     font-size: 2rem; |         margin: 15px 0; | ||||||
|     font-weight: bold; |         width: 100%; | ||||||
|     margin: 20px 0; |         max-width: 400px; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| section { |     p { | ||||||
|     margin: 15px 0; |         font-size: 1.2rem; | ||||||
|     width: 100%; |     } | ||||||
|     max-width: 400px; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| p { |     button { | ||||||
|     font-size: 1.2rem; |         background-color: #1c1919; | ||||||
| } |         color: white; | ||||||
|  |         padding: 12px 25px; | ||||||
|  |         font-size: 1.1rem; | ||||||
|  |         font-weight: bold; | ||||||
|  |         border: none; | ||||||
|  |         border-radius: 5px; | ||||||
|  |         cursor: pointer; | ||||||
|  |         transition: background-color 0.3s ease; | ||||||
|  |         margin-top: 15px; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| button { |     button:hover { | ||||||
|     background-color: #1c1919; |         background-color: #333; | ||||||
|     color: white; |     } | ||||||
|     padding: 12px 25px; |  | ||||||
|     font-size: 1.1rem; |  | ||||||
|     font-weight: bold; |  | ||||||
|     border: none; |  | ||||||
|     border-radius: 5px; |  | ||||||
|     cursor: pointer; |  | ||||||
|     transition: background-color 0.3s ease; |  | ||||||
|     margin-top: 15px; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| button:hover { |     button:disabled { | ||||||
|     background-color: #333; |         background-color: #aaa; | ||||||
| } |         cursor: not-allowed; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| button:disabled { |     a { | ||||||
|     background-color: #aaa; |         color: #fff; | ||||||
|     cursor: not-allowed; |         text-decoration: none; | ||||||
| } |         font-weight: bold; | ||||||
|  |         font-size: 1.2rem; | ||||||
|  |         margin-top: 20px; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| a { |     a:hover { | ||||||
|     color: #fff; |         text-decoration: underline; | ||||||
|     text-decoration: none; |     } | ||||||
|     font-weight: bold; |  | ||||||
|     font-size: 1.2rem; |  | ||||||
|     margin-top: 20px; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| a:hover { |     h2 { | ||||||
|     text-decoration: underline; |         color: #ffdf00; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| h2 { |     h2.success { | ||||||
|     color: #ffdf00; |         color: #4CAF50; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| h2.success { |     h2.failure { | ||||||
|     color: #4CAF50; |         color: #FF6347; | ||||||
| } |     } | ||||||
| 
 | 
 | ||||||
| h2.failure { |     button.reset { | ||||||
|     color: #FF6347; |         background-color: #ff6347; | ||||||
| } |         padding: 10px 20px; | ||||||
|  |         font-size: 1.1rem; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| button.reset { |     button.reset:hover { | ||||||
|     background-color: #ff6347; |         background-color: #e55347; | ||||||
|     padding: 10px 20px; |     } | ||||||
|     font-size: 1.1rem; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| button.reset:hover { |     button.continue { | ||||||
|     background-color: #e55347; |         background-color: #4CAF50; | ||||||
| } |         padding: 10px 20px; | ||||||
|  |         font-size: 1.1rem; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| button.continue { |     button.continue:hover { | ||||||
|     background-color: #4CAF50; |         background-color: #45a049; | ||||||
|     padding: 10px 20px; |     } | ||||||
|     font-size: 1.1rem; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| button.continue:hover { |     section > button { | ||||||
|     background-color: #45a049; |         margin-top: 20px; | ||||||
| } |     } | ||||||
| 
 | </style> | ||||||
| section > button { |  | ||||||
|     margin-top: 20px; |  | ||||||
| }</style> |  | ||||||
|  |  | ||||||
|  | @ -1,8 +1,23 @@ | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| 	// Show the gift key that was in ENV during build | 	import { page } from '$app/state'; | ||||||
| 	const steamGiftKey = import.meta.env.VITE_STEAM_GIFT_KEY; | 
 | ||||||
|  | 	let steamGiftKey = $state<string | null>(null); | ||||||
|  | 	let isLegit = $state<boolean>(true); | ||||||
|  | 
 | ||||||
|  | 	$effect(() => { | ||||||
|  | 		const bk = page.url.searchParams.get('bk'); | ||||||
|  | 		if (!bk) { | ||||||
|  | 			isLegit = false; | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 		steamGiftKey = atob(bk); | ||||||
|  | 	}); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <h1>Congrats!</h1> | {#if isLegit} | ||||||
| <h2>Here is your prize <3</h2> | 	<h1>Congrats!</h1> | ||||||
| <p>{steamGiftKey}</p> | 	<h2>Enjoy your gift <3</h2> | ||||||
|  | 	<p>{steamGiftKey}</p> | ||||||
|  | {:else} | ||||||
|  | 	<h1>Sorry, this gift is not for you</h1> | ||||||
|  | {/if} | ||||||
										
											Binary file not shown.
										
									
								
							|  | @ -1,4 +1,4 @@ | ||||||
| import adapter from 'svelte-adapter-bun' | import adapter from '@sveltejs/adapter-node' | ||||||
| import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; | ||||||
| 
 | 
 | ||||||
| /** @type {import('@sveltejs/kit').Config} */ | /** @type {import('@sveltejs/kit').Config} */ | ||||||
|  |  | ||||||
		Reference in a new issue