feat: contact topics per audience, room above the last sentence, a hero line that says what a client gets
Build & Deploy / 🔍 Prepare (push) Successful in 5s
Build & Deploy / 🏗️ Build (push) Canceled after 4m30s
Build & Deploy / 🚀 Deploy (push) Canceled after 0s
Build & Deploy / 🩺 Smoke Test (push) Canceled after 0s
Build & Deploy / 🔔 Notify (push) Canceled after 0s

Contact: the message starter offered every topic on both pages. The homepage
now offers automation, a website, or something else; the freelance page a
developer, a reliable app, or something else.

Thread: where it crosses the page above the last sentence it ran too close
to the text. It keeps more distance now, on phones too.

Hero: the line under the hero listed years, working hours and two links,
which says nothing to a client (owner). It now names four things a client
gets: one contact who builds it himself, an offer before anything costs
money, changes by email, servers in Germany.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 12:32:33 +02:00
co-authored by Claude Opus 5.5
parent af66f61c26
commit 2cb15608dd
10 changed files with 51 additions and 37 deletions
+5 -3
View File
@@ -10,9 +10,11 @@ import { ContactComposer } from "./ContactComposer";
/** ClosingCta: the contact section. One address and a message starter, no form to submit. */
export const ClosingCta: React.FC<{
contact: Content["contact"];
/** What visitors of this page may want: the topics of the message starter. */
topics: readonly string[];
/** The last sentence of the story; the story thread ends in front of it. */
story?: string;
}> = ({ contact, story }) => (
}> = ({ contact, topics, story }) => (
<section
id="contact"
data-glow
@@ -28,7 +30,7 @@ export const ClosingCta: React.FC<{
/>
<div className="bit-glow bit-glow-dots" aria-hidden="true" />
<BitSeam />
<div className="relative mx-auto grid w-full max-w-[1400px] grid-cols-1 gap-12 px-5 py-16 md:px-12 md:py-40 lg:grid-cols-12 lg:items-center lg:gap-12">
<div className="relative mx-auto grid w-full max-w-[1400px] grid-cols-1 gap-12 px-5 pb-16 pt-28 md:px-12 md:py-40 lg:grid-cols-12 lg:items-center lg:gap-12">
<Reveal className="lg:col-span-6">
{story && (
<p className="relative m-0 mb-10 max-w-xl font-sans text-2xl font-bold leading-[1.1] tracking-tight text-white md:mb-14 md:text-5xl">
@@ -55,7 +57,7 @@ export const ClosingCta: React.FC<{
</Reveal>
<Reveal delay={0.15} className="lg:col-span-6">
<BitAura source="around" tone="dark">
<ContactComposer />
<ContactComposer topicIds={topics} />
</BitAura>
</Reveal>
</div>
@@ -51,9 +51,16 @@ const withBlanks = (text: string): React.ReactNode =>
* opens it in the visitor's own mail app, ready to finish and send. The address
* is assembled in the browser, so it never appears in the page source.
*/
export const ContactComposer: React.FC = () => {
export const ContactComposer: React.FC<{
/** The topics this page offers, in this order. */
topicIds: readonly string[];
}> = ({ topicIds }) => {
const { contact } = useContent();
const topics = contact.topics;
const topics = React.useMemo(
() =>
topicIds.flatMap((id) => contact.topics.filter((item) => item.id === id)),
[contact.topics, topicIds],
);
const [topicId, setTopicId] = React.useState(topics[0]?.id ?? "");
const [address, setAddress] = React.useState<string | null>(null);
const [copied, setCopied] = React.useState(false);
+7 -22
View File
@@ -43,35 +43,20 @@ export const HeroStatement: React.FC<{ hero: Content["hero"] }> = ({
</div>
</div>
<ul className="m-0 mt-14 flex list-none flex-wrap gap-x-8 gap-y-3 border-t border-slate-200 p-0 pt-6 md:mt-20">
{/* What a client gets, in a few words. */}
<ul className="m-0 mt-14 grid list-none grid-cols-1 gap-x-10 gap-y-3 border-t border-slate-200 p-0 pt-6 sm:grid-cols-2 md:mt-20 lg:grid-cols-4">
{hero.trust.map((item) => (
<li
key={item}
className="font-mono text-[10px] uppercase tracking-[0.2em] text-slate-500 md:text-[11px]"
className="flex items-start gap-3 font-sans text-sm leading-snug text-slate-700 md:text-base"
>
<span
className="mt-[0.45em] h-1.5 w-1.5 shrink-0 bg-indigo-600"
aria-hidden="true"
/>
{item}
</li>
))}
<li className="font-mono text-[10px] uppercase tracking-[0.2em] text-slate-500 md:text-[11px]">
{hero.builtAndRunning}{" "}
<a
href="https://klz-cables.com"
target="_blank"
rel="noopener noreferrer"
className="text-slate-900 underline-offset-4 hover:underline"
>
klz-cables.com
</a>
{" · "}
<a
href="https://e-tib.com"
target="_blank"
rel="noopener noreferrer"
className="text-slate-900 underline-offset-4 hover:underline"
>
e-tib.com
</a>
</li>
</ul>
</div>
</section>