08e856120b
- Tapping an object on the desk opens a window (desktop) or a bottom sheet (mobile) instead of flipping: projects, now, servers, reading, about, contact - Desktop windows in poster style (2px ink rule, hard offset shadow), open from the tapped object, thrown by the title bar with momentum and elastic viewport edges, stack by focus, minimize into a tray, Escape closes the top window, focus moves to close and returns to the trigger - Mobile sheets via vaul 1.1.2: drag down to dismiss, overlay, focus trap - Project window shows live/source links from Directus when present - Hero "Write me" opens the contact window; still a plain #contact link without JavaScript - Shared current-book loader for desk, deck and reading window - Texts in de/en, i18n key check extended Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
70 lines
3.1 KiB
TypeScript
70 lines
3.1 KiB
TypeScript
import { getTranslations } from "next-intl/server";
|
|
import KineticWordmark from "./KineticWordmark";
|
|
import OpenWindowLink from "./fenster/OpenWindowLink";
|
|
|
|
interface HeroProps {
|
|
locale: string;
|
|
}
|
|
|
|
// Abgabe der Masterarbeit, Grundlage für den Countdown im Intro
|
|
const THESIS_DEADLINE = new Date("2027-02-15T12:00:00+01:00");
|
|
|
|
const MARQUEE = ["Self-Hosting", "Next.js", "SwiftUI", "Flutter", "Docker", "Microsoft 365", "Godot", "Home Assistant"];
|
|
|
|
export default async function Hero({ locale }: HeroProps) {
|
|
const t = await getTranslations({ locale, namespace: "home.hero" });
|
|
const daysLeft = Math.max(0, Math.ceil((THESIS_DEADLINE.getTime() - Date.now()) / 86_400_000));
|
|
|
|
return (
|
|
<>
|
|
<section id="top" className="relative overflow-hidden bg-signal px-4 pt-24 text-ink sm:px-6 md:pt-28 lg:px-10">
|
|
<p className="font-mono text-[13px] leading-snug">{t("kicker")}</p>
|
|
|
|
<div className="mt-4 sm:mt-8">
|
|
<KineticWordmark />
|
|
</div>
|
|
|
|
<div className="mt-3 grid gap-6 border-t-2 border-ink pb-8 pt-6 md:grid-cols-[1.3fr_1fr] md:items-end md:pb-10">
|
|
<h1 className="text-balance font-display text-[clamp(2rem,4.4vw,4rem)] font-extrabold leading-[0.96] tracking-[-0.035em] [font-variation-settings:'wdth'_85]">
|
|
<span className="sr-only">Dennis Konkol: </span>
|
|
{t("claim")}
|
|
</h1>
|
|
<div>
|
|
<p className="max-w-[42ch] text-[17px] leading-relaxed">
|
|
{t("intro")} {daysLeft > 0 && t("countdown", { days: daysLeft })}
|
|
</p>
|
|
<div className="mt-5 flex flex-wrap gap-2.5">
|
|
<a
|
|
href="#projects"
|
|
className="inline-flex items-center gap-2 rounded-full bg-ink px-5 py-3.5 text-[15px] font-semibold text-paper transition-transform duration-150 ease-out active:scale-[0.97]"
|
|
>
|
|
{t("ctaWork")} <span aria-hidden="true">↓</span>
|
|
</a>
|
|
<OpenWindowLink
|
|
href="#contact"
|
|
request={{ kind: "contact" }}
|
|
className="inline-flex items-center rounded-full px-5 py-3.5 text-[15px] font-semibold shadow-[inset_0_0_0_1.5px_rgb(var(--plakat-ink))] transition-[background-color,color,transform] duration-150 ease-out hover:bg-ink hover:text-signal active:scale-[0.97]"
|
|
>
|
|
{t("ctaContact")}
|
|
</OpenWindowLink>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<div className="overflow-hidden bg-ink text-paper" aria-hidden="true">
|
|
<div className="flex w-max animate-marquee gap-9 py-[18px] font-display text-[clamp(1.1rem,2.4vw,1.7rem)] font-bold leading-none">
|
|
{[...MARQUEE, ...MARQUEE].map((item, i) => (
|
|
<span key={i} className="flex items-center gap-9 whitespace-nowrap">
|
|
{item}
|
|
<svg viewBox="0 0 24 24" className="h-[0.7em] w-[0.7em] fill-signal">
|
|
<path d="M12 1.5l2.6 7.9 7.9 2.6-7.9 2.6-2.6 7.9-2.6-7.9-7.9-2.6 7.9-2.6z" />
|
|
</svg>
|
|
</span>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|