Add the new Grinchmas page (previous commit only captured deletions)
deploy / deploy (push) Successful in 5s

The prior commit's git add errored on an already-removed pathspec and
silently skipped every other file — this is the rest of that change:
content/books/grinchmas.md (real page, no longer draft-only),
layouts/books/single.html, layouts/partials/arc-redeem-form.html,
hugo.toml's bookshop_base_url-driven form target, and the homepage/nav
links pointing at /books/grinchmas/.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-04 20:34:22 -04:00
parent c82de9baad
commit 768ef5ccd3
5 changed files with 86 additions and 3 deletions
+1 -1
View File
@@ -5,5 +5,5 @@ description: "TODO: one-line description of Thistle & Moth"
TODO: Thistle & Moth homepage copy goes here. TODO: Thistle & Moth homepage copy goes here.
Get a free story: [download the reader magnet](/gift). Writers: see our Get a free story: [download the reader magnet](/books/grinchmas/). Writers: see our
[submission guidelines](/submissions). [submission guidelines](/submissions).
+12 -1
View File
@@ -3,5 +3,16 @@ title: "A Hallmark Grinchmas"
author: "Marisol T. S. Kuhn" author: "Marisol T. S. Kuhn"
cover_image: "https://downloads.thistleandmoth.org/grinchmas/grinchmas-cover.png" cover_image: "https://downloads.thistleandmoth.org/grinchmas/grinchmas-cover.png"
description: "California native Bart Marley unexpectedly finds himself in the, to its mind perfect, midwestern town of Hallmark. One child refuses to give up on the stranger but is her innocence the Christmas miracle Bart needs?" description: "California native Bart Marley unexpectedly finds himself in the, to its mind perfect, midwestern town of Hallmark. One child refuses to give up on the stranger but is her innocence the Christmas miracle Bart needs?"
draft: true
# Label on the signup form's submit button.
cta_text: "Send it to me"
# Code of the bookshop ARC campaign this form redeems (see
# reground-tools/arc-campaign.sh) — thistleandmoth.org/shop/arc/<arc_code>.
arc_code: "grinchmas"
--- ---
California native Bart Marley unexpectedly finds himself in the, to its
mind perfect, midwestern town of Hallmark. One child refuses to give up
on the stranger but is her innocence the Christmas miracle Bart needs?
Get *A Hallmark Grinchmas* free — enter your email below.
+1 -1
View File
@@ -32,7 +32,7 @@ disableKinds = ["taxonomy", "term"]
[[menu.main]] [[menu.main]]
name = "Free Book" name = "Free Book"
url = "/free-book/" url = "/books/grinchmas/"
weight = 30 weight = 30
[[menu.main]] [[menu.main]]
+11
View File
@@ -0,0 +1,11 @@
{{ define "main" }}
<section class="book-hero">
<h1>{{ .Title }}</h1>
{{ with .Params.cover_image }}<img class="book-cover" src="{{ . }}" alt="{{ $.Title }} cover">{{ end }}
{{ with .Params.hero_subhead }}<p class="book-subhead">{{ . }}</p>{{ end }}
{{ .Content }}
{{ partial "arc-redeem-form.html" (dict "id" "top" "page" .) }}
</section>
{{ end }}
+61
View File
@@ -0,0 +1,61 @@
{{ $id := .id }}
{{ $page := .page }}
<form id="arc-form-{{ $id }}" class="enroll-form">
<label for="arc-email-{{ $id }}">Email</label>
<input type="email" id="arc-email-{{ $id }}" name="email" required autocomplete="email" placeholder="you@example.com">
<div class="field-honeypot" aria-hidden="true">
<label for="arc-website-{{ $id }}">Leave this field empty</label>
<input type="text" id="arc-website-{{ $id }}" name="website" tabindex="-1" autocomplete="off">
</div>
<p class="field-subscribe">
<label><input type="checkbox" id="arc-subscribe-{{ $id }}" name="subscribe" value="1"> Keep me posted on new releases and giveaways</label>
</p>
<button type="submit" class="btn">{{ $page.Params.cta_text | default "Send it to me" }}</button>
</form>
<p id="arc-status-{{ $id }}" role="status" class="enroll-status"></p>
<script>
(function () {
var form = document.getElementById("arc-form-{{ $id }}");
var status = document.getElementById("arc-status-{{ $id }}");
var arcURL = {{ $page.Site.Params.bookshop_base_url }} + "/arc/" + {{ $page.Params.arc_code }};
form.addEventListener("submit", function (e) {
e.preventDefault();
if (form.website.value) return; // honeypot
var submitBtn = form.querySelector("button[type=submit]");
submitBtn.disabled = true;
status.textContent = "Sending…";
var body = new URLSearchParams();
body.set("email", form.email.value);
if (form.subscribe.checked) body.set("subscribe", "1");
fetch(arcURL, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: body.toString()
}).then(function (res) {
if (res.ok) {
form.reset();
form.hidden = true;
status.textContent = "Check your email — it's on its way.";
return;
}
submitBtn.disabled = false;
if (res.status === 400) {
status.textContent = "That doesn't look like a valid email address.";
} else if (res.status === 429) {
status.textContent = "Too many attempts — try again in a minute.";
} else if (res.status === 410) {
status.textContent = "This giveaway has ended.";
} else {
status.textContent = "Something went wrong. Try again in a moment.";
}
}).catch(function () {
submitBtn.disabled = false;
status.textContent = "Something went wrong. Try again in a moment.";
});
});
})();
</script>