feat: ultra-aggressive mobile spacing refinement & native fidelity navigation redesign

This commit is contained in:
2026-02-15 20:15:04 +01:00
parent 6244425551
commit cb32b9d62f
19 changed files with 722 additions and 376 deletions

View File

@@ -7,7 +7,7 @@ export const Footer: React.FC = () => {
const currentYear = new Date().getFullYear();
return (
<footer className="relative py-16 mt-24 border-t border-slate-100 bg-white z-10">
<footer className="relative py-10 md:py-16 mt-8 md:mt-24 border-t border-slate-100 bg-white z-10">
{/* Tech border at top */}
<div className="absolute top-0 left-0 right-0 h-px overflow-hidden">
<div
@@ -20,14 +20,19 @@ export const Footer: React.FC = () => {
</div>
<div className="narrow-container">
<div className="grid grid-cols-1 md:grid-cols-2 gap-12 items-end">
<div className="space-y-8">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-12 items-end">
<div className="space-y-6">
<div className="flex items-center gap-3">
<Image src={LogoBlack} alt="Marc Mintel" height={72} />
<Image
src={LogoBlack}
alt="Marc Mintel"
height={64}
className="h-12 md:h-16 w-auto"
/>
</div>
</div>
<div className="flex flex-col md:items-end gap-4 text-sm font-mono text-slate-300 uppercase tracking-widest">
<div className="flex flex-col md:items-end gap-3 md:gap-4 text-xs md:text-sm font-mono text-slate-300 uppercase tracking-widest">
<span>© {currentYear}</span>
<div className="flex gap-8">
<a

View File

@@ -1,5 +1,5 @@
"use client";
import { AnimatePresence, motion } from "framer-motion";
import Image from "next/image";
import Link from "next/link";
import { usePathname } from "next/navigation";
@@ -10,6 +10,7 @@ import IconWhite from "../assets/logo/Icon White Transparent.svg";
export const Header: React.FC = () => {
const pathname = usePathname();
const [isScrolled, setIsScrolled] = React.useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = React.useState(false);
React.useEffect(() => {
const handleScroll = () => {
@@ -19,18 +20,44 @@ export const Header: React.FC = () => {
return () => window.removeEventListener("scroll", handleScroll);
}, []);
// Close mobile menu on pathname change and handle body scroll lock
React.useEffect(() => {
setIsMobileMenuOpen(false);
}, [pathname]);
React.useEffect(() => {
if (isMobileMenuOpen) {
document.body.style.overflow = "hidden";
} else {
document.body.style.overflow = "unset";
}
return () => {
document.body.style.overflow = "unset";
};
}, [isMobileMenuOpen]);
const isActive = (path: string) => pathname === path;
const navLinks = [
{ href: "/about", label: "Über mich" },
{ href: "/websites", label: "Websites" },
{ href: "/case-studies", label: "Case Studies", prefix: true },
{ href: "/blog", label: "Blog", prefix: true },
];
return (
<header
className={`sticky top-0 z-50 transition-all duration-500 ${
isScrolled
? "bg-white/70 backdrop-blur-xl border-b border-slate-100 shadow-sm shadow-slate-100/50"
: "bg-white/80 backdrop-blur-md border-b border-slate-50"
}`}
>
<header className="sticky top-0 z-[100] w-full">
{/* Decoupled Background Layer - Prevents backdrop-filter parent context bugs */}
<div
className={`absolute inset-0 transition-all duration-500 -z-10 ${
isScrolled
? "bg-white/70 backdrop-blur-xl border-b border-slate-100 shadow-sm shadow-slate-100/50"
: "bg-white/80 backdrop-blur-md border-b border-slate-50"
}`}
/>
{/* Animated tech border at bottom */}
<div className="absolute bottom-0 left-0 right-0 h-px overflow-hidden">
<div className="absolute bottom-0 left-0 right-0 h-px overflow-hidden pointer-events-none">
<div
className="h-full w-full"
style={{
@@ -42,28 +69,24 @@ export const Header: React.FC = () => {
/>
</div>
<div className="narrow-container py-4 flex items-center justify-between">
<div className="narrow-container py-4 flex items-center justify-between relative z-10">
<Link href="/" className="flex items-center gap-4 group">
<div className="flex items-center gap-3">
<div className="w-12 h-12 bg-black rounded-xl flex items-center justify-center group-hover:scale-105 transition-all duration-500 shadow-sm shrink-0 relative overflow-hidden">
<div className="w-10 h-10 md:w-12 md:h-12 bg-black rounded-xl flex items-center justify-center group-hover:scale-105 transition-all duration-500 shadow-sm shrink-0 relative overflow-hidden">
<Image
src={IconWhite}
alt="Marc Mintel Icon"
width={32}
height={32}
className="w-8 h-8 relative z-10"
className="w-6 h-6 md:w-8 md:h-8 relative z-10"
/>
</div>
</div>
</Link>
<nav className="flex items-center gap-8">
{[
{ href: "/about", label: "Über mich" },
{ href: "/websites", label: "Websites" },
{ href: "/case-studies", label: "Case Studies", prefix: true },
{ href: "/blog", label: "Blog", prefix: true },
].map((link) => {
{/* Desktop Navigation */}
<nav className="hidden md:flex items-center gap-8">
{navLinks.map((link) => {
const active = link.prefix
? isActive(link.href) || pathname?.startsWith(`${link.href}/`)
: isActive(link.href);
@@ -97,7 +120,196 @@ export const Header: React.FC = () => {
Anfrage
</Link>
</nav>
{/* Mobile Toggle */}
<button
className="md:hidden relative z-[110] p-2 w-10 h-10 flex items-center justify-center rounded-xl bg-slate-900 text-white active:scale-90 transition-all duration-300 shadow-lg shadow-slate-200"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
aria-label="Toggle Menu"
>
<div className="w-5 h-3.5 relative flex flex-col justify-between">
<motion.span
animate={
isMobileMenuOpen ? { rotate: 45, y: 7 } : { rotate: 0, y: 0 }
}
transition={{ duration: 0.3, ease: [0.23, 1, 0.32, 1] }}
className="w-full h-0.5 bg-current rounded-full origin-center"
/>
<motion.span
animate={
isMobileMenuOpen ? { opacity: 0, x: -10 } : { opacity: 1, x: 0 }
}
transition={{ duration: 0.2 }}
className="w-full h-0.5 bg-current rounded-full"
/>
<motion.span
animate={
isMobileMenuOpen ? { rotate: -45, y: -7 } : { rotate: 0, y: 0 }
}
transition={{ duration: 0.3, ease: [0.23, 1, 0.32, 1] }}
className="w-full h-0.5 bg-current rounded-full origin-center"
/>
</div>
</button>
</div>
{/* Mobile Navigation - Bottom-Anchored Control Center */}
<AnimatePresence>
{isMobileMenuOpen && (
<React.Fragment key="mobile-control-center">
{/* Dimmed Backdrop */}
<motion.div
key="cc-backdrop"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.25 }}
onClick={() => setIsMobileMenuOpen(false)}
className="fixed inset-0 z-[101] bg-black/30 backdrop-blur-sm md:hidden"
/>
{/* Bottom Sheet */}
<motion.div
key="cc-sheet"
initial={{ y: "100%" }}
animate={{ y: 0 }}
exit={{ y: "100%" }}
transition={{
type: "spring",
stiffness: 350,
damping: 30,
mass: 0.8,
}}
drag="y"
dragConstraints={{ top: 0, bottom: 0 }}
dragElastic={0.15}
onDragEnd={(_, info) => {
if (info.offset.y > 80 || info.velocity.y > 300) {
setIsMobileMenuOpen(false);
}
}}
className="fixed inset-x-0 bottom-0 z-[102] md:hidden bg-white rounded-t-[2rem] shadow-[0_-8px_40px_rgba(0,0,0,0.12)] flex flex-col max-h-[85vh] overflow-hidden"
>
{/* Grab Handle */}
<div className="flex justify-center pt-3 pb-2 cursor-grab active:cursor-grabbing">
<div className="w-10 h-1 bg-slate-200 rounded-full" />
</div>
{/* Status Bar */}
<div className="px-6 py-3 flex justify-between items-center border-b border-slate-100/80">
<div className="flex items-center gap-2 text-[9px] font-mono font-bold tracking-[0.15em] text-slate-400 uppercase">
<div className="w-1.5 h-1.5 rounded-full bg-green-500 animate-pulse" />
Online
</div>
<div className="text-[9px] font-mono font-bold tracking-widest text-slate-400 uppercase">
{pathname === "/"
? "HOME"
: pathname.toUpperCase().replace(/^\//, "")}
</div>
</div>
{/* Tiled Navigation Grid */}
<div className="px-5 pt-5 pb-3 flex-1 overflow-y-auto">
<div className="grid grid-cols-2 gap-2.5">
{[
{ href: "/about", label: "Über mich", sub: "Architect" },
{ href: "/websites", label: "Websites", sub: "Systems" },
{
href: "/case-studies",
label: "Cases",
sub: "Solutions",
prefix: true,
},
{
href: "/blog",
label: "Blog",
sub: "Insights",
prefix: true,
},
].map((item, i) => {
const active = item.prefix
? pathname?.startsWith(item.href)
: pathname === item.href;
return (
<motion.div
key={item.href}
initial={{ opacity: 0, scale: 0.85, y: 15 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
transition={{
delay: 0.05 + i * 0.04,
type: "spring",
stiffness: 400,
damping: 25,
}}
whileTap={{ scale: 0.95 }}
>
<Link
href={item.href}
onClick={() => setIsMobileMenuOpen(false)}
className={`relative flex flex-col justify-center p-6 h-[110px] rounded-2xl border transition-all duration-200 ${
active
? "bg-slate-50 border-slate-200 ring-1 ring-slate-200"
: "bg-white border-slate-100 active:bg-slate-50"
}`}
>
<div>
<span className="text-[15px] font-black tracking-tight text-slate-900 block leading-tight mb-1">
{item.label}
</span>
<span className="text-[9px] font-mono font-bold text-slate-400 uppercase tracking-[0.2em]">
{item.sub}
</span>
</div>
{active && (
<div className="absolute top-4 right-4 w-1.5 h-1.5 rounded-full bg-slate-900" />
)}
</Link>
</motion.div>
);
})}
</div>
</div>
{/* Primary CTA */}
<div className="px-5 pb-5 pt-2">
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.25, type: "spring", stiffness: 300 }}
whileTap={{ scale: 0.97 }}
>
<Link
href="/contact"
onClick={() => setIsMobileMenuOpen(false)}
className="flex items-center justify-between w-full p-4 bg-slate-900 text-white rounded-2xl active:bg-slate-800 transition-colors"
>
<span className="text-[13px] font-bold uppercase tracking-[0.15em]">
Projekt anfragen
</span>
<svg
className="w-4 h-4 text-slate-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2.5"
d="M14 5l7 7m0 0l-7 7m7-7H3"
/>
</svg>
</Link>
</motion.div>
</div>
{/* Safe-Area Spacer (iOS home indicator) */}
<div className="h-[env(safe-area-inset-bottom,0px)]" />
</motion.div>
</React.Fragment>
)}
</AnimatePresence>
</header>
);
};

View File

@@ -1,54 +1,69 @@
import { BookOpen, Code2, Terminal, Wrench } from 'lucide-react';
import * as React from 'react';
import { BookOpen, Code2, Terminal, Wrench } from "lucide-react";
import * as React from "react";
export const Hero: React.FC = () => {
return (
<section className="relative bg-slate-900 text-white py-20 md:py-24 overflow-hidden">
<section className="relative bg-slate-900 text-white py-16 md:py-24 overflow-hidden text-center">
{/* Background pattern */}
<div className="absolute inset-0 opacity-10">
<div className="absolute inset-0" style={{
backgroundImage: 'radial-gradient(circle at 1px 1px, white 1px, transparent 0)',
backgroundSize: '40px 40px'
}} />
<div
className="absolute inset-0"
style={{
backgroundImage:
"radial-gradient(circle at 1px 1px, white 1px, transparent 0)",
backgroundSize: "32px 32px",
}}
/>
</div>
<div className="container relative z-10">
<div className="max-w-4xl mx-auto text-center">
<div className="max-w-4xl mx-auto">
{/* Main heading */}
<h1 className="text-4xl md:text-6xl font-bold mb-6 animate-slide-up">
<h1 className="text-4xl md:text-6xl font-bold mb-4 md:mb-6 animate-slide-up leading-tight">
Digital Problem Solver
</h1>
<p className="text-xl md:text-2xl text-slate-300 mb-8 leading-relaxed animate-fade-in">
I work on Digital problems and build tools, scripts, and systems to solve them.
<p className="text-lg md:text-2xl text-slate-300 mb-8 leading-relaxed animate-fade-in px-4 md:px-0">
I work on Digital problems and build tools, scripts, and systems to
solve them.
</p>
{/* Quick stats or focus areas */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-6 mb-12 animate-fade-in">
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 md:gap-6 mb-12 animate-fade-in">
<div className="bg-white/5 backdrop-blur-sm rounded-2xl p-6 border border-white/10 hover:border-white/30 transition-all duration-300">
<Code2 className="mx-auto mb-3 text-slate-400" size={28} />
<div className="text-xs font-bold uppercase tracking-widest text-slate-300">Code</div>
<div className="text-xs font-bold uppercase tracking-widest text-slate-300">
Code
</div>
</div>
<div className="bg-white/5 backdrop-blur-sm rounded-2xl p-6 border border-white/10 hover:border-white/30 transition-all duration-300">
<Wrench className="mx-auto mb-3 text-slate-400" size={28} />
<div className="text-xs font-bold uppercase tracking-widest text-slate-300">Tools</div>
<div className="text-xs font-bold uppercase tracking-widest text-slate-300">
Tools
</div>
</div>
<div className="bg-white/5 backdrop-blur-sm rounded-2xl p-6 border border-white/10 hover:border-white/30 transition-all duration-300">
<Terminal className="mx-auto mb-3 text-slate-400" size={28} />
<div className="text-xs font-bold uppercase tracking-widest text-slate-300">Automation</div>
<div className="text-xs font-bold uppercase tracking-widest text-slate-300">
Automation
</div>
</div>
<div className="bg-white/5 backdrop-blur-sm rounded-2xl p-6 border border-white/10 hover:border-white/30 transition-all duration-300">
<BookOpen className="mx-auto mb-3 text-slate-400" size={28} />
<div className="text-xs font-bold uppercase tracking-widest text-slate-300">Learning</div>
<div className="text-xs font-bold uppercase tracking-widest text-slate-300">
Learning
</div>
</div>
</div>
{/* Topics */}
<div className="mt-8 text-sm text-slate-400 animate-fade-in">
<span className="font-semibold text-slate-300">Topics:</span> Vibe coding with AI Debugging Mac tools Automation Small scripts Learning notes FOSS
<span className="font-semibold text-slate-300">Topics:</span> Vibe
coding with AI Debugging Mac tools Automation Small scripts
Learning notes FOSS
</div>
</div>
</div>
</section>
);
};
};

View File

@@ -20,17 +20,17 @@ export const HeroSection: React.FC = () => {
const opacity = useTransform(scrollY, [0, 600], [1, 0]);
return (
<section className="relative min-h-[100vh] flex items-center justify-center overflow-hidden bg-white">
<section className="relative min-h-[85dvh] md:min-h-[100dvh] flex items-center justify-center overflow-hidden bg-white px-5 md:px-0">
{/* 1. The Binary Architecture (Background) */}
<div className="absolute inset-0 z-0">
<AbstractCircuit />
</div>
{/* 2. Content Layer */}
<div className="relative z-10 container mx-auto px-6 h-full flex flex-col justify-center items-center">
<div className="relative z-10 container mx-auto h-full flex flex-col justify-center items-center">
<motion.div
style={{ y, opacity }}
className="text-center relative max-w-[90vw]"
className="text-center relative max-w-full md:max-w-[90vw]"
>
{/* Architectural Coordinate Labels */}
<div className="absolute -left-20 top-0 hidden xl:flex flex-col gap-8 opacity-20 pointer-events-none">
@@ -47,19 +47,19 @@ export const HeroSection: React.FC = () => {
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 1, delay: 0.2 }}
className="mb-10 inline-flex items-center gap-4 px-6 py-2 border border-slate-100 bg-white/40 backdrop-blur-sm rounded-full"
className="mb-4 md:mb-10 inline-flex items-center gap-3 md:gap-4 px-4 md:px-6 py-2 border border-slate-100 bg-white/40 backdrop-blur-sm rounded-full"
>
<div className="flex gap-1">
<div className="w-1 h-1 rounded-full bg-blue-500 animate-pulse" />
<div className="w-1 h-1 rounded-full bg-blue-300 animate-pulse delay-100" />
</div>
<span className="text-[10px] font-mono font-bold tracking-[0.4em] text-slate-500 uppercase">
<span className="text-[9px] md:text-[10px] font-mono font-bold tracking-[0.3em] md:tracking-[0.4em] text-slate-500 uppercase">
Digital_Architect // v.2026
</span>
</motion.div>
{/* Headline */}
<h1 className="text-7xl md:text-[11rem] font-black tracking-tighter leading-[0.8] text-slate-900 mb-12 uppercase">
<h1 className="text-3xl md:text-[11rem] font-black tracking-tighter leading-[0.9] md:leading-[0.8] text-slate-900 mb-6 md:mb-12 uppercase">
<div className="block">
<GlitchText delay={0.5} duration={1.2}>
Websites
@@ -80,20 +80,26 @@ export const HeroSection: React.FC = () => {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 1, delay: 0.8 }}
className="flex flex-col items-center gap-12"
className="flex flex-col items-center gap-6 md:gap-12"
>
<p className="text-xl md:text-3xl text-slate-400 font-medium max-w-2xl leading-relaxed">
Ein Entwickler. Ein Ansprechpartner. <br />
<p className="text-base md:text-3xl text-slate-400 font-medium max-w-2xl leading-relaxed px-4">
Ein Entwickler. Ein Ansprechpartner.{" "}
<br className="hidden md:block" />
<span className="text-slate-900 font-bold tracking-tight">
Systematische Architekturen für das Web.
</span>
</p>
<div className="flex flex-wrap items-center justify-center gap-6">
<Button href="/contact" size="large">
<div className="flex flex-col md:flex-row items-center justify-center gap-4 md:gap-6 w-full px-5 md:px-0">
<Button href="/contact" size="large" className="w-full md:w-auto">
Projekt anfragen
</Button>
<Button href="/websites" variant="outline" size="large">
<Button
href="/websites"
variant="outline"
size="large"
className="w-full md:w-auto"
>
Prozess ansehen
</Button>
</div>
@@ -102,13 +108,13 @@ export const HeroSection: React.FC = () => {
</div>
{/* 3. Blueprint Frame (Decorative Borders) */}
<div className="absolute inset-0 pointer-events-none border-[1px] border-slate-100 m-8 opacity-40" />
<div className="absolute inset-0 pointer-events-none border-[1px] border-slate-100 m-4 md:m-8 opacity-40 md:opacity-40" />
<div className="absolute top-8 left-8 p-4 hidden md:block opacity-20 transform -rotate-90 origin-top-left transition-opacity hover:opacity-100 group">
<span className="text-[10px] font-mono tracking-widest text-slate-400">
POS_TRANSMISSION_001
</span>
</div>
<div className="absolute bottom-8 right-8 p-4 hidden md:block opacity-20 transition-opacity hover:opacity-100">
<div className="absolute bottom-4 right-4 md:bottom-8 md:right-8 p-4 opacity-20 transition-opacity hover:opacity-100 scale-75 md:scale-100 origin-bottom-right">
<span className="text-[10px] font-mono tracking-widest text-slate-400">
EST_2026 // M-ARCH
</span>
@@ -116,10 +122,10 @@ export const HeroSection: React.FC = () => {
{/* 4. Scroll Indicator */}
<motion.div
className="absolute bottom-10 left-1/2 -translate-x-1/2 flex flex-col items-center gap-3 opacity-40"
className="absolute bottom-6 md:bottom-10 left-1/2 -translate-x-1/2 flex flex-col items-center gap-3 opacity-40"
style={{ opacity }}
>
<div className="w-[1px] h-12 bg-slate-200" />
<div className="w-[1px] h-8 md:h-12 bg-slate-200" />
<span className="text-[9px] font-mono uppercase tracking-[0.3em] text-slate-400">
Scroll
</span>

View File

@@ -27,6 +27,8 @@ interface IframeSectionProps {
dynamicGlow?: boolean;
minHeight?: number;
mobileWidth?: number;
mobileHeight?: string;
desktopHeight?: string;
}
import PropTypes from "prop-types";
@@ -129,6 +131,8 @@ export const IframeSection: React.FC<IframeSectionProps> = ({
dynamicGlow = true,
minHeight = 400,
mobileWidth = 390,
mobileHeight,
desktopHeight,
}) => {
const containerRef = React.useRef<HTMLDivElement>(null);
const iframeRef = React.useRef<HTMLIFrameElement>(null);
@@ -264,7 +268,20 @@ export const IframeSection: React.FC<IframeSectionProps> = ({
return match ? parseFloat(match[1]) : null;
};
const baseNumericHeight = parseNumericHeight(height);
const [isMobile, setIsMobile] = React.useState(false);
React.useEffect(() => {
const checkMobile = () => setIsMobile(window.innerWidth < 768);
checkMobile();
window.addEventListener("resize", checkMobile);
return () => window.removeEventListener("resize", checkMobile);
}, []);
const activeHeight = isMobile
? mobileHeight || height
: desktopHeight || height;
const baseNumericHeight = parseNumericHeight(activeHeight);
const finalScaledHeight = clipHeight
? clipHeight * scale
: baseNumericHeight
@@ -273,11 +290,11 @@ export const IframeSection: React.FC<IframeSectionProps> = ({
const chassisStyle = {
height:
height === "100%"
activeHeight === "100%"
? "100%"
: finalScaledHeight
? `${finalScaledHeight + headerHeightPx}px`
: `calc(${height} + ${headerHeightPx}px)`,
: `calc(${activeHeight} + ${headerHeightPx}px)`,
minHeight: minHeight ? `${minHeight}px` : undefined,
};

View File

@@ -44,9 +44,9 @@ export const Card: React.FC<CardProps> = ({
const paddings = {
none: "p-0",
small: "p-6 md:p-8",
normal: "p-8 md:p-10",
large: "p-10 md:p-12",
small: "p-4 md:p-8",
normal: "p-5 md:p-10",
large: "p-6 md:p-12",
};
const [hexId, setHexId] = React.useState("0x0000");
@@ -103,7 +103,13 @@ export const Container: React.FC<{
};
return (
<div className={cn("mx-auto px-6 w-full", variants[variant], className)}>
<div
className={cn(
"mx-auto px-5 md:px-6 w-full",
variants[variant],
className,
)}
>
{children}
</div>
);

View File

@@ -29,18 +29,18 @@ export const MediumCard: React.FC<MediumCardProps> = ({ post }) => {
variant="glass"
padding="normal"
techBorder={false}
className="relative overflow-hidden transition-all duration-300 border-slate-100 hover:border-slate-300 bg-white/30 backdrop-blur-sm"
className="relative overflow-hidden transition-all duration-300 border-slate-100 hover:border-slate-300 bg-white/30 backdrop-blur-sm p-5 md:p-6"
>
<div className="space-y-4">
<div className="space-y-3 md:space-y-4">
<div className="flex items-center justify-between">
<time className="text-[10px] font-bold uppercase tracking-[0.2em] text-slate-400">
<time className="text-[9px] md:text-[10px] font-bold uppercase tracking-[0.2em] text-slate-400">
{formattedDate}
</time>
<div className="flex gap-2">
<div className="flex gap-1.5 md:gap-2">
{tags?.slice(0, 2).map((tag) => (
<span
key={tag}
className="text-[9px] font-mono text-slate-300 uppercase"
className="text-[8px] md:text-[9px] font-mono text-slate-300 uppercase"
>
#{tag}
</span>
@@ -48,16 +48,16 @@ export const MediumCard: React.FC<MediumCardProps> = ({ post }) => {
</div>
</div>
<div className="space-y-2">
<h3 className="text-2xl font-bold text-slate-900 tracking-tight leading-tight group-hover:text-black transition-colors">
<div className="space-y-1.5 md:space-y-2">
<h3 className="text-xl md:text-2xl font-bold text-slate-900 tracking-tight leading-tight group-hover:text-black transition-colors">
{title}
</h3>
<p className="text-base text-slate-500 font-serif italic leading-relaxed line-clamp-2">
<p className="text-sm md:text-base text-slate-500 font-serif italic leading-relaxed line-clamp-2">
{description}
</p>
</div>
<div className="pt-2 flex items-center gap-2 text-[10px] font-bold uppercase tracking-widest text-slate-400 group-hover:text-slate-900 transition-all">
<div className="pt-1 md:pt-2 flex items-center gap-2 text-[9px] md:text-[10px] font-bold uppercase tracking-widest text-slate-400 group-hover:text-slate-900 transition-all">
<span>Beitrag öffnen</span>
<ArrowRight className="w-3 h-3 translate-x-0 group-hover:translate-x-1 transition-transform" />
</div>

View File

@@ -23,7 +23,7 @@ export const PageHeader: React.FC<PageHeaderProps> = ({
return (
<section
className={cn(
"narrow-container relative",
"narrow-container relative overflow-hidden md:overflow-visible",
isBlog
? "pt-32 pb-12 md:pt-48 md:pb-16"
: "pt-24 pb-16 md:pt-40 md:pb-24",
@@ -35,8 +35,8 @@ export const PageHeader: React.FC<PageHeaderProps> = ({
className={cn(
"absolute font-bold text-slate-50 select-none -z-10 opacity-40 tracking-tighter leading-none",
isBlog
? "-left-8 top-12 text-[12rem] md:text-[16rem]"
: "-left-24 -top-12 text-[20rem] md:text-[24rem]",
? "-left-4 md:-left-8 top-12 text-[10rem] md:text-[16rem]"
: "-left-12 md:-left-24 -top-8 md:-top-12 text-[15rem] md:text-[24rem]",
)}
>
{backgroundSymbol}
@@ -51,13 +51,13 @@ export const PageHeader: React.FC<PageHeaderProps> = ({
)}
<div
className={cn("space-y-6 md:space-y-8 relative", isBlog && "max-w-7xl")}
className={cn("space-y-4 md:space-y-8 relative", isBlog && "max-w-7xl")}
>
<Reveal>
<h1
className={cn(
"font-bold text-slate-900 tracking-tighter leading-[1.1]",
isBlog ? "text-4xl md:text-6xl" : "text-5xl md:text-7xl",
isBlog ? "text-xl md:text-6xl" : "text-2xl md:text-7xl",
)}
>
{title}
@@ -70,8 +70,8 @@ export const PageHeader: React.FC<PageHeaderProps> = ({
className={cn(
"font-serif italic text-slate-400 leading-relaxed",
isBlog
? "text-lg md:text-xl max-w-xl"
: "text-xl md:text-2xl max-w-2xl",
? "text-sm md:text-xl max-w-xl"
: "text-base md:text-2xl max-w-2xl",
)}
>
{description}

View File

@@ -49,7 +49,7 @@ export const Section: React.FC<SectionProps> = ({
return (
<section
className={cn(
"relative py-24 md:py-40 group overflow-hidden",
"relative py-6 md:py-40 group overflow-hidden",
bgClass,
borderTopClass,
borderBottomClass,
@@ -81,41 +81,43 @@ export const Section: React.FC<SectionProps> = ({
{effects}
<div className={cn("relative z-10", containerClass)}>
<div className="grid grid-cols-1 md:grid-cols-12 gap-12 md:gap-24">
<div className="grid grid-cols-1 md:grid-cols-12 gap-4 md:gap-24">
{/* Sidebar: Number & Title (Only if provided) */}
{(number || title || illustration) && (
<div className="md:col-span-3">
<div className="md:sticky md:top-40 space-y-8">
{number && (
<Reveal delay={delay}>
<span className="block text-7xl md:text-8xl font-bold text-slate-100 leading-none select-none tracking-tighter relative">
{number}
{/* Subtle binary overlay on number */}
<span
className="absolute top-1 left-0 text-[8px] font-mono text-slate-200/30 tracking-wider leading-none select-none pointer-events-none"
aria-hidden="true"
>
{parseInt(number || "0")
.toString(2)
.padStart(8, "0")}
<div className="md:sticky md:top-40 flex flex-col gap-4 md:gap-8">
<div className="flex items-end md:flex-col md:items-start gap-6 md:gap-8">
{number && (
<Reveal delay={delay}>
<span className="block text-4xl md:text-8xl font-bold text-slate-100 leading-none select-none tracking-tighter relative">
{number}
{/* Subtle binary overlay on number */}
<span
className="absolute -top-1 md:top-1 left-0 text-[7px] md:text-[8px] font-mono text-slate-200/30 tracking-wider leading-none select-none pointer-events-none"
aria-hidden="true"
>
{parseInt(number || "0")
.toString(2)
.padStart(8, "0")}
</span>
</span>
</span>
</Reveal>
)}
{title && (
<Reveal delay={delay + 0.1}>
<div className="flex items-center gap-4">
{/* Animated dot indicator */}
<div className="w-1.5 h-1.5 rounded-full bg-slate-300 animate-circuit-pulse shrink-0" />
<Label className="text-slate-900 text-[10px] tracking-[0.4em]">
{title}
</Label>
</div>
</Reveal>
)}
</Reveal>
)}
{title && (
<Reveal delay={delay + 0.1}>
<div className="flex items-center gap-3 md:gap-4 mb-2 md:mb-0">
{/* Animated dot indicator */}
<div className="w-1.5 h-1.5 rounded-full bg-slate-300 animate-circuit-pulse shrink-0" />
<Label className="text-slate-900 text-[9px] md:text-[10px] tracking-[0.3em] md:tracking-[0.4em]">
{title}
</Label>
</div>
</Reveal>
)}
</div>
{illustration && (
<Reveal delay={delay + 0.2}>
<div className="pt-8 opacity-100 group-hover:scale-105 transition-transform duration-1000 ease-out origin-left grayscale hover:grayscale-0">
<div className="pt-2 md:pt-8 opacity-100 group-hover:scale-105 transition-transform duration-1000 ease-out origin-left grayscale hover:grayscale-0">
{illustration}
</div>
</Reveal>

View File

@@ -1,4 +1,4 @@
import * as React from 'react';
import * as React from "react";
interface TypographyProps {
children: React.ReactNode;
@@ -6,49 +6,77 @@ interface TypographyProps {
}
export const H1: React.FC<TypographyProps> = ({ children, className = "" }) => (
<h1 className={`text-5xl md:text-7xl font-bold text-slate-900 tracking-tighter leading-[1.1] ${className}`}>
<h1
className={`text-4xl md:text-7xl font-bold text-slate-900 tracking-tighter leading-[1.1] ${className}`}
>
{children}
</h1>
);
export const H2: React.FC<TypographyProps> = ({ children, className = "" }) => (
<h2 className={`text-3xl md:text-5xl font-bold text-slate-900 tracking-tighter leading-tight ${className}`}>
<h2
className={`text-xl md:text-5xl font-bold text-slate-900 tracking-tighter leading-tight ${className}`}
>
{children}
</h2>
);
export const H3: React.FC<TypographyProps> = ({ children, className = "" }) => (
<h3 className={`text-2xl md:text-4xl font-bold text-slate-900 tracking-tight leading-tight ${className}`}>
<h3
className={`text-lg md:text-4xl font-bold text-slate-900 tracking-tight leading-tight ${className}`}
>
{children}
</h3>
);
export const H4: React.FC<TypographyProps> = ({ children, className = "" }) => (
<h4 className={`text-xl md:text-2xl font-bold text-slate-900 tracking-tight ${className}`}>
<h4
className={`text-base md:text-2xl font-bold text-slate-900 tracking-tight ${className}`}
>
{children}
</h4>
);
export const LeadText: React.FC<TypographyProps> = ({ children, className = "" }) => (
<p className={`text-lg md:text-xl font-serif italic text-slate-500 leading-relaxed ${className}`}>
export const LeadText: React.FC<TypographyProps> = ({
children,
className = "",
}) => (
<p
className={`text-sm md:text-xl font-serif italic text-slate-500 leading-relaxed ${className}`}
>
{children}
</p>
);
export const BodyText: React.FC<TypographyProps> = ({ children, className = "" }) => (
<p className={`text-base text-slate-500 leading-relaxed ${className}`}>
export const BodyText: React.FC<TypographyProps> = ({
children,
className = "",
}) => (
<p
className={`text-sm md:text-base text-slate-500 leading-relaxed ${className}`}
>
{children}
</p>
);
export const Label: React.FC<TypographyProps> = ({ children, className = "" }) => (
<span className={`text-[10px] font-bold uppercase tracking-[0.3em] text-slate-400 block ${className}`}>
export const Label: React.FC<TypographyProps> = ({
children,
className = "",
}) => (
<span
className={`text-[10px] font-bold uppercase tracking-[0.3em] text-slate-400 block ${className}`}
>
{children}
</span>
);
export const MonoLabel: React.FC<TypographyProps> = ({ children, className = "" }) => (
<span className={`text-[10px] font-mono uppercase tracking-[0.2em] text-slate-400 block ${className}`}>
export const MonoLabel: React.FC<TypographyProps> = ({
children,
className = "",
}) => (
<span
className={`text-[10px] font-mono uppercase tracking-[0.2em] text-slate-400 block ${className}`}
>
{children}
</span>
);

View File

@@ -24,30 +24,30 @@ export const BlogCommandBar: React.FC<BlogCommandBarProps> = ({
return (
<div
className={cn(
"w-full max-w-2xl mx-auto flex flex-col items-center space-y-6 px-4 md:px-0",
"w-full max-w-2xl mx-auto flex flex-col items-center space-y-4 md:space-y-6 px-0",
className,
)}
>
{/* Command Input Area */}
<div className="relative group w-full">
<div className="relative group w-full px-0 sm:px-4 md:px-0">
{/* Glow Effect */}
<div className="absolute -inset-0.5 bg-gradient-to-r from-slate-200 to-slate-100 rounded-2xl blur opacity-30 group-hover:opacity-100 transition duration-500" />
<div className="absolute -inset-0.5 bg-gradient-to-r from-slate-200 to-slate-100 rounded-2xl blur opacity-20 group-hover:opacity-100 transition duration-500" />
<div className="relative flex items-center bg-white rounded-2xl border border-slate-200 p-2 shadow-sm transition-all focus-within:ring-2 focus-within:ring-slate-100 focus-within:border-slate-300">
<div className="pl-4 text-slate-400">
<Search className="w-5 h-5" />
<div className="relative flex items-center bg-white rounded-2xl border border-slate-200 p-1.5 md:p-2 shadow-sm transition-all focus-within:ring-2 focus-within:ring-slate-100 focus-within:border-slate-300">
<div className="pl-3 md:pl-4 text-slate-400">
<Search className="w-4 h-4 md:w-5 md:h-5" />
</div>
<input
type="text"
value={searchQuery}
onChange={(e) => onSearchChange(e.target.value)}
placeholder="Search posts..."
className="w-full bg-transparent px-4 py-3 text-lg text-slate-900 placeholder:text-slate-300 outline-none font-bold"
className="w-full bg-transparent px-3 md:px-4 py-2 md:py-3 text-base md:text-lg text-slate-900 placeholder:text-slate-300 outline-none font-bold"
/>
{searchQuery && (
<button
onClick={() => onSearchChange("")}
className="mr-2 px-3 py-1.5 bg-slate-100 hover:bg-slate-200 rounded-lg text-[10px] font-bold uppercase tracking-wider text-slate-500 hover:text-slate-900 transition-colors"
className="mr-2 px-2.5 py-1 md:px-3 md:py-1.5 bg-slate-100 hover:bg-slate-200 rounded-lg text-[9px] md:text-[10px] font-bold uppercase tracking-wider text-slate-500 hover:text-slate-900 transition-colors"
>
Clear
</button>
@@ -56,7 +56,7 @@ export const BlogCommandBar: React.FC<BlogCommandBarProps> = ({
</div>
{/* Tag Command Row */}
<div className="flex flex-wrap items-center justify-center gap-2">
<div className="flex flex-wrap items-center justify-center gap-1.5 md:gap-2 px-4 md:px-0">
{tags.map((tag) => {
const isActive = activeTags.includes(tag);
return (
@@ -64,7 +64,7 @@ export const BlogCommandBar: React.FC<BlogCommandBarProps> = ({
key={tag}
onClick={() => onTagToggle(tag)}
className={cn(
"px-3 py-1.5 rounded-lg text-[10px] font-mono uppercase tracking-wider border transition-all duration-200 select-none",
"px-2.5 py-1 md:px-3 md:py-1.5 rounded-lg text-[9px] md:text-[10px] font-mono uppercase tracking-wider border transition-all duration-200 select-none",
isActive
? "bg-slate-900 text-white border-slate-900 shadow-md transform scale-105"
: "bg-white text-slate-500 border-slate-200 hover:border-slate-400 hover:text-slate-900 hover:bg-slate-50",