Dark surfaces now carry light: frames glow along their edge and shed binary digits (BitAura), dark sections open with a lit seam (BitSeam), the career path is a line of light and "My work" became a dark stage. Buttons carry a travelling light and a spot that follows the pointer (BitGlow). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
81 lines
3.1 KiB
TypeScript
81 lines
3.1 KiB
TypeScript
"use client";
|
|
|
|
import { BitSeam } from "@/src/components/bits/BitSeam";
|
|
import * as React from "react";
|
|
import Image from "next/image";
|
|
import { motion } from "framer-motion";
|
|
import { BitReveal } from "@/src/components/bits/BitReveal";
|
|
import { BitWipe } from "@/src/components/bits/BitWipe";
|
|
import { DecodeText } from "@/src/components/bits/DecodeText";
|
|
|
|
/**
|
|
* PortraitSection: the introduction, with the portrait fading out of a dark surface
|
|
* and the text set over it.
|
|
*/
|
|
export const PortraitSection: React.FC<{
|
|
id?: string;
|
|
index: string;
|
|
label: string;
|
|
title: React.ReactNode;
|
|
children: React.ReactNode;
|
|
}> = ({ id, index, label, title, children }) => (
|
|
<section
|
|
id={id}
|
|
className="relative scroll-mt-24 overflow-hidden bg-slate-900 text-white"
|
|
>
|
|
{/* Portrait: right side on wide screens, top on small ones. */}
|
|
<motion.div
|
|
className="relative h-[110vw] w-full md:absolute md:inset-y-0 md:right-0 md:h-auto md:w-[62%]"
|
|
initial={{ scale: 1.06 }}
|
|
whileInView={{ scale: 1 }}
|
|
viewport={{ once: true, margin: "-10%" }}
|
|
transition={{ duration: 1.4, ease: [0.16, 1, 0.3, 1] }}
|
|
>
|
|
<Image
|
|
src="/marc-mintel.png"
|
|
alt="Marc Mintel, freelance web developer"
|
|
fill
|
|
sizes="(min-width: 768px) 62vw, 100vw"
|
|
className="object-cover object-[50%_18%] grayscale"
|
|
priority={false}
|
|
/>
|
|
{/* Slow light behind the fades, so the dark surface is not flat. */}
|
|
<div className="bit-aurora" aria-hidden="true" />
|
|
{/* Fades: into the surface on the left, and at top and bottom. */}
|
|
<div className="absolute inset-0 hidden bg-gradient-to-r from-slate-900 via-slate-900/75 to-slate-900/10 md:block" />
|
|
<div className="absolute inset-x-0 bottom-0 h-2/5 bg-gradient-to-t from-slate-900 to-transparent" />
|
|
<div className="absolute inset-x-0 top-0 h-24 bg-gradient-to-b from-slate-900 to-transparent" />
|
|
{/* The portrait assembles itself out of binary digits. */}
|
|
<BitReveal />
|
|
</motion.div>
|
|
|
|
<div className="relative z-10 mx-auto w-full max-w-[1400px] px-5 pb-20 md:px-12 md:py-40">
|
|
<motion.div
|
|
className="-mt-24 max-w-3xl md:mt-0"
|
|
initial={{ opacity: 0, y: 24 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true, margin: "-10%" }}
|
|
transition={{ duration: 0.8, delay: 0.2, ease: [0.16, 1, 0.3, 1] }}
|
|
>
|
|
<div className="mb-8 flex items-center gap-4 md:mb-12">
|
|
<span className="font-mono text-[11px] font-bold tracking-[0.2em] text-white">
|
|
{index}
|
|
</span>
|
|
<span className="h-px w-10 bg-slate-600" />
|
|
<DecodeText
|
|
text={label}
|
|
className="font-mono text-[11px] uppercase tracking-[0.25em] text-slate-400"
|
|
/>
|
|
</div>
|
|
<BitWipe tone="light" delay={0.35}>
|
|
<h2 className="m-0 text-5xl font-bold leading-[0.95] tracking-tighter text-white md:text-7xl lg:text-[6.5rem]">
|
|
{title}
|
|
</h2>
|
|
</BitWipe>
|
|
<div className="mt-10 md:mt-14">{children}</div>
|
|
</motion.div>
|
|
</div>
|
|
<BitSeam density={1} />
|
|
</section>
|
|
);
|