added toggle verse display and fixed timer spacing

This commit is contained in:
George Powell
2026-02-26 01:23:13 -05:00
parent f3c9feaf97
commit e1a665ba63
4 changed files with 98 additions and 10 deletions

View File

@@ -73,7 +73,7 @@
Next Verse In
</p>
<p
class="text-4xl font-triodion font-black text-gray-800 tabular-nums"
class="text-4xl font-triodion font-black text-gray-800 tabular-nums whitespace-nowrap"
>
{timeUntilNext}
</p>

View File

@@ -1,6 +1,11 @@
<script lang="ts">
import { fade, fly } from "svelte/transition";
import { getBookById, toOrdinal } from "$lib/utils/game";
import {
getVerseSnippet,
shareResult,
copyToClipboard as clipboardCopy,
} from "$lib/utils/share";
import Container from "./Container.svelte";
import CountdownTimer from "./CountdownTimer.svelte";
import StreakCounter from "./StreakCounter.svelte";
@@ -31,6 +36,7 @@
reference,
onChapterGuessCompleted,
shareText,
verseText,
streak = 0,
streakPercentile = null,
}: {
@@ -44,6 +50,7 @@
reference: string;
onChapterGuessCompleted: () => void;
shareText: string;
verseText: string;
streak?: number;
streakPercentile?: number | null;
} = $props();
@@ -55,6 +62,22 @@
let copySuccess = $state(false);
let bubbleCopied = $state(false);
let copyTracked = $state(false);
let showSnippetOption = $state(false);
let includeSnippet = $state(false);
let effectiveShareText = $derived(
includeSnippet
? (() => {
const snippet = getVerseSnippet(verseText);
const lines = shareText.split("\n");
return [
...lines.slice(0, -1),
snippet,
lines[lines.length - 1],
].join("\n");
})()
: shareText,
);
// List of congratulations messages with weights
const congratulationsMessages: WeightedMessage[] = [
@@ -132,11 +155,11 @@
{/if}
<div class="flex flex-row gap-3 items-stretch w-full">
<div class="flex-[2] min-w-0 flex flex-col">
<div class="flex-2 min-w-0 flex flex-col">
<CountdownTimer />
</div>
{#if streak > 0}
<div class="flex-[1] min-w-0 flex flex-col">
<div class="flex-1 min-w-0 flex flex-col">
<StreakCounter {streak} {streakPercentile} />
</div>
{/if}
@@ -224,7 +247,7 @@
onclick={() => {
if (hasWebShare) {
(window as any).rybbit?.event("Share");
handleShare();
shareResult(effectiveShareText);
} else {
if (!copyTracked) {
(window as any).rybbit?.event(
@@ -232,7 +255,7 @@
);
copyTracked = true;
}
copyToClipboard();
clipboardCopy(effectiveShareText);
copySuccess = true;
setTimeout(() => {
copySuccess = false;
@@ -261,12 +284,13 @@
(window as any).rybbit?.event("Copy to Clipboard");
copyTracked = true;
}
copyToClipboard();
clipboardCopy(effectiveShareText);
showSnippetOption = true;
bubbleCopied = true;
setTimeout(() => {
bubbleCopied = false;
}, 2000);
}}>{shareText}</button
}}>{effectiveShareText}</button
>
{#if hasWebShare}
<span class="copy-hint"
@@ -280,6 +304,21 @@
</div>
</div>
</div>
{#if showSnippetOption}
<div class="snippet-toggle-row mr-4" in:fly={{ y: -8, duration: 220 }}>
<span class="snippet-label">Show verse snippet in share?</span>
<button
class="snippet-toggle"
class:on={includeSnippet}
onclick={() => (includeSnippet = !includeSnippet)}
aria-pressed={includeSnippet}
aria-label="Show snippet in share"
>
<span class="toggle-thumb"></span>
</button>
</div>
{/if}
</div>
<style>
@@ -485,4 +524,53 @@
transform-origin: right center;
margin-top: -6px;
}
/* ── Snippet toggle row ── */
.snippet-toggle-row {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 0.5rem;
padding: 0 0.25rem;
}
.snippet-label {
font-size: 0.72rem;
color: #666;
letter-spacing: 0.01em;
user-select: none;
}
.snippet-toggle {
position: relative;
width: 36px;
height: 20px;
border-radius: 10px;
background: #ccc;
border: none;
cursor: pointer;
transition: background 200ms ease;
flex-shrink: 0;
padding: 0;
}
.snippet-toggle.on {
background: #34c759;
}
.toggle-thumb {
position: absolute;
top: 2px;
left: 2px;
width: 16px;
height: 16px;
border-radius: 50%;
background: white;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
transition: transform 200ms ease;
}
.snippet-toggle.on .toggle-thumb {
transform: translateX(16px);
}
</style>

View File

@@ -1,4 +1,3 @@
import type { SHA512_256 } from '@oslojs/crypto/sha2';
import type { Guess } from './game';
export function getVerseSnippet(verseText: string): string {
@@ -16,8 +15,8 @@ export function getVerseSnippet(verseText: string): string {
return pos;
}
const start = posAfterWord(10);
const end = posAfterWord(18);
const start = posAfterWord(9);
const end = posAfterWord(25);
// Find first punctuation mark between words 10 and 25
const range = text.substring(start, end);

View File

@@ -319,6 +319,7 @@
reference={dailyVerse.reference}
onChapterGuessCompleted={persistence.onChapterGuessCompleted}
shareText={getShareText()}
verseText={dailyVerse.verseText}
{streak}
{streakPercentile}
/>