The classes that were being written and thrown away

A sweep for the bug behind the homepage titles found five more of it, because
the mistake is easy and silent: put a class on the tag you write a th:replace
on, and Thymeleaf hands you back the fragment with its own class attribute and
drops yours. Nothing warns, and the page looks nearly right.

  catering  the divider's mt-10, so the branch mark sat on the paragraph above it
  contact   mt-4 under both "Our hours" and "Find us" — the same flush headings
            the homepage had
  footer    mt-4 between the address and the hours under it
  home      text-bakery-800 on the address, which is why "Find us" rendered a
            shade darker (bakery-900, inherited from body) than "Our hours" in
            the panel beside it

Fixed where the fragments already said it should be: "both fragments take the
classes that vary by where they sit". They now take two — the element's own
class as well as the row's or the link's — so the caller has somewhere to put
this that survives. `divider` takes its spacing the same way.

A class on a th:replace tag now has no reason to exist anywhere in the
templates, and there are none left.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
2026-07-26 22:13:05 -05:00
co-authored by Claude Opus 5
parent 5aa2e4589e
commit 68f1ec5961
6 changed files with 17 additions and 15 deletions
+1 -1
View File
@@ -17,7 +17,7 @@
mind, and we will bake to it. mind, and we will bake to it.
</p> </p>
<div class="mt-10" th:replace="~{fragments/opening :: divider}"></div> <div th:replace="~{fragments/opening :: divider('mt-10')}"></div>
<div class="mt-12 max-w-6xl mx-auto space-y-16 md:space-y-20"> <div class="mt-12 max-w-6xl mx-auto space-y-16 md:space-y-20">
+2 -4
View File
@@ -81,13 +81,11 @@
<aside class="space-y-6"> <aside class="space-y-6">
<div class="panel p-6 md:p-8"> <div class="panel p-6 md:p-8">
<h2 class="h4 text-bakery-900">Our hours</h2> <h2 class="h4 text-bakery-900">Our hours</h2>
<div class="mt-4 text-bakery-800" <div th:replace="~{fragments/visit :: hours('mt-4', 'text-bakery-800')}"></div>
th:replace="~{fragments/visit :: hours('text-bakery-800')}"></div>
</div> </div>
<div class="panel p-6 md:p-8"> <div class="panel p-6 md:p-8">
<h2 class="h4 text-bakery-900">Find us</h2> <h2 class="h4 text-bakery-900">Find us</h2>
<div class="mt-4 text-bakery-800" <div th:replace="~{fragments/visit :: address('mt-4 text-bakery-800', 'link-plain')}"></div>
th:replace="~{fragments/visit :: address('link-plain')}"></div>
</div> </div>
<div class="panel-quiet p-6 md:p-8"> <div class="panel-quiet p-6 md:p-8">
<h2 class="h4 text-bakery-900">Ordering for a crowd?</h2> <h2 class="h4 text-bakery-900">Ordering for a crowd?</h2>
@@ -20,11 +20,10 @@
<div> <div>
<h3 class="label text-bakery-300 mb-4 font-adbhashitha">Visit</h3> <h3 class="label text-bakery-300 mb-4 font-adbhashitha">Visit</h3>
<div th:replace="~{fragments/visit :: address('link-on-dark')}"></div> <div th:replace="~{fragments/visit :: address('', 'link-on-dark')}"></div>
<!--/* The hours are the thing people come to a bakery's site for, and the footer is on every <!--/* The hours are the thing people come to a bakery's site for, and the footer is on every
page. */--> page. */-->
<div class="mt-4 text-sm text-bakery-200" <div th:replace="~{fragments/visit :: hours('mt-4', 'text-sm text-bakery-200')}"></div>
th:replace="~{fragments/visit :: hours('text-sm text-bakery-200')}"></div>
</div> </div>
</div> </div>
@@ -54,8 +54,9 @@
<p th:if="${!#strings.isEmpty(blurb)}" class="mt-3 text-bakery-100 leading-relaxed" th:text="${blurb}">A line.</p> <p th:if="${!#strings.isEmpty(blurb)}" class="mt-3 text-bakery-100 leading-relaxed" th:text="${blurb}">A line.</p>
</div> </div>
<!--/* The branch from the wordmark, between one part of a page and the next. */--> <!--/* The branch from the wordmark, between one part of a page and the next. Takes its own spacing,
<div th:fragment="divider" class="flex justify-center" aria-hidden="true"> because the tag a caller writes the th:replace on is discarded along with any class on it. */-->
<div th:fragment="divider(className)" th:class="'flex justify-center ' + ${className}" aria-hidden="true">
<span class="mark mark-r w-12 h-12 text-bakery-400"></span> <span class="mark mark-r w-12 h-12 text-bakery-400"></span>
</div> </div>
</body> </body>
@@ -11,16 +11,21 @@
Both fragments take the classes that vary by where they sit — cream in the footer, sage on white in a Both fragments take the classes that vary by where they sit — cream in the footer, sage on white in a
card — so the content is shared without the styling being averaged into something that suits neither. card — so the content is shared without the styling being averaged into something that suits neither.
They take TWO classes each, and the outer one is not a convenience. A caller cannot put a class on the
tag it writes the th:replace on: th:replace swaps that whole tag out for the fragment, so the attribute
is dropped and nothing says so. Every call site here had tried it — an mt-4 that never spaced anything,
a text-bakery-800 that left the address a shade darker than the hours beside it.
*/--> */-->
<ul th:fragment="hours(rowClass)" class="space-y-3"> <ul th:fragment="hours(className, rowClass)" th:class="'space-y-3 ' + ${className}">
<li th:each="span : ${hours}" th:class="'flex justify-between gap-4 ' + ${rowClass}"> <li th:each="span : ${hours}" th:class="'flex justify-between gap-4 ' + ${rowClass}">
<span th:text="${span.days}">Tuesday Friday</span> <span th:text="${span.days}">Tuesday Friday</span>
<span class="font-medium whitespace-nowrap" th:text="${span.hours}">7:00am 2:00pm</span> <span class="font-medium whitespace-nowrap" th:text="${span.hours}">7:00am 2:00pm</span>
</li> </li>
</ul> </ul>
<address th:fragment="address(linkClass)" class="not-italic space-y-3"> <address th:fragment="address(className, linkClass)" th:class="'not-italic space-y-3 ' + ${className}">
<p th:text="${shopStreet}">215 E Main Street</p> <p th:text="${shopStreet}">215 E Main Street</p>
<p th:text="${shopTown}">Princeville, IL 61559</p> <p th:text="${shopTown}">Princeville, IL 61559</p>
<p> <p>
+2 -3
View File
@@ -112,12 +112,11 @@
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-12 measure-wide mt-14 md:mt-18"> <div class="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-12 measure-wide mt-14 md:mt-18">
<div class="panel p-6 md:p-8"> <div class="panel p-6 md:p-8">
<h2 class="h3 text-bakery-900 mb-8">Our hours</h2> <h2 class="h3 text-bakery-900 mb-8">Our hours</h2>
<div th:replace="~{fragments/visit :: hours('text-bakery-800')}"></div> <div th:replace="~{fragments/visit :: hours('', 'text-bakery-800')}"></div>
</div> </div>
<div class="panel p-6 md:p-8"> <div class="panel p-6 md:p-8">
<h2 class="h3 text-bakery-900 mb-8">Find us</h2> <h2 class="h3 text-bakery-900 mb-8">Find us</h2>
<div class="text-bakery-800" <div th:replace="~{fragments/visit :: address('text-bakery-800', 'link-plain')}"></div>
th:replace="~{fragments/visit :: address('link-plain')}"></div>
</div> </div>
</div> </div>
</div> </div>