Files
bibdle/src/lib/components/GuessesTable.svelte
2026-01-28 14:57:22 -05:00

202 lines
5.3 KiB
Svelte

<script lang="ts">
import { bibleBooks } from "$lib/types/bible";
import Container from "./Container.svelte";
interface Guess {
book: {
id: string;
name: string;
testament: string;
section: string;
};
testamentMatch: boolean;
sectionMatch: boolean;
adjacent: boolean;
firstLetterMatch: boolean;
}
let {
guesses,
correctBookId,
}: { guesses: Guess[]; correctBookId: string } = $props();
let hasGuesses = $derived(guesses.length > 0);
function getBoxColor(isCorrect: boolean, isAdjacent?: boolean): string {
if (isCorrect) return "bg-green-500 border-green-600";
if (isAdjacent) return "bg-yellow-500 border-yellow-600";
return "bg-red-500 border-red-600";
}
function getBoxContent(
guess: Guess,
column: "book" | "firstLetter" | "testament" | "section",
): string {
switch (column) {
case "book":
return guess.book.name;
case "firstLetter":
// Check if this is the special Epistles + "1" case
const correctBook = bibleBooks.find(
(b) => b.id === correctBookId,
);
const correctIsEpistlesWithNumber =
(correctBook?.section === "Pauline Epistles" ||
correctBook?.section === "General Epistles") &&
correctBook.name[0] === "1";
const guessStartsWithNumber = guess.book.name[0] === "1";
if (
correctIsEpistlesWithNumber &&
guessStartsWithNumber &&
guess.firstLetterMatch
) {
return "Yes"; // Special wordplay case
}
return guess.book.name[0]; // Normal case: just show the first letter
case "testament":
return (
guess.book.testament.charAt(0).toUpperCase() +
guess.book.testament.slice(1).toLowerCase()
);
case "section":
return guess.book.section;
}
}
</script>
{#if !hasGuesses}
<Container class="p-6 text-center">
<h2 class="font-triodion text-xl italic mb-3 text-gray-800">
Instructions
</h2>
<p class="text-gray-700 leading-relaxed italic">
Guess what book of the bible you think the verse is from. You will
get clues to tell you if your guess is close or not. Green means the
category is correct; red means wrong.
</p>
</Container>
{:else}
<div class="space-y-3">
<!-- Column Headers -->
<div
class="flex gap-2 justify-center mb-4 pb-2 border-b border-gray-400"
>
<div
class="w-1/4 shrink-0 text-center text-sm font-semibold text-gray-700"
>
Book
</div>
<div
class="w-1/4 shrink-0 text-center text-sm font-semibold text-gray-700"
>
Testament
</div>
<div
class="w-1/4 shrink-0 text-center text-sm font-semibold text-gray-700"
>
Section
</div>
<div
class="w-1/4 shrink-0 text-center text-sm font-semibold text-gray-700"
>
First Letter
</div>
</div>
{#each guesses as guess, rowIndex (guess.book.id)}
<div class="flex gap-2 justify-center">
<!-- Book Column -->
<div
class="w-1/4 shrink-0 h-16 sm:h-20 md:h-24 border-2 border-opacity-80 rounded-lg flex items-center justify-center text-white font-bold text-base sm:text-lg md:text-xl shadow-lg animate-flip-in {getBoxColor(
guess.book.id === correctBookId,
)}"
style="animation-delay: {rowIndex * 1000 + 0 * 500}ms"
>
<span class="text-center leading-tight px-1 text-shadow-lg"
>{getBoxContent(guess, "book")}</span
>
</div>
<!-- Testament Column -->
<div
class="w-1/4 shrink-0 h-16 sm:h-20 md:h-24 border-2 border-opacity-80 rounded-lg flex items-center justify-center text-white font-bold text-base sm:text-lg md:text-xl shadow-md animate-flip-in {getBoxColor(
guess.testamentMatch,
)}"
style="animation-delay: {rowIndex * 1000 + 1 * 500}ms"
>
<span class="text-center leading-tight px-1 text-shadow-sm"
>{getBoxContent(guess, "testament")}</span
>
</div>
<!-- Section Column -->
<div
class="relative w-1/4 shrink-0 h-16 sm:h-20 md:h-24 border-2 border-opacity-80 rounded-lg flex items-center justify-center text-white font-bold text-base sm:text-lg md:text-xl shadow-md animate-flip-in {getBoxColor(
guess.sectionMatch,
guess.adjacent,
)}"
style="animation-delay: {rowIndex * 1000 + 2 * 500}ms"
>
<span class="text-center leading-tight px-1 text-shadow-sm"
>{getBoxContent(guess, "section")}
{#if guess.adjacent}
‼️
{/if}
</span>
</div>
<!-- First Letter Column -->
<div
class="w-1/4 shrink-0 h-16 sm:h-20 md:h-24 border-2 border-opacity-80 rounded-lg flex items-center justify-center text-white font-bold text-base sm:text-lg md:text-xl shadow-md animate-flip-in {getBoxColor(
guess.firstLetterMatch,
)}"
style="animation-delay: {rowIndex * 1000 + 3 * 500}ms"
>
<span class="text-center leading-tight px-1 text-shadow-sm"
>{getBoxContent(guess, "firstLetter")}</span
>
</div>
</div>
{/each}
</div>
<!-- </div> -->
{/if}
<style>
@keyframes flipIn {
0% {
opacity: 0;
transform: rotateX(-90deg);
}
50% {
transform: rotateX(0deg);
}
100% {
opacity: 1;
transform: rotateX(0deg);
}
}
.animate-flip-in {
opacity: 0;
transform: rotateX(-90deg);
animation: flipIn 0.6s ease-out forwards;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.fade-in {
animation: fadeIn 0.5s ease-out;
}
</style>