mirror of
https://github.com/SoPat712/maisie-heardle.git
synced 2025-08-21 18:28:45 -04:00
Better colors, better playback, version bump
This commit is contained in:
@@ -158,6 +158,7 @@
|
|||||||
let iframeElement: HTMLIFrameElement;
|
let iframeElement: HTMLIFrameElement;
|
||||||
let widget: any;
|
let widget: any;
|
||||||
let widgetReady = false;
|
let widgetReady = false;
|
||||||
|
let loading = true; // ← disable play until preload
|
||||||
let artworkUrl = '';
|
let artworkUrl = '';
|
||||||
let isPlaying = false;
|
let isPlaying = false;
|
||||||
let currentPosition = 0;
|
let currentPosition = 0;
|
||||||
@@ -190,7 +191,7 @@
|
|||||||
timeLeft = `${h}:${m}:${s}`;
|
timeLeft = `${h}:${m}:${s}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── CLAMPED FILL PERCENT & NEXT SEGMENT ─────────────────────────────────────
|
// ─── FILL % & NEXT SEGMENT ───────────────────────────────────────────────────
|
||||||
let fillPercent = 0;
|
let fillPercent = 0;
|
||||||
$: {
|
$: {
|
||||||
const raw = gameOver
|
const raw = gameOver
|
||||||
@@ -224,22 +225,26 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
// dark‑mode listener
|
|
||||||
window
|
window
|
||||||
.matchMedia('(prefers-color-scheme: dark)')
|
.matchMedia('(prefers-color-scheme: dark)')
|
||||||
.addEventListener('change', (e) => (darkMode = e.matches));
|
.addEventListener('change', (e) => (darkMode = e.matches));
|
||||||
// countdown
|
|
||||||
updateTime();
|
updateTime();
|
||||||
countdownInterval = setInterval(updateTime, 1000);
|
countdownInterval = setInterval(updateTime, 1000);
|
||||||
// SoundCloud widget
|
|
||||||
widget = SC.Widget(iframeElement);
|
widget = SC.Widget(iframeElement);
|
||||||
widget.bind(SC.Widget.Events.READY, () => {
|
widget.bind(SC.Widget.Events.READY, () => {
|
||||||
widgetReady = true;
|
|
||||||
widget.getDuration((d: number) => (fullDuration = d));
|
widget.getDuration((d: number) => (fullDuration = d));
|
||||||
widget.getCurrentSound((sound: any) => {
|
widget.getCurrentSound((sound: any) => {
|
||||||
artworkUrl = sound.artwork_url || '';
|
artworkUrl = sound.artwork_url || '';
|
||||||
});
|
});
|
||||||
|
// preload silently:
|
||||||
|
widget.play();
|
||||||
|
widget.pause();
|
||||||
|
widget.seekTo(0);
|
||||||
|
loading = false;
|
||||||
|
widgetReady = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
widget.bind(SC.Widget.Events.PLAY, () => {
|
widget.bind(SC.Widget.Events.PLAY, () => {
|
||||||
startPolling();
|
startPolling();
|
||||||
if (!gameOver) {
|
if (!gameOver) {
|
||||||
@@ -275,21 +280,17 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
function playSegment() {
|
function playSegment() {
|
||||||
if (!widgetReady) return;
|
if (!widgetReady || loading) return;
|
||||||
currentPosition = 0;
|
currentPosition = 0;
|
||||||
widget.seekTo(0);
|
widget.seekTo(0);
|
||||||
widget.play();
|
widget.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
function togglePlayPause() {
|
function togglePlayPause() {
|
||||||
if (!widgetReady) return;
|
if (!widgetReady || loading) return;
|
||||||
isPlaying ? widget.pause() : playSegment();
|
isPlaying ? widget.pause() : playSegment();
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleDark() {
|
|
||||||
darkMode = !darkMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
function skipIntro() {
|
function skipIntro() {
|
||||||
if (!widgetReady || gameOver) return;
|
if (!widgetReady || gameOver) return;
|
||||||
attemptInfos = [...attemptInfos, { status: 'skip' }];
|
attemptInfos = [...attemptInfos, { status: 'skip' }];
|
||||||
@@ -301,8 +302,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function submitGuess() {
|
function submitGuess() {
|
||||||
if (!widgetReady || gameOver || !userInput) return;
|
if (!widgetReady || gameOver) return;
|
||||||
// auto-select if none chosen
|
|
||||||
if (!selectedTrack && suggestions.length) {
|
if (!selectedTrack && suggestions.length) {
|
||||||
selectedTrack =
|
selectedTrack =
|
||||||
suggestions.find((t) => t.title.toLowerCase() === userInput.toLowerCase()) ||
|
suggestions.find((t) => t.title.toLowerCase() === userInput.toLowerCase()) ||
|
||||||
@@ -312,13 +312,17 @@
|
|||||||
|
|
||||||
attemptCount++;
|
attemptCount++;
|
||||||
const ans = currentTrack.title.toLowerCase();
|
const ans = currentTrack.title.toLowerCase();
|
||||||
if (selectedTrack!.title.toLowerCase() === ans) {
|
if (selectedTrack.title.toLowerCase() === ans) {
|
||||||
attemptInfos = [...attemptInfos, { status: 'correct', title: currentTrack.title }];
|
attemptInfos = [...attemptInfos, { status: 'correct', title: currentTrack.title }];
|
||||||
gameOver = true;
|
gameOver = true;
|
||||||
message = `✅ Correct! It was “${currentTrack.title}.” You got it in ${attemptCount} ${attemptCount === 1 ? 'try' : 'tries'}.`;
|
message = `✅ Correct! It was “${currentTrack.title}.” You ${
|
||||||
|
attemptCount === maxAttempts
|
||||||
|
? 'nailed it on the last try!'
|
||||||
|
: `got it in ${attemptCount} ${attemptCount === 1 ? 'try' : 'tries'}.`
|
||||||
|
}`;
|
||||||
widget.pause();
|
widget.pause();
|
||||||
} else {
|
} else {
|
||||||
attemptInfos = [...attemptInfos, { status: 'wrong', title: selectedTrack!.title }];
|
attemptInfos = [...attemptInfos, { status: 'wrong', title: selectedTrack.title }];
|
||||||
userInput = '';
|
userInput = '';
|
||||||
selectedTrack = null;
|
selectedTrack = null;
|
||||||
if (attemptCount >= maxAttempts) revealAnswer();
|
if (attemptCount >= maxAttempts) revealAnswer();
|
||||||
@@ -345,7 +349,6 @@
|
|||||||
inputEl.blur();
|
inputEl.blur();
|
||||||
}
|
}
|
||||||
|
|
||||||
// update suggestions reactively, hide once a track is selected
|
|
||||||
$: suggestions =
|
$: suggestions =
|
||||||
userInput && !selectedTrack
|
userInput && !selectedTrack
|
||||||
? tracks.filter((t) => t.title.toLowerCase().includes(userInput.toLowerCase())).slice(0, 5)
|
? tracks.filter((t) => t.title.toLowerCase().includes(userInput.toLowerCase())).slice(0, 5)
|
||||||
@@ -402,7 +405,7 @@
|
|||||||
<p class="text-xs" style="color:{COLORS.accent}">
|
<p class="text-xs" style="color:{COLORS.accent}">
|
||||||
Prepared with SoundCloud, Svelte, Tailwind CSS, Inter font, svelte-hero-icons, and moment.js
|
Prepared with SoundCloud, Svelte, Tailwind CSS, Inter font, svelte-hero-icons, and moment.js
|
||||||
<br /><br />
|
<br /><br />
|
||||||
Game version: 2.0.0
|
Game version: 2.1.0
|
||||||
</p>
|
</p>
|
||||||
<p class="text-sm italic">New track in <strong>{timeLeft}</strong></p>
|
<p class="text-sm italic">New track in <strong>{timeLeft}</strong></p>
|
||||||
<button
|
<button
|
||||||
@@ -422,9 +425,10 @@
|
|||||||
<!-- Main UI -->
|
<!-- Main UI -->
|
||||||
<div
|
<div
|
||||||
class="fixed inset-0 flex flex-col overflow-hidden"
|
class="fixed inset-0 flex flex-col overflow-hidden"
|
||||||
style="background:{darkMode ? COLORS.text : COLORS.background};color:{darkMode
|
style="
|
||||||
? COLORS.background
|
background: {darkMode ? COLORS.text : COLORS.background};
|
||||||
: COLORS.text}"
|
color: {darkMode ? COLORS.background : COLORS.text}
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<div class="flex items-center justify-between px-4 pt-4">
|
<div class="flex items-center justify-between px-4 pt-4">
|
||||||
@@ -452,15 +456,18 @@
|
|||||||
{#each attemptInfos as info}
|
{#each attemptInfos as info}
|
||||||
<div
|
<div
|
||||||
class="flex h-12 items-center rounded border px-3 font-semibold"
|
class="flex h-12 items-center rounded border px-3 font-semibold"
|
||||||
style="border-color:{info.status === 'skip'
|
style="
|
||||||
|
border-color: {info.status === 'skip'
|
||||||
? COLORS.primary
|
? COLORS.primary
|
||||||
: info.status === 'wrong'
|
: info.status === 'wrong'
|
||||||
? COLORS.accent
|
? COLORS.accent
|
||||||
: COLORS.secondary};color:{info.status === 'skip'
|
: COLORS.secondary};
|
||||||
|
color: {info.status === 'skip'
|
||||||
? COLORS.primary
|
? COLORS.primary
|
||||||
: info.status === 'wrong'
|
: info.status === 'wrong'
|
||||||
? COLORS.accent
|
? COLORS.accent
|
||||||
: COLORS.secondary}"
|
: COLORS.secondary}
|
||||||
|
"
|
||||||
>
|
>
|
||||||
{#if info.status === 'skip'}▢ Skipped
|
{#if info.status === 'skip'}▢ Skipped
|
||||||
{:else if info.status === 'wrong'}☒ {info.title}
|
{:else if info.status === 'wrong'}☒ {info.title}
|
||||||
@@ -496,7 +503,9 @@
|
|||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="px-4 py-2">
|
<div class="px-4 py-2">
|
||||||
<div class="font-semibold" style="color:{COLORS.primary}">{currentTrack.title}</div>
|
<div class="font-semibold" style="color:{COLORS.primary}">
|
||||||
|
{currentTrack.title}
|
||||||
|
</div>
|
||||||
<div class="text-sm" style="color:{COLORS.accent}">{ARTIST_NAME}</div>
|
<div class="text-sm" style="color:{COLORS.accent}">{ARTIST_NAME}</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
@@ -544,9 +553,14 @@
|
|||||||
<button
|
<button
|
||||||
on:click={togglePlayPause}
|
on:click={togglePlayPause}
|
||||||
class="flex h-16 w-16 items-center justify-center rounded-full border-2 disabled:opacity-50"
|
class="flex h-16 w-16 items-center justify-center rounded-full border-2 disabled:opacity-50"
|
||||||
style="border-color:{COLORS.accent}"
|
style="border-color:{loading ? '#888888' : COLORS.accent}"
|
||||||
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<Icon src={isPlaying ? Pause : Play} class="h-8 w-8" style="color:{COLORS.accent}" />
|
<Icon
|
||||||
|
src={isPlaying ? Pause : Play}
|
||||||
|
class="h-8 w-8"
|
||||||
|
style="color:{loading ? '#888888' : COLORS.accent}"
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -559,24 +573,21 @@
|
|||||||
placeholder="Type song title…"
|
placeholder="Type song title…"
|
||||||
bind:value={userInput}
|
bind:value={userInput}
|
||||||
on:keydown={onInputKeydown}
|
on:keydown={onInputKeydown}
|
||||||
on:focus={() => {
|
on:focus={() => (selectedTrack = null)}
|
||||||
selectedTrack = null;
|
|
||||||
}}
|
|
||||||
class="w-full rounded border px-3 py-2"
|
class="w-full rounded border px-3 py-2"
|
||||||
style="border-color:{COLORS.primary};background:{darkMode
|
style="
|
||||||
? COLORS.text
|
border-color:{COLORS.primary};
|
||||||
: COLORS.background};color:{darkMode ? COLORS.background : COLORS.text}"
|
background: {darkMode ? COLORS.text : COLORS.background};
|
||||||
|
color: {darkMode ? COLORS.background : COLORS.text}
|
||||||
|
"
|
||||||
/>
|
/>
|
||||||
{#if suggestions.length}
|
{#if suggestions.length}
|
||||||
<ul
|
<ul
|
||||||
class="
|
class="absolute bottom-full left-0 z-10 mb-1 max-h-36 w-full overflow-y-auto rounded border"
|
||||||
absolute bottom-full left-0 z-10 mb-1
|
|
||||||
max-h-36 w-full overflow-y-auto rounded border
|
|
||||||
"
|
|
||||||
style="
|
style="
|
||||||
border-color: {darkMode ? COLORS.background : COLORS.text};
|
border-color: {darkMode ? COLORS.background : COLORS.text};
|
||||||
background: {darkMode ? COLORS.text : COLORS.background}
|
background: {darkMode ? COLORS.text : COLORS.background}
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{#each suggestions as s}
|
{#each suggestions as s}
|
||||||
<li>
|
<li>
|
||||||
@@ -619,5 +630,5 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* Tailwind in app.css handles all spacing/layout */
|
/* Tailwind in app.css handles spacing/layout */
|
||||||
</style>
|
</style>
|
||||||
|
Reference in New Issue
Block a user