This repository has been archived on 2026-09-03. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
itsthevine/src/main/resources/templates/contact.html
T
austin ec61b40b12 A design pass: the type ladder from the logo, and one name per thing
TYPOGRAPHY, taken from the lockup and walked down to something you can read a paragraph in. "The Vine" in
LeJour Script over COFFEEHOUSE + BAKERY in AdBhashitha is the whole brand voice, so: the script stays in
the wordmark and nowhere else (it is unreadable at length); AdBhashitha carries h1–h4 and the price, and
keeps the wordmark's 0.01em letter-spacing so a heading sits on the same rhythm as the logo above it;
`eyebrow` and `label` are the hinge — sans, but letterspaced like the tagline — and then plain Raleway.
Sizes are declared once in type.css instead of being re-chosen per template, and none of the type classes
set a colour, because the same heading appears in sage on cream and in cream on sage.

BUTTONS AND SURFACES have names now. `panel` is the white box that was "bg-white rounded-3xl shadow-xs"
written out in nine places (which is how two of them end up with different corners); `panel-lift` is one
that reacts. `pill` is one shape in four colourways, which exist because this site puts buttons on cream
AND on sage and they cannot be the same colour on both. `chip`/`chip-on` are the products filter.

RHYTHM: `section` (py-16 md:py-24) and `band` (py-14 md:py-20, tighter because a coloured strip is already
doing the separating) replace nine hand-picked paddings.

FOCUS: one visible ring for everything reachable by keyboard, as an outline rather than a shadow so it
works on cream, on white and on the sage bands, at zero specificity so a utility can still win.

Z-INDEX: written down in base.css, all two of it — 40 the sticky header, 30 the mobile panel, which is a
child of the header and so can only ever sit under the bar. Everything else stacks in document order. The
point of the comment is that a third layer doesn't get invented at 9999.

DROPDOWNS: the admin's category selects were drawing the platform's own arrow in the platform's grey; they
get the site's chevron and room for it.

53 tests green. Every class used across all nine pages — five public, four admin — resolves in the
compiled stylesheet, so nothing here is styled by a name that doesn't exist.
2026-07-26 18:10:47 -05:00

100 lines
5.0 KiB
HTML

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:replace="~{fragments/page :: page(${title}, ${description}, ${path}, ~{::content})}">
<body>
<div th:fragment="content" class="min-h-screen bg-bakery-50">
<header class="container mx-auto px-4 pt-14 pb-10 md:pt-20 md:pb-12 text-center">
<h1 class="h1 text-bakery-900">Contact us</h1>
<p class="mt-4 text-bakery-800 max-w-xl mx-auto leading-relaxed">
Ask about a cake, a date, or an order for a crowd. We read everything that comes in.
</p>
</header>
<!--/*
The form, and beside it the things somebody on this page is usually actually after: when we are open,
where we are, and the phone number. They were on the homepage and in the footer but not here, which
made this page a form and nothing else.
*/-->
<div class="container mx-auto px-4 pb-16 md:pb-24">
<div class="grid gap-8 lg:grid-cols-[1.4fr_1fr] max-w-5xl mx-auto items-start">
<div class="panel p-8 md:p-10">
<h2 class="h3 text-bakery-900 mb-2">Get in touch</h2>
<p class="text-bakery-700 mb-8">
Or call us: <a href="tel:+13097010660" class="underline underline-offset-4 hover:text-bakery-600">(309) 701-0660</a>
</p>
<!--/*
A plain form post. The enquiry is validated, written down and mailed by the server, which then
renders this page again with the outcome — no fetch, no JSON, and nothing to go wrong between
pressing the button and the enquiry being recorded.
Spring Security's CSRF token is added to any th:action form automatically, which is what keeps
this working on a deployment that has an identity provider configured (there, an unaccompanied
POST is rejected).
*/-->
<!--/* th:unless, not th:if="${!sent}": the attribute is absent on a GET, and SpEL cannot negate
a null. */-->
<form th:action="@{/contact}" method="post" th:unless="${sent}">
<div class="mb-4">
<label class="block text-sm font-medium text-bakery-800 mb-2" for="name">Name</label>
<input type="text" id="name" name="name" th:value="${name}" required
class="w-full px-4 py-2.5 bg-bakery-50 border border-bakery-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-bakery-500 focus:border-bakery-500">
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-bakery-800 mb-2" for="email">Email</label>
<input type="email" id="email" name="email" th:value="${email}" required
class="w-full px-4 py-2.5 bg-bakery-50 border border-bakery-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-bakery-500 focus:border-bakery-500">
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-bakery-800 mb-2" for="message">Message</label>
<textarea id="message" name="message" rows="5" required th:text="${message}"
class="w-full px-4 py-2.5 bg-bakery-50 border border-bakery-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-bakery-500 focus:border-bakery-500"></textarea>
</div>
<div class="flex flex-col items-center gap-4">
<button type="submit"
class="pill-sage">
Send message
</button>
<!--/* Never claim a success we did not get: say what happened and give them the phone number. */-->
<p th:if="${error}" role="alert" class="text-center text-red-700">
<span th:text="${error}">Could not send the message.</span>
Please call us on
<a href="tel:+13097010660" class="underline underline-offset-4">(309) 701-0660</a>.
</p>
</div>
</form>
<p th:if="${sent}" role="status" class="text-bakery-700">
Thanks. Your message is on its way, and we will get back to you.
</p>
</div>
<aside class="space-y-6">
<div class="panel p-6 md:p-8">
<h2 class="h4 text-bakery-900">Our hours</h2>
<div class="mt-4 text-bakery-800"
th:replace="~{fragments/visit :: hours('text-bakery-800')}"></div>
</div>
<div class="panel p-6 md:p-8">
<h2 class="h4 text-bakery-900">Find us</h2>
<div class="mt-4 text-bakery-800"
th:replace="~{fragments/visit :: address('hover:text-bakery-600 underline underline-offset-4')}"></div>
</div>
<div class="rounded-3xl border border-bakery-200 p-6 md:p-8">
<h2 class="h4 text-bakery-900">Ordering for a crowd?</h2>
<p class="mt-2 text-sm text-bakery-700 leading-relaxed">
Goodie boxes, party packages and wedding desserts have their own page, with sizes and prices.
</p>
<a href="/catering" class="mt-4 inline-block text-bakery-700 hover:text-bakery-900 font-medium
underline underline-offset-4 transition-colors">
Goodie boxes &amp; catering
</a>
</div>
</aside>
</div>
</div>
</div>
</body>
</html>