stop won boards showing "null" on the website

A won board has no answer row, and passing that null straight to
replaceChildren printed it as the text "null" under the board. Add a
fill() helper that skips null children like h() does and use it on the
board page. Bump the asset version so browsers load the new wordle.js
alongside the new board.js.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adamandClaude Opus 5.5 committed 2026-09-29 21:27:10 +00:00
1 parent fc3c74822f
commit f278ab0ac1
9 files changed
+23 -16

No files matched your search

+5 -5
View File
@@ -1,8 +1,8 @@
import {
h, icon, tile, bigBoard, emptyState, skeleton, toast, copyText, confetti, mountShell,
h, fill, icon, tile, bigBoard, emptyState, skeleton, toast, copyText, confetti, mountShell,
profileHeader, parseBoardName, boardPage, historyPage, getBoard, getLastBoard, findGame, today,
formatDay, resultText, shareText,
} from "./wordle.js?v=2";
} from "./wordle.js?v=3";
mountShell();
const main = document.getElementById("main");
@@ -30,14 +30,14 @@ async function show(user, day) {
? await findGame(user, today(), -1) ?? await getLastBoard(user)
: await getBoard(user, day);
} catch {
stage.replaceChildren(h("h2", {}, "Couldn't load the board"), h("p", {}, "Check your connection and try again."),
fill(stage, h("h2", {}, "Couldn't load the board"), h("p", {}, "Check your connection and try again."),
h("button", { class: "btn btn-primary", type: "button", onclick: () => location.reload() }, "Retry"));
return;
}
if (!board) {
const when = day == null ? "any games" : `a game on ${formatDay(day)}`;
stage.replaceChildren(
fill(stage,
h("h2", {}, `No board for ${user}`),
h("p", { style: { color: "var(--muted)", margin: "0" } }, `Couldn't find ${when}.`),
day == null ? null : navRow(user, day),
@@ -59,7 +59,7 @@ async function show(user, day) {
h("span", {}, "The word was"),
[...board.answer].map(letter => tile(letter, "correct")));
stage.replaceChildren(
fill(stage,
h("div", { class: "headline" },
h("span", { class: board.won ? "badge win" : "badge loss", style: { "font-size": "0.95rem", padding: "6px 14px" } },
board.won ? `Solved in ${resultText(board)}` : `Missed it - ${resultText(board)}`)),
+2 -2
View File
@@ -8,7 +8,7 @@
<meta name="color-scheme" content="dark light">
<link rel="icon" type="image/svg+xml" href="/wordle/favicon.svg">
<link rel="alternate icon" href="/wordle/favicon.ico">
<link rel="stylesheet" href="/wordle/wordle.css?v=2">
<link rel="stylesheet" href="/wordle/wordle.css?v=3">
<script>
// Apply the saved theme before the page draws
try {
@@ -18,7 +18,7 @@
if (s.contrast) document.documentElement.dataset.contrast = "high";
} catch (e) {}
</script>
<script type="module" src="/wordle/board.js?v=2"></script>
<script type="module" src="/wordle/board.js?v=3"></script>
</head>
<body>
<main id="main" class="container">
+2 -2
View File
@@ -8,7 +8,7 @@
<meta name="color-scheme" content="dark light">
<link rel="icon" type="image/svg+xml" href="/wordle/favicon.svg">
<link rel="alternate icon" href="/wordle/favicon.ico">
<link rel="stylesheet" href="/wordle/wordle.css?v=2">
<link rel="stylesheet" href="/wordle/wordle.css?v=3">
<script>
// Apply the saved theme before the page draws
try {
@@ -18,7 +18,7 @@
if (s.contrast) document.documentElement.dataset.contrast = "high";
} catch (e) {}
</script>
<script type="module" src="/wordle/history.js?v=2"></script>
<script type="module" src="/wordle/history.js?v=3"></script>
</head>
<body>
<main id="main" class="container">
+1 -1
View File
@@ -1,7 +1,7 @@
import {
h, icon, miniBoard, emptyState, skeleton, mountShell, profileHeader, normalizeUser, boardPage,
getHistory, today, formatDay, relativeDay, weekdayIndex, resultText,
} from "./wordle.js?v=2";
} from "./wordle.js?v=3";
mountShell();
const main = document.getElementById("main");
+1 -1
View File
@@ -2,7 +2,7 @@ import {
SSH_COMMAND, h, icon, tile, avatar, miniBoard, emptyState, skeleton, toast, copyText, countdown,
mountShell, normalizeUser, statsPage, boardPage, following, setFollowing, recentSearches,
addRecentSearch, getStats, getBoard, today, resultText, score, sleep, reducedMotion,
} from "./wordle.js?v=2";
} from "./wordle.js?v=3";
mountShell({ active: "home" });
const main = document.getElementById("main");
+2 -2
View File
@@ -8,7 +8,7 @@
<meta name="color-scheme" content="dark light">
<link rel="icon" type="image/svg+xml" href="/wordle/favicon.svg">
<link rel="alternate icon" href="/wordle/favicon.ico">
<link rel="stylesheet" href="/wordle/wordle.css?v=2">
<link rel="stylesheet" href="/wordle/wordle.css?v=3">
<script>
// Apply the saved theme before the page draws
try {
@@ -18,7 +18,7 @@
if (s.contrast) document.documentElement.dataset.contrast = "high";
} catch (e) {}
</script>
<script type="module" src="/wordle/home.js?v=2"></script>
<script type="module" src="/wordle/home.js?v=3"></script>
</head>
<body>
<main id="main" class="container">
+2 -2
View File
@@ -8,7 +8,7 @@
<meta name="color-scheme" content="dark light">
<link rel="icon" type="image/svg+xml" href="/wordle/favicon.svg">
<link rel="alternate icon" href="/wordle/favicon.ico">
<link rel="stylesheet" href="/wordle/wordle.css?v=2">
<link rel="stylesheet" href="/wordle/wordle.css?v=3">
<script>
// Apply the saved theme before the page draws
try {
@@ -18,7 +18,7 @@
if (s.contrast) document.documentElement.dataset.contrast = "high";
} catch (e) {}
</script>
<script type="module" src="/wordle/stats.js?v=2"></script>
<script type="module" src="/wordle/stats.js?v=3"></script>
</head>
<body>
<main id="main" class="container">
+1 -1
View File
@@ -2,7 +2,7 @@ import {
h, icon, miniBoard, emptyState, skeleton, toast, copyText, countUp, countdown, mountShell,
profileHeader, normalizeUser, statsPage, boardPage, getStats, getHistory, today, formatDay,
relativeDay, resultText, describeBoard,
} from "./wordle.js?v=2";
} from "./wordle.js?v=3";
mountShell();
const main = document.getElementById("main");
+7
View File
@@ -27,6 +27,13 @@ export function h(tag, props = {}, ...children) {
return el;
}
// Replace an element's children, skipping null/false like h() does
// (replaceChildren on its own would show them as the text "null")
export function fill(el, ...children) {
el.replaceChildren(...children.flat(Infinity).filter(child => child != null && child !== false));
return el;
}
const ICONS = {
search: '<circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/>',
gear: '<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z"/>',