From 68a946a0a07cd6661c480d9854511db12be8cb4d Mon Sep 17 00:00:00 2001 From: George Powell Date: Fri, 19 Dec 2025 02:53:45 -0500 Subject: [PATCH] redirect to bibdle.dev and components --- src/lib/components/Feedback.svelte | 15 ++ src/lib/components/GuessesTable.svelte | 66 +++++++ src/lib/components/SearchInput.svelte | 55 ++++++ src/lib/components/VerseDisplay.svelte | 19 ++ src/lib/components/WinScreen.svelte | 74 ++++++++ src/lib/index.ts | 7 + src/lib/utils/game.ts | 43 +++++ src/routes/+page.server.ts | 5 +- src/routes/+page.svelte | 245 +++---------------------- src/routes/dev/+page.svelte | 107 +++++++++++ 10 files changed, 415 insertions(+), 221 deletions(-) create mode 100644 src/lib/components/Feedback.svelte create mode 100644 src/lib/components/GuessesTable.svelte create mode 100644 src/lib/components/SearchInput.svelte create mode 100644 src/lib/components/VerseDisplay.svelte create mode 100644 src/lib/components/WinScreen.svelte create mode 100644 src/lib/utils/game.ts create mode 100644 src/routes/dev/+page.svelte diff --git a/src/lib/components/Feedback.svelte b/src/lib/components/Feedback.svelte new file mode 100644 index 0000000..6643361 --- /dev/null +++ b/src/lib/components/Feedback.svelte @@ -0,0 +1,15 @@ + + +
+ Thank you so much for playing! Feel free to email me directly with feedback: + george@snail.city +
diff --git a/src/lib/components/GuessesTable.svelte b/src/lib/components/GuessesTable.svelte new file mode 100644 index 0000000..6783d97 --- /dev/null +++ b/src/lib/components/GuessesTable.svelte @@ -0,0 +1,66 @@ + + +
+ + + + + + + + + + {#each guesses as guess (guess.book.id)} + + + + + + {/each} + +
BookTestamentSection
+ {guess.book.id === correctBookId ? "✅" : "❌"} + {guess.book.name} + + {guess.testamentMatch ? "✅" : "🟥"} + {guess.book.testament.charAt(0).toUpperCase() + + guess.book.testament.slice(1).toLowerCase()} + + {guess.sectionMatch ? "✅" : "🟥"} + {guess.adjacent ? "‼️ " : ""}{guess.book.section} +
+
diff --git a/src/lib/components/SearchInput.svelte b/src/lib/components/SearchInput.svelte new file mode 100644 index 0000000..efc3f32 --- /dev/null +++ b/src/lib/components/SearchInput.svelte @@ -0,0 +1,55 @@ + + +
+ + {#if searchQuery && filteredBooks.length > 0} + + {:else if searchQuery} +

No books found

+ {/if} +
diff --git a/src/lib/components/VerseDisplay.svelte b/src/lib/components/VerseDisplay.svelte new file mode 100644 index 0000000..b489d80 --- /dev/null +++ b/src/lib/components/VerseDisplay.svelte @@ -0,0 +1,19 @@ + + +
+
+ {dailyVerse.verseText} +
+ {#if isWon} +

+ {dailyVerse.reference} +

+ {/if} +
diff --git a/src/lib/components/WinScreen.svelte b/src/lib/components/WinScreen.svelte new file mode 100644 index 0000000..2665e2c --- /dev/null +++ b/src/lib/components/WinScreen.svelte @@ -0,0 +1,74 @@ + + +
+

+ 🎉 Congratulations! 🎉 +

+

+ The verse is from {bookName} +

+

+ Your grade: {grade} +

+ + + + + {#if statsData} +
+

+ You were the {toOrdinal(statsData.solveRank)} person to solve today. +

+

+ You rank {toOrdinal(statsData.guessRank)} in guesses. +

+

+ Average: {statsData.averageGuesses.toFixed(1)} guesses +

+
+ {:else if !statsSubmitted} +
Submitting stats...
+ {/if} +
diff --git a/src/lib/index.ts b/src/lib/index.ts index 856f2b6..e2d8bf3 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1 +1,8 @@ // place files you want to import through the `$lib` alias in this folder. + +export * from './utils/game'; +export { default as VerseDisplay } from './components/VerseDisplay.svelte'; +export { default as SearchInput } from './components/SearchInput.svelte'; +export { default as GuessesTable } from './components/GuessesTable.svelte'; +export { default as WinScreen } from './components/WinScreen.svelte'; +export { default as Feedback } from './components/Feedback.svelte'; diff --git a/src/lib/utils/game.ts b/src/lib/utils/game.ts new file mode 100644 index 0000000..d7b5ef1 --- /dev/null +++ b/src/lib/utils/game.ts @@ -0,0 +1,43 @@ +import { bibleBooks, type BibleBook } from '$lib/types/bible'; + +export function getBookById(id: string): BibleBook | undefined { + return bibleBooks.find((b) => b.id === id); +} + +export function isAdjacent(id1: string, id2: string): boolean { + const b1 = getBookById(id1); + const b2 = getBookById(id2); + return !!(b1 && b2 && Math.abs(b1.order - b2.order) === 1); +} + +export function getGrade(numGuesses: number, popularity: number): string { + const difficulty = 14 - popularity; + const performanceScore = Math.max(0, 10 - numGuesses); + const totalScore = performanceScore + difficulty * 0.8; + if (totalScore >= 14) return "🟢 S"; + if (totalScore >= 11) return "🟢 A"; + if (totalScore >= 8) return "🟡 B"; + if (totalScore >= 5) return "🟠 C"; + return "🔴 C-"; +} + +export function toOrdinal(n: number): string { + if (n >= 11 && n <= 13) { + return `${n}th`; + } + const mod = n % 10; + const suffix = mod === 1 ? "st" : mod === 2 ? "nd" : mod === 3 ? "rd" : "th"; + return `${n}${suffix}`; +} + +export function generateUUID(): string { + if (typeof window !== 'undefined' && typeof (window as any).crypto?.randomUUID === "function") { + return (window as any).crypto.randomUUID(); + } + // Fallback + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + const r = ((window as any).crypto.getRandomValues(new Uint8Array(1))[0] % 16) | 0; + const v = c === "x" ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); +} \ No newline at end of file diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts index 6bc2326..7fc85b6 100644 --- a/src/routes/+page.server.ts +++ b/src/routes/+page.server.ts @@ -6,13 +6,10 @@ import { fail } from '@sveltejs/kit'; import { fetchRandomVerse } from '$lib/server/bible-api'; import { getBookById } from '$lib/server/bible'; import type { DailyVerse } from '$lib/server/db/schema'; -import type { BibleBook } from '$lib/types/bible'; import crypto from 'node:crypto'; async function getTodayVerse(): Promise { - const today = new Date(); - today.setUTCHours(0, 0, 0, 0); - const dateStr = today.toISOString().slice(0, 10); + const dateStr = new Date().toLocaleDateString('en-CA', { timeZone: 'America/New_York' }); const existing = await db.select().from(dailyVerses).where(eq(dailyVerses.date, dateStr)).limit(1); if (existing.length > 0) { diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index ce36f78..9b99ed8 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -12,6 +12,13 @@ import { browser } from "$app/environment"; import { fade } from "svelte/transition"; + import VerseDisplay from "$lib/components/VerseDisplay.svelte"; + import SearchInput from "$lib/components/SearchInput.svelte"; + import GuessesTable from "$lib/components/GuessesTable.svelte"; + import WinScreen from "$lib/components/WinScreen.svelte"; + import Feedback from "$lib/components/Feedback.svelte"; + import { getGrade } from "$lib/utils/game"; + let { data }: PageProps = $props(); let dailyVerse = $derived(data.dailyVerse); @@ -22,6 +29,7 @@ let searchQuery = $state(""); let copied = $state(false); + let isDev = $state(false); let anonymousId = $state(""); let statsSubmitted = $state(false); @@ -32,12 +40,6 @@ averageGuesses: number; } | null>(null); - let filteredBooks = $derived( - bibleBooks.filter((book) => - book.name.toLowerCase().includes(searchQuery.toLowerCase()), - ), - ); - let guessedIds = $derived(new Set(guesses.map((g) => g.book.id))); let isWon = $derived(guesses.some((g) => g.book.id === correctBookId)); @@ -90,27 +92,6 @@ searchQuery = ""; } - function getGrade(numGuesses: number, popularity: number): string { - const difficulty = 14 - popularity; - const performanceScore = Math.max(0, 10 - numGuesses); - const totalScore = performanceScore + difficulty * 0.8; - if (totalScore >= 14) return "🟢 S"; - if (totalScore >= 11) return "🟢 A"; - if (totalScore >= 8) return "🟡 B"; - if (totalScore >= 5) return "🟠 C"; - return "🔴 C-"; - } - - function toOrdinal(n: number): string { - if (n >= 11 && n <= 13) { - return `${n}th`; - } - const mod = n % 10; - const suffix = - mod === 1 ? "st" : mod === 2 ? "nd" : mod === 3 ? "rd" : "th"; - return `${n}${suffix}`; - } - function generateUUID(): string { // Try native randomUUID if available if (typeof window.crypto.randomUUID === "function") { @@ -145,6 +126,11 @@ statsSubmitted = localStorage.getItem(statsKey) === "true"; }); + $effect(() => { + if (!browser) return; + isDev = window.location.host === "192.168.0.42:5174"; + }); + // Load saved guesses $effect(() => { if (!browser) return; @@ -334,212 +320,37 @@ - Bibdle + Bibdle{isDev ? " dev" : ""}

- Bibdle + Bibdle {isDev ? "dev" : ""}

- -
-
- {dailyVerse.verseText} -
- {#if isWon} -

- {dailyVerse.reference} -

- {/if} -
+ {#if !isWon} - -
- { - if (e.key === "Enter" && filteredBooks.length > 0) { - submitGuess(filteredBooks[0].id); - } - }} - /> - {#if searchQuery && filteredBooks.length > 0} -
    - {#each filteredBooks as book} -
  • - -
  • - {/each} -
- {:else if searchQuery} -

- No books found -

- {/if} -
+ {:else} -
-

- 🎉 Congratulations! 🎉 -

-

- The verse is from {getBookById(correctBookId)?.name} -

- -

- Your grade: {grade} -

- - - - - {#if statsData} -
-

- You were the {toOrdinal(statsData.solveRank)} person - to solve today. -

-

- You rank {toOrdinal(statsData.guessRank)} in guesses. -

- -

- Average: {statsData.averageGuesses.toFixed(1)} guesses -

-
- {:else if !statsSubmitted} -
- Submitting stats... -
- {/if} -
+ {/if} - -
- - - - - - - - - - {#each guesses as guess (guess.book.id)} - - - - - - {/each} - -
BookTestamentSection
- {guess.book.id === correctBookId ? "✅" : "❌"} - {guess.book.name} - - {guess.testamentMatch ? "✅" : "🟥"} - {guess.book.testament.charAt(0).toUpperCase() + - guess.book.testament.slice(1).toLowerCase()} - - {guess.sectionMatch ? "✅" : "🟥"} - {guess.adjacent ? "‼️ " : ""}{guess.book - .section} -
-
+ {#if isWon} -
- Thank you so much for playing! Feel free to email me directly - with feedback: - george@snail.city -
+ {/if}
diff --git a/src/routes/dev/+page.svelte b/src/routes/dev/+page.svelte new file mode 100644 index 0000000..c924612 --- /dev/null +++ b/src/routes/dev/+page.svelte @@ -0,0 +1,107 @@ + + + + Bibdle Dev Debug + + +
+
+

+ Bibdle Dev Debug +

+ +
+
+

Browser Local Time

+

+ {localTime} +

+
+ +
+

UTC Time

+

+ {utcTime} +

+
+ +
+

Today (Browser Local)

+

+ {todayDate} +

+
+ +
+

+ Countdown to Next Bible Verse (Midnight, local browser time) +

+
+

+ {countdown} +

+

Next date: {nextDate}

+
+
+
+
+