feat: improve guesses collapse timing, win screen CTA, and progress page polish

- GuessesTable now accepts a `minimized` prop instead of deriving collapse from `isWon`, giving the parent control over timing
- Delay collapsing guesses grid until win animations complete (1800ms), skipped for already-completed puzzles
- Replace plain progress link on win screen with a styled green button matching other CTAs
- Progress page: remove redundant subtitle and nav button from header, add book status legend, add axis labels to guess history chart

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
George Powell
2026-03-22 00:47:02 -04:00
parent 3eb3a968dc
commit 45d33b6bad
4 changed files with 104 additions and 19 deletions

View File

@@ -5,13 +5,17 @@
let {
guesses,
correctBookId,
isWon = false,
}: { guesses: Guess[]; correctBookId: string; isWon?: boolean } = $props();
minimized = false,
}: { guesses: Guess[]; correctBookId: string; minimized?: boolean } = $props();
let hasGuesses = $derived(guesses.length > 0);
let showMinimized = $derived(isWon && guesses.length > 3);
let showMinimized = $derived(minimized);
let expanded = $state(false);
$effect(() => {
if (!minimized) expanded = false;
});
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";

View File

@@ -330,12 +330,9 @@
{/if}
{#if isLoggedIn}
<a
href="/progress"
class="text-sm text-center text-gray-500 dark:text-gray-400 hover:text-emerald-600 dark:hover:text-emerald-400 transition-colors"
>
View your progress →
</a>
<div class="signin-prompt">
<a href="/progress" class="progress-btn"> 📈 See your progress </a>
</div>
{:else}
<div class="signin-prompt">
<p class="signin-text">
@@ -712,4 +709,43 @@
height: 1.1rem;
flex-shrink: 0;
}
.progress-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 0.6rem 1rem;
width: 100%;
margin-bottom: 0.6rem;
background: #059669;
color: #fff;
border-radius: 0.5rem;
font-size: 0.95rem;
font-weight: 600;
text-decoration: none;
transition:
background 150ms ease,
transform 80ms ease;
}
.progress-btn:hover {
background: #047857;
transform: translateY(-1px);
}
.progress-btn:active {
background: #065f46;
transform: scale(0.98);
}
@media (prefers-color-scheme: dark) {
.progress-btn {
background: #10b981;
color: #fff;
}
.progress-btn:hover {
background: #059669;
}
.progress-btn:active {
background: #047857;
}
}
</style>

View File

@@ -53,6 +53,7 @@
let statsData = $state<StatsData | null>(null);
let streak = $state(0);
let streakPercentile = $state<number | null>(null);
let guessesMinimized = $state(false);
const persistence = createGamePersistence(
() => dailyVerse.date,
@@ -204,6 +205,23 @@
}
});
// Delay collapsing the guesses grid until animations complete (mirrors showWinScreen delay)
$effect(() => {
if (!isWon || persistence.guesses.length <= 3) {
guessesMinimized = false;
return;
}
if (persistence.isWinAlreadyTracked()) {
guessesMinimized = true;
} else {
const animationDelay = 1800;
const timeoutId = setTimeout(() => {
guessesMinimized = true;
}, animationDelay);
return () => clearTimeout(timeoutId);
}
});
// Track win analytics
$effect(() => {
if (!browser || !isWon) return;
@@ -333,7 +351,7 @@
<GuessesTable
guesses={persistence.guesses}
{correctBookId}
{isWon}
minimized={guessesMinimized}
/>
</div>

View File

@@ -186,16 +186,11 @@
<div class="max-w-3xl mx-auto">
<!-- Header -->
<div class="text-center mb-6 md:mb-8">
<h1 class="text-3xl md:text-4xl font-bold text-gray-100 mb-2">
<h1 class="text-3xl md:text-4xl font-bold text-gray-100 mb-4">
Your Progress
</h1>
<p class="text-sm md:text-base text-gray-300 mb-4">
Your Bible knowledge journey
</p>
<a
href="/"
class="inline-flex items-center px-4 py-2 bg-amber-600 text-white rounded-lg hover:bg-amber-700 transition-colors text-sm font-medium shadow-md"
>
<a href="/" class="p-2 px-20 w-full items-center text-gray-300">
&larr; Back to Game
</a>
</div>
@@ -360,6 +355,16 @@
</div>
{/each}
</div>
<p class="text-xs text-gray-500 mt-3 leading-relaxed">
<span class="text-blue-400 font-medium">Explored</span>
— played at least once<br />
<span class="text-emerald-400 font-medium"
>Mastered</span
>
— avg &le; 3 guesses over 2+ plays<br />
<span class="text-amber-400 font-medium">Perfect</span>
mastered and guessed in 1 at least once
</p>
</Container>
</div>
@@ -382,7 +387,7 @@
</span>
</div>
<svg
viewBox="0 0 400 120"
viewBox="0 0 400 135"
class="w-full"
aria-hidden="true"
>
@@ -406,6 +411,13 @@
/>
</linearGradient>
</defs>
<!-- Y-axis label -->
<text
transform="translate(8, 60) rotate(-90)"
text-anchor="middle"
font-size="8"
fill="#9ca3af"
>Guesses</text>
<!-- Fill polygon -->
<polygon
points="{polylinePoints} {svgX(
@@ -454,12 +466,27 @@
>
{chartPoints[chartPoints.length - 1].label}
</text>
<!-- X-axis title -->
<text
x="200"
y="132"
font-size="8"
fill="#9ca3af"
text-anchor="middle"
>Date</text>
</svg>
{#if chartImproving}
<p class="text-xs text-emerald-400 mt-1">
You're getting better!
</p>
{/if}
<p
class="text-xs text-gray-500 mt-2 leading-relaxed"
>
Each point is your average guesses over a
rolling window of games. A downward trend means
you're improving.
</p>
</div>
</Container>
</div>