From fe5649dc2d56a3b763a65f7fbff474ae4bd8fa88 Mon Sep 17 00:00:00 2001 From: Zakaria Date: Wed, 13 May 2026 11:24:27 -0400 Subject: [PATCH] Update Version (Beta): login + leaderboard/ word definition --- CSS/styles.css | 39 +++++++++++-------- README.md | 2 +- fancy-wordle-modern.html | 6 +-- index.html | 6 +-- script.js | 81 ++++++++++++++-------------------------- supabase/schema.sql | 33 +--------------- 6 files changed, 60 insertions(+), 107 deletions(-) diff --git a/CSS/styles.css b/CSS/styles.css index 839ff1f..13775d2 100644 --- a/CSS/styles.css +++ b/CSS/styles.css @@ -462,43 +462,52 @@ h2 { line-height: 1.5; } -.history-panel { +.definition-panel { display: grid; gap: 10px; margin-bottom: 22px; } -.history-panel h3 { +.definition-panel h3 { margin: 0; font-family: var(--font-display); font-size: 1.15rem; font-weight: 500; } -.history-list { - display: grid; - gap: 8px; -} - -.history-row { - display: grid; - grid-template-columns: 1fr auto; - gap: 12px; - padding: 10px 12px; +.stats-definition { + padding: 14px; border: 1px solid var(--border); border-radius: 14px; background: var(--bg); + color: var(--muted); + line-height: 1.55; + text-align: start; } -.history-word { +.stats-definition strong { + display: block; + margin-bottom: 6px; + color: var(--fg); + font-family: var(--font-display); + font-size: 1.35rem; + font-weight: 500; + line-height: 1.1; +} + +.stats-definition .word-label { + font-family: var(--font-body); + font-size: 0.76rem; font-weight: 900; letter-spacing: 0.08em; text-transform: uppercase; } -.history-meta { +.stats-definition em { + display: block; + margin-top: 10px; color: var(--muted); - font-size: 0.84rem; + font-style: normal; } .leaderboard-card { diff --git a/README.md b/README.md index 391880f..654d2f1 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ The database chooses the word from `public.wordle_words` based on the current UT The hourly leaderboard uses completed authenticated rounds for the current UTC hour. It ranks wins first, then fewer guesses, then earliest completion time. -Leaderboard tabs include this hour, today, and all time. Signed-in users are included even if their row falls outside the top 25. Stats also show recent personal history and this hour's average score summary. +Leaderboard tabs include this hour, today, and all time. Signed-in users are included even if their row falls outside the top 25. Stats also show the current revealed word definition and this hour's average score summary. `supabase/seed-word-data.sql` is generated from `targetWords.json` and `dictionary.json`: diff --git a/fancy-wordle-modern.html b/fancy-wordle-modern.html index 90e8452..b957108 100644 --- a/fancy-wordle-modern.html +++ b/fancy-wordle-modern.html @@ -72,9 +72,9 @@
-
-

Recent history

-
+
+

Word reveal

+
diff --git a/index.html b/index.html index 90e8452..b957108 100644 --- a/index.html +++ b/index.html @@ -72,9 +72,9 @@
-
-

Recent history

-
+
+

Word reveal

+
diff --git a/script.js b/script.js index 165d3f8..ac6e3a1 100644 --- a/script.js +++ b/script.js @@ -16,6 +16,7 @@ let authSession = null let authProfile = null let leaderboardScope = "hour" let latestLeaderboardRows = [] +let lastDefinition = null const WORD_LENGTH = 5 const MAX_GUESSES = 6 @@ -96,7 +97,7 @@ const statsModal = document.getElementById("stats-modal") const statsGrid = document.getElementById("stats-grid") const statsNote = document.getElementById("stats-note") const guessBars = document.getElementById("guess-bars") -const historyList = document.getElementById("history-list") +const statsDefinition = document.getElementById("stats-definition") const resetStatsButton = document.getElementById("reset-stats") const shareResultsButton = document.getElementById("share-results") @@ -419,6 +420,7 @@ function applyHourlyRound(round) { guesses: round.guessCount || MAX_GUESSES, word: round.word || "" } + if (round.word) loadWordDefinition(round.word, Boolean(round.won)) lockUntilNextWord() return } @@ -1123,6 +1125,11 @@ function playCelebrationSound() { } async function showWordDefinition(word, isWin = true) { + const definition = await loadWordDefinition(word, isWin) + showDefinitionAlert(definition) +} + +async function loadWordDefinition(word, isWin = true) { try { const response = await fetch(`https://api.dictionaryapi.dev/api/v2/entries/en/${word}`) if (!response.ok) throw new Error(`API request failed: ${response.status}`) @@ -1135,20 +1142,23 @@ async function showWordDefinition(word, isWin = true) { if (!definition) throw new Error("No definition found") - showDefinitionAlert({ + lastDefinition = { title: `${word.toUpperCase()} ${partOfSpeech ? `(${partOfSpeech})` : ""}`, body: definition, example, isWin - }) + } } catch (error) { console.info("Definition lookup unavailable:", error) - showDefinitionAlert({ + lastDefinition = { title: word.toUpperCase(), body: "Definition not available at the moment.", isWin - }) + } } + + renderStatsDefinition() + return lastDefinition } function showDefinitionAlert({ title, body, example, isWin }) { @@ -1308,7 +1318,7 @@ async function renderStats() { .join("") renderStatsNote(summary) - await renderHistory() + renderStatsDefinition() } function renderStatsNote(summary) { @@ -1372,60 +1382,25 @@ async function getHourlySummary() { } } -async function renderHistory() { - if (!historyList) return +function renderStatsDefinition() { + if (!statsDefinition) return - if (hourlyRound?.backend !== "supabase") { - historyList.innerHTML = '
Sign in to keep a cross-device history.
' + if (!lastResult) { + statsDefinition.innerHTML = "Finish this hour's word to reveal its definition here." return } - const rows = await getPlayerHistory() - if (rows.length === 0) { - historyList.innerHTML = '
No completed rounds yet.
' + if (!lastDefinition) { + statsDefinition.innerHTML = "Loading definition..." return } - historyList.innerHTML = rows - .map(row => ` -
- - ${escapeHtml(row.word)} - ${formatHistoryHour(row.hourStart)} - - ${row.won ? `${row.guessCount}/6` : "X/6"} -
- `) - .join("") -} - -async function getPlayerHistory() { - const client = getSupabaseClient() - if (!client || !authSession) return [] - - const { data, error } = await client.rpc("get_player_history", { history_limit: 8 }) - if (error) { - console.warn("Failed to load history:", error) - return [] - } - - return (Array.isArray(data) ? data : []).map(row => ({ - hourStart: row.hour_start, - word: row.word || "-----", - won: Boolean(row.won), - guessCount: row.guess_count || MAX_GUESSES, - completedAt: row.completed_at - })) -} - -function formatHistoryHour(value) { - if (!value) return "" - - return new Intl.DateTimeFormat(undefined, { - month: "short", - day: "numeric", - hour: "numeric" - }).format(new Date(value)) + statsDefinition.innerHTML = ` + ${lastResult.won ? "Solved word" : "Answer"} + ${escapeHtml(lastDefinition.title)} + ${escapeHtml(lastDefinition.body)} + ${lastDefinition.example ? `Example: ${escapeHtml(lastDefinition.example)}` : ""} + ` } function renderLeaderboardLoading() { diff --git a/supabase/schema.sql b/supabase/schema.sql index ae71c01..3c7b3ba 100644 --- a/supabase/schema.sql +++ b/supabase/schema.sql @@ -674,37 +674,7 @@ begin end; $$; -create or replace function public.get_player_history(history_limit integer default 10) -returns table ( - hour_start timestamptz, - word text, - won boolean, - guess_count integer, - completed_at timestamptz -) -language plpgsql -security definer -set search_path = public -as $$ -begin - if auth.uid() is null then - raise exception 'Authentication required'; - end if; - - return query - select - rounds.hour_start, - rounds.word, - rounds.won, - rounds.guess_count, - rounds.completed_at - from public.wordle_rounds rounds - where rounds.user_id = auth.uid() - and rounds.completed_at is not null - order by rounds.hour_start desc - limit greatest(1, least(coalesce(history_limit, 10), 25)); -end; -$$; +drop function if exists public.get_player_history(integer); create or replace function public.get_hourly_summary() returns table ( @@ -760,6 +730,5 @@ grant execute on function public.submit_guess(uuid, text) to authenticated; grant execute on function public.get_user_stats() to authenticated; grant execute on function public.get_hourly_leaderboard() to anon, authenticated; grant execute on function public.get_leaderboard(text) to anon, authenticated; -grant execute on function public.get_player_history(integer) to authenticated; grant execute on function public.get_hourly_summary() to anon, authenticated; grant execute on function public.complete_hourly_round(uuid, boolean, integer) to authenticated;