879 lines
36 KiB
TypeScript
879 lines
36 KiB
TypeScript
"use client";
|
||
|
||
import { useCallback, useEffect, useRef, useState } from "react";
|
||
import { Button } from "@/components/ui/button";
|
||
import { Calendar, Cookie } from "lucide-react";
|
||
import { colors } from "@/lib/colors";
|
||
import ProtectedAppointmentBooking from "@/components/ProtectedAppointmentBooking";
|
||
import AppointmentStatus from "@/components/AppointmentStatus";
|
||
import PriceCalculator from "@/components/PriceCalculator";
|
||
import SpinningNumbers from "@/components/SpinningNumbers";
|
||
import GlassSurface from "@/components/GlassSurface";
|
||
import LogoLoop from "@/components/LogoLoop";
|
||
import PillNav from "@/components/PillNav";
|
||
import TimelineDemo from "@/components/ui/timeline-demo";
|
||
import { HoverEffect } from "@/components/ui/card-hover-effect";
|
||
import HeroScrollDemo from "@/components/ui/container-scroll-animation-demo";
|
||
import { BackgroundBeams } from "@/components/ui/background-beams";
|
||
import Link from 'next/link';
|
||
|
||
// Scroll animation hook
|
||
const useScrollAnimation = () => {
|
||
const [scrollY, setScrollY] = useState(0);
|
||
|
||
useEffect(() => {
|
||
const handleScroll = () => setScrollY(window.scrollY);
|
||
window.addEventListener('scroll', handleScroll);
|
||
return () => window.removeEventListener('scroll', handleScroll);
|
||
}, []);
|
||
|
||
return scrollY;
|
||
};
|
||
|
||
// Intersection Observer hook for fade-in animations
|
||
const useInView = (threshold = 0.1) => {
|
||
const [isInView, setIsInView] = useState(false);
|
||
const ref = useRef<HTMLDivElement>(null);
|
||
|
||
useEffect(() => {
|
||
const observer = new IntersectionObserver(
|
||
([entry]) => {
|
||
if (entry.isIntersecting) {
|
||
setIsInView(true);
|
||
}
|
||
},
|
||
{ threshold }
|
||
);
|
||
|
||
if (ref.current) {
|
||
observer.observe(ref.current);
|
||
}
|
||
|
||
return () => observer.disconnect();
|
||
}, [threshold]);
|
||
|
||
return [ref, isInView] as const;
|
||
};
|
||
|
||
// Cookie Button Component
|
||
const CookieButton = () => {
|
||
const [showBanner, setShowBanner] = useState(false);
|
||
|
||
const handleAccept = () => {
|
||
setShowBanner(false);
|
||
// Add cookie acceptance logic here
|
||
};
|
||
|
||
return (
|
||
<>
|
||
{/* Cookie Button */}
|
||
<button
|
||
onClick={() => setShowBanner(true)}
|
||
className="fixed bottom-6 left-6 z-50 w-14 h-14 rounded-full flex items-center justify-center shadow-lg transition-all duration-300 hover:scale-110"
|
||
style={{ backgroundColor: colors.secondary }}
|
||
>
|
||
<Cookie className="w-6 h-6 text-white" />
|
||
</button>
|
||
|
||
{/* Cookie Banner */}
|
||
{showBanner && (
|
||
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-4">
|
||
<div
|
||
className="max-w-md w-full p-6 rounded-3xl shadow-2xl"
|
||
style={{ backgroundColor: colors.background }}
|
||
>
|
||
<div className="flex items-center space-x-3 mb-4">
|
||
<Cookie className="w-6 h-6" style={{ color: colors.primary }} />
|
||
<h3 className="text-lg font-semibold" style={{ color: colors.primary }}>
|
||
Cookie-Einstellungen
|
||
</h3>
|
||
</div>
|
||
<p className="mb-6 text-sm" style={{ color: colors.secondary }}>
|
||
Wir verwenden Cookies, um Ihre Erfahrung zu verbessern. Durch die Nutzung unserer Website stimmen Sie unserer Datenschutzrichtlinie zu.
|
||
</p>
|
||
<div className="flex space-x-3">
|
||
<Button
|
||
onClick={handleAccept}
|
||
className="flex-1 rounded-full font-medium"
|
||
style={{
|
||
backgroundColor: colors.primary,
|
||
color: colors.background
|
||
}}
|
||
>
|
||
Akzeptieren
|
||
</Button>
|
||
<Button
|
||
onClick={() => setShowBanner(false)}
|
||
variant="outline"
|
||
className="flex-1 rounded-full"
|
||
style={{
|
||
borderColor: colors.secondary,
|
||
color: colors.secondary
|
||
}}
|
||
>
|
||
Ablehnen
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</>
|
||
);
|
||
};
|
||
|
||
export default function AboutServicePage() {
|
||
const scrollY = useScrollAnimation();
|
||
const [heroRef, heroInView] = useInView();
|
||
const [servicesRef, servicesInView] = useInView();
|
||
const [processRef, processInView] = useInView();
|
||
const [pricingRef, pricingInView] = useInView();
|
||
const [aboutRef, aboutInView] = useInView();
|
||
const [contactRef, contactInView] = useInView();
|
||
const navWrapperRef = useRef<HTMLDivElement>(null);
|
||
const navInnerRef = useRef<HTMLDivElement>(null);
|
||
const [navOffset, setNavOffset] = useState(0);
|
||
const navOffsetRef = useRef(0);
|
||
const navExpandedRef = useRef(false);
|
||
const animationFrameRef = useRef<number | null>(null);
|
||
|
||
useEffect(() => {
|
||
navOffsetRef.current = navOffset;
|
||
}, [navOffset]);
|
||
|
||
useEffect(() => {
|
||
return () => {
|
||
if (animationFrameRef.current) {
|
||
cancelAnimationFrame(animationFrameRef.current);
|
||
}
|
||
};
|
||
}, []);
|
||
|
||
const animateOffset = useCallback((target: number) => {
|
||
if (!Number.isFinite(target)) return;
|
||
if (animationFrameRef.current) {
|
||
cancelAnimationFrame(animationFrameRef.current);
|
||
animationFrameRef.current = null;
|
||
}
|
||
|
||
const startValue = navOffsetRef.current;
|
||
const delta = target - startValue;
|
||
if (Math.abs(delta) < 0.5) {
|
||
navOffsetRef.current = target;
|
||
setNavOffset(target);
|
||
return;
|
||
}
|
||
|
||
const duration = 520;
|
||
const startTime = performance.now();
|
||
|
||
const easeOutCubic = (t: number) => 1 - Math.pow(1 - t, 3);
|
||
|
||
const step = (now: number) => {
|
||
const elapsed = now - startTime;
|
||
const progress = Math.min(elapsed / duration, 1);
|
||
const eased = easeOutCubic(progress);
|
||
const value = startValue + delta * eased;
|
||
navOffsetRef.current = value;
|
||
setNavOffset(value);
|
||
|
||
if (progress < 1) {
|
||
animationFrameRef.current = requestAnimationFrame(step);
|
||
} else {
|
||
animationFrameRef.current = null;
|
||
}
|
||
};
|
||
|
||
animationFrameRef.current = requestAnimationFrame(step);
|
||
}, []);
|
||
|
||
const calculateNavOffset = useCallback(
|
||
(mode: "animate" | "immediate" = "animate", expandedOverride?: boolean) => {
|
||
if (!navWrapperRef.current || !navInnerRef.current) return;
|
||
const expanded = expandedOverride ?? navExpandedRef.current;
|
||
const wrapperWidth = navWrapperRef.current.clientWidth;
|
||
const navWidth = navInnerRef.current.offsetWidth;
|
||
const offset = expanded ? Math.max(0, (wrapperWidth - navWidth) / 2) : 0;
|
||
if (!Number.isFinite(offset)) return;
|
||
if (mode === "immediate") {
|
||
navOffsetRef.current = offset;
|
||
setNavOffset(offset);
|
||
} else {
|
||
animateOffset(offset);
|
||
}
|
||
},
|
||
[animateOffset]
|
||
);
|
||
|
||
useEffect(() => {
|
||
calculateNavOffset("immediate", navExpandedRef.current);
|
||
const handleResize = () => calculateNavOffset("immediate", navExpandedRef.current);
|
||
window.addEventListener("resize", handleResize);
|
||
return () => window.removeEventListener("resize", handleResize);
|
||
}, [calculateNavOffset]);
|
||
|
||
useEffect(() => {
|
||
if (!navInnerRef.current || typeof ResizeObserver === "undefined") return;
|
||
const observer = new ResizeObserver(() => {
|
||
calculateNavOffset("immediate", navExpandedRef.current);
|
||
});
|
||
observer.observe(navInnerRef.current);
|
||
return () => observer.disconnect();
|
||
}, [calculateNavOffset]);
|
||
|
||
useEffect(() => {
|
||
const wrapper = navWrapperRef.current;
|
||
if (!wrapper) return;
|
||
const handleTransitionEnd = (event: TransitionEvent) => {
|
||
if (event.propertyName === "max-width" || event.propertyName === "width" || event.propertyName === "transform") {
|
||
calculateNavOffset(navExpandedRef.current ? "animate" : "immediate", navExpandedRef.current);
|
||
}
|
||
};
|
||
wrapper.addEventListener("transitionend", handleTransitionEnd);
|
||
return () => wrapper.removeEventListener("transitionend", handleTransitionEnd);
|
||
}, [calculateNavOffset]);
|
||
|
||
// Partner Logos für LogoLoop
|
||
const partnerLogos = [
|
||
{
|
||
node: (
|
||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '8px' }}>
|
||
<svg viewBox="0 0 48 48" fill="none" width={96} height={96} xmlns="http://www.w3.org/2000/svg">
|
||
{/* Traefik - Reverse Proxy mit drei Punkten */}
|
||
<circle cx="16" cy="16" r="4" fill={colors.background}/>
|
||
<circle cx="24" cy="24" r="4" fill={colors.background}/>
|
||
<circle cx="32" cy="32" r="4" fill={colors.background}/>
|
||
<path d="M16 16L24 24M24 24L32 32" stroke={colors.background} strokeWidth="2" strokeLinecap="round"/>
|
||
<path d="M12 24L24 12L36 24" stroke={colors.background} strokeWidth="2" opacity="0.5"/>
|
||
</svg>
|
||
<span style={{ color: colors.background, fontSize: '14px', fontWeight: '600', whiteSpace: 'nowrap' }}>Traefik</span>
|
||
</div>
|
||
),
|
||
title: "Traefik",
|
||
href: "https://traefik.io"
|
||
},
|
||
{
|
||
node: (
|
||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '8px' }}>
|
||
<svg viewBox="0 0 48 48" fill="none" width={96} height={96} xmlns="http://www.w3.org/2000/svg">
|
||
{/* Porkbun - Domain/Globe */}
|
||
<circle cx="24" cy="24" r="16" stroke={colors.background} strokeWidth="3"/>
|
||
<path d="M8 24C8 18 12 14 24 14C36 14 40 18 40 24C40 30 36 34 24 34C12 34 8 30 8 24Z" stroke={colors.background} strokeWidth="2"/>
|
||
<path d="M24 8C24 8 18 14 18 20C18 26 24 32 24 32" stroke={colors.background} strokeWidth="2"/>
|
||
</svg>
|
||
<span style={{ color: colors.background, fontSize: '14px', fontWeight: '600', whiteSpace: 'nowrap' }}>Porkbun</span>
|
||
</div>
|
||
),
|
||
title: "Porkbun",
|
||
href: "https://porkbun.com"
|
||
},
|
||
{
|
||
node: (
|
||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '8px' }}>
|
||
<svg viewBox="0 0 48 48" fill="none" width={96} height={96} xmlns="http://www.w3.org/2000/svg">
|
||
{/* n8n - Workflow Nodes */}
|
||
<circle cx="16" cy="16" r="5" fill={colors.background}/>
|
||
<circle cx="32" cy="16" r="5" fill={colors.background}/>
|
||
<circle cx="16" cy="32" r="5" fill={colors.background}/>
|
||
<circle cx="32" cy="32" r="5" fill={colors.background}/>
|
||
<path d="M21 16L27 16M16 21L16 27M21 32L27 32" stroke={colors.background} strokeWidth="2" strokeLinecap="round"/>
|
||
</svg>
|
||
<span style={{ color: colors.background, fontSize: '14px', fontWeight: '600', whiteSpace: 'nowrap' }}>n8n</span>
|
||
</div>
|
||
),
|
||
title: "n8n",
|
||
href: "https://n8n.io"
|
||
},
|
||
{
|
||
node: (
|
||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '8px' }}>
|
||
<svg viewBox="0 0 48 48" fill="none" width={96} height={96} xmlns="http://www.w3.org/2000/svg">
|
||
{/* Mistral AI - Wind/Wave */}
|
||
<path d="M8 24Q16 16 24 24T40 24" stroke={colors.background} strokeWidth="3" strokeLinecap="round" fill="none"/>
|
||
<path d="M10 28Q18 20 26 28T42 28" stroke={colors.background} strokeWidth="3" strokeLinecap="round" fill="none" opacity="0.7"/>
|
||
<circle cx="24" cy="24" r="2" fill={colors.background} opacity="0.5"/>
|
||
</svg>
|
||
<span style={{ color: colors.background, fontSize: '14px', fontWeight: '600', whiteSpace: 'nowrap' }}>Mistral AI</span>
|
||
</div>
|
||
),
|
||
title: "Mistral AI",
|
||
href: "https://mistral.ai"
|
||
},
|
||
{
|
||
node: (
|
||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '8px' }}>
|
||
<svg viewBox="0 0 48 48" fill="none" width={96} height={96} xmlns="http://www.w3.org/2000/svg">
|
||
{/* Hetzner - Server/Cloud */}
|
||
<rect x="12" y="14" width="24" height="20" rx="2" stroke={colors.background} strokeWidth="3"/>
|
||
<path d="M16 20H32M16 24H32M16 28H28" stroke={colors.background} strokeWidth="2" strokeLinecap="round"/>
|
||
<circle cx="36" cy="18" r="3" fill={colors.background}/>
|
||
</svg>
|
||
<span style={{ color: colors.background, fontSize: '14px', fontWeight: '600', whiteSpace: 'nowrap' }}>Hetzner</span>
|
||
</div>
|
||
),
|
||
title: "Hetzner",
|
||
href: "https://www.hetzner.com"
|
||
},
|
||
{
|
||
node: (
|
||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '8px' }}>
|
||
<svg viewBox="0 0 48 48" fill="none" width={96} height={96} xmlns="http://www.w3.org/2000/svg">
|
||
{/* Cursor - Code Editor */}
|
||
<rect x="12" y="12" width="24" height="24" rx="4" stroke={colors.background} strokeWidth="3"/>
|
||
<path d="M18 20L24 24L18 28" stroke={colors.background} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
|
||
<path d="M28 20L30 24L28 28" stroke={colors.background} strokeWidth="2" strokeLinecap="round"/>
|
||
</svg>
|
||
<span style={{ color: colors.background, fontSize: '14px', fontWeight: '600', whiteSpace: 'nowrap' }}>Cursor</span>
|
||
</div>
|
||
),
|
||
title: "Cursor AI",
|
||
href: "https://cursor.sh"
|
||
},
|
||
{
|
||
node: (
|
||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '8px' }}>
|
||
<svg viewBox="0 0 48 48" fill="none" width={96} height={96} xmlns="http://www.w3.org/2000/svg">
|
||
{/* Appwrite - Database/Backend */}
|
||
<rect x="14" y="10" width="20" height="28" rx="2" stroke={colors.background} strokeWidth="3"/>
|
||
<path d="M14 18H34M14 24H34M14 30H28" stroke={colors.background} strokeWidth="2" strokeLinecap="round"/>
|
||
<circle cx="32" cy="14" r="2" fill={colors.background}/>
|
||
</svg>
|
||
<span style={{ color: colors.background, fontSize: '14px', fontWeight: '600', whiteSpace: 'nowrap' }}>Appwrite</span>
|
||
</div>
|
||
),
|
||
title: "Appwrite",
|
||
href: "https://appwrite.io"
|
||
}
|
||
];
|
||
|
||
const valueProps = [
|
||
{
|
||
title: "Zeitersparnis",
|
||
description: "Wir übernehmen den digitalen Teil, Sie konzentrieren sich aufs Geschäft",
|
||
link: "#zeitersparnis"
|
||
},
|
||
{
|
||
title: "Kompetenz & Erfahrung",
|
||
description: "Technisch stark, klar in der Umsetzung",
|
||
link: "#kompetenz-erfahrung"
|
||
},
|
||
{
|
||
title: "Maßgeschneiderte Lösungen",
|
||
description: "Keine Templates, sondern individuelle Umsetzung",
|
||
link: "#massgeschneiderte-loesungen"
|
||
},
|
||
{
|
||
title: "Stressfreies Webmanagement",
|
||
description: "Ein Ansprechpartner für alles",
|
||
link: "#stressfreies-webmanagement"
|
||
}
|
||
];
|
||
|
||
const navIsExpanded = scrollY > 40;
|
||
|
||
const previousNavState = useRef(navIsExpanded);
|
||
|
||
useEffect(() => {
|
||
const previous = previousNavState.current;
|
||
previousNavState.current = navIsExpanded;
|
||
navExpandedRef.current = navIsExpanded;
|
||
|
||
let raf1: number | null = null;
|
||
let raf2: number | null = null;
|
||
let timeoutId: number | null = null;
|
||
|
||
if (navIsExpanded) {
|
||
if (previous === false) {
|
||
raf1 = requestAnimationFrame(() => {
|
||
calculateNavOffset("animate", true);
|
||
});
|
||
raf2 = requestAnimationFrame(() => {
|
||
calculateNavOffset("animate", true);
|
||
});
|
||
timeoutId = window.setTimeout(() => {
|
||
calculateNavOffset("animate", true);
|
||
}, 320);
|
||
} else {
|
||
calculateNavOffset("immediate", true);
|
||
}
|
||
} else {
|
||
animateOffset(0);
|
||
}
|
||
|
||
return () => {
|
||
if (raf1 !== null) cancelAnimationFrame(raf1);
|
||
if (raf2 !== null) cancelAnimationFrame(raf2);
|
||
if (timeoutId !== null) window.clearTimeout(timeoutId);
|
||
};
|
||
}, [navIsExpanded, calculateNavOffset, animateOffset]);
|
||
|
||
return (
|
||
<>
|
||
<div className="min-h-screen overflow-hidden" style={{ backgroundColor: colors.background }}>
|
||
{/* Fixed Navigation mit PillNav */}
|
||
<div
|
||
className="fixed left-0 right-0 z-40 px-4 top-4 transition-all duration-500"
|
||
style={{
|
||
transitionTimingFunction: "cubic-bezier(0.22, 1, 0.36, 1)"
|
||
}}
|
||
>
|
||
<div
|
||
className="w-full mx-auto transition-all duration-500 ease-out"
|
||
style={{
|
||
maxWidth: navIsExpanded ? "72rem" : "38rem",
|
||
width: navIsExpanded ? "100%" : "96%"
|
||
}}
|
||
>
|
||
<GlassSurface
|
||
width="100%"
|
||
height="auto"
|
||
borderRadius={9999}
|
||
displace={2.0}
|
||
backgroundOpacity={0.3}
|
||
className="w-full transition-all duration-500 ease-out"
|
||
style={{
|
||
minHeight: '70px',
|
||
backgroundColor: `${colors.secondary}66`,
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
padding: '0.5rem 1.5rem',
|
||
transition: 'backdrop-filter 0.45s ease'
|
||
}}
|
||
>
|
||
<div
|
||
ref={navWrapperRef}
|
||
className="relative w-full flex items-center justify-center transition-all duration-500"
|
||
style={{
|
||
transitionTimingFunction: "cubic-bezier(0.22, 1, 0.36, 1)"
|
||
}}
|
||
>
|
||
{/* PillNav mit den Nav-Links */}
|
||
<div
|
||
ref={navInnerRef}
|
||
className="inline-flex transition-all duration-500"
|
||
style={{
|
||
transform: navIsExpanded ? `translateX(-${navOffset}px)` : "translateX(0)",
|
||
transitionTimingFunction: "cubic-bezier(0.22, 1, 0.36, 1)"
|
||
}}
|
||
>
|
||
<PillNav
|
||
logo="/WebKlarLogo.png"
|
||
logoAlt="Webklar Logo"
|
||
items={[
|
||
{ label: 'Über uns', href: '#about' },
|
||
{ label: 'Leistungen', href: '#services' },
|
||
{ label: 'Unsere Abläufe', href: '#process' }
|
||
]}
|
||
activeHref="#"
|
||
baseColor={colors.secondary}
|
||
pillColor={colors.background}
|
||
hoveredPillTextColor={colors.background}
|
||
pillTextColor={colors.primary}
|
||
className="pill-nav-custom"
|
||
/>
|
||
</div>
|
||
{/* Kontakt-Button rechts */}
|
||
<div
|
||
className="hidden md:block absolute right-0 transition-all duration-500 overflow-hidden"
|
||
style={{
|
||
opacity: navIsExpanded ? 1 : 0,
|
||
maxWidth: navIsExpanded ? "200px" : "0px",
|
||
pointerEvents: navIsExpanded ? "auto" : "none",
|
||
transform: navIsExpanded ? "translateX(0)" : "translateX(16px)",
|
||
transitionTimingFunction: "cubic-bezier(0.22, 1, 0.36, 1)"
|
||
}}
|
||
>
|
||
<Link href="/kontakte">
|
||
<Button className="rounded-full text-sm font-semibold px-3 sm:px-5 py-1.5 shadow-lg hover:shadow-xl transition-all duration-300 hover:scale-105 btn-enhanced pulse-glow" style={{ backgroundColor: colors.primary, color: colors.background }}>
|
||
Kontakt
|
||
</Button>
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
</GlassSurface>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Background Video Hero Section */}
|
||
<section id="hero" className="relative h-screen flex items-center justify-center overflow-hidden">
|
||
{/* Video Background */}
|
||
<div className="absolute inset-0 z-0">
|
||
<video
|
||
autoPlay
|
||
muted
|
||
loop
|
||
playsInline
|
||
className="w-full h-full object-cover"
|
||
style={{ filter: 'blur(8px)' }}
|
||
>
|
||
<source src="/path/to/your/background-video.mp4" type="video/mp4" />
|
||
</video>
|
||
<div
|
||
className="absolute inset-0 backdrop-blur-sm"
|
||
style={{
|
||
background: `linear-gradient(135deg, ${colors.primary}CC, ${colors.secondary}CC)`
|
||
}}
|
||
></div>
|
||
</div>
|
||
|
||
|
||
|
||
<div ref={heroRef} className="relative z-20 px-4 sm:px-8 pt-24 sm:pt-28 pb-20 sm:pb-24 max-w-7xl mx-auto text-center">
|
||
<h1 className={`text-4xl sm:text-6xl md:text-8xl font-bold mb-6 sm:mb-8 transition-all duration-1000 ${
|
||
heroInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'
|
||
}`}>
|
||
<span style={{ color: colors.background }}>
|
||
webklar – das Web maßgeschneidert auf Ihr Unternehmen
|
||
</span>
|
||
</h1>
|
||
|
||
<div className={`flex flex-wrap justify-center gap-2 sm:gap-4 mb-8 sm:mb-12 text-xs sm:text-sm mt-6 transition-all duration-1000 delay-300 ${
|
||
heroInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'
|
||
}`}>
|
||
{['Strategieberatung', 'UX/UI Design', 'Entwicklung', 'SEO & Support'].map((item) => (
|
||
<span
|
||
key={item}
|
||
className="px-3 sm:px-4 py-2 rounded-full backdrop-blur-sm border"
|
||
style={{
|
||
backgroundColor: `${colors.background}80`,
|
||
borderColor: colors.tertiary,
|
||
color: colors.primary
|
||
}}
|
||
>
|
||
{item}
|
||
</span>
|
||
))}
|
||
</div>
|
||
|
||
<div className={`flex flex-col sm:flex-row items-center justify-center gap-4 sm:gap-6 transition-all duration-1000 delay-500 ${
|
||
heroInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'
|
||
}`}>
|
||
<Button
|
||
onClick={() => document.getElementById('contact')?.scrollIntoView({ behavior: 'smooth' })}
|
||
className="w-full sm:w-auto px-6 sm:px-8 py-3 sm:py-4 rounded-full flex items-center justify-center space-x-3 text-base sm:text-lg font-semibold shadow-2xl hover:shadow-3xl transition-all duration-300 hover:scale-105 btn-enhanced hover-lift"
|
||
style={{
|
||
backgroundColor: colors.background,
|
||
color: colors.primary
|
||
}}
|
||
>
|
||
<Calendar className="w-5 sm:w-6 h-5 sm:h-6" />
|
||
<span>Kostenlosen Termin buchen</span>
|
||
</Button>
|
||
</div>
|
||
|
||
{/* Partner Tools */}
|
||
<div className="mt-8 sm:mt-12 px-4 sm:px-8">
|
||
<div style={{ position: 'relative', overflow: 'visible', maxWidth: '100%' }} className="logo-loop-container">
|
||
<div style={{ height: '180px', position: 'relative', width: '100%', paddingBottom: '30px', overflow: 'hidden' }} className="logo-loop-inner">
|
||
<LogoLoop
|
||
logos={partnerLogos}
|
||
speed={60}
|
||
direction="left"
|
||
logoHeight={140}
|
||
gap={100}
|
||
pauseOnHover
|
||
scaleOnHover
|
||
ariaLabel="Technology partners"
|
||
style={{ width: '100%' }}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* About Section */}
|
||
<section
|
||
id="about"
|
||
ref={aboutRef}
|
||
className="relative px-4 sm:px-8 py-12 sm:py-20 rounded-t-[2rem] sm:rounded-t-[3rem] rounded-b-[2rem] sm:rounded-b-[3rem] mx-2 sm:mx-4 backdrop-blur-sm"
|
||
style={{ backgroundColor: `${colors.background}F0`, position: 'relative', zIndex: 10 }}
|
||
>
|
||
<div className="max-w-7xl mx-auto">
|
||
<div className="grid lg:grid-cols-2 gap-8 sm:gap-16 items-center">
|
||
{/* Links: Spinning Numbers */}
|
||
<div className="relative order-2 lg:order-1">
|
||
<SpinningNumbers />
|
||
</div>
|
||
|
||
{/* Rechts: Text im Zeitungsstil (mehrspaltig) */}
|
||
<div className={`order-1 lg:order-2 transition-all duration-1000 w-full flex flex-col justify-center ${
|
||
aboutInView ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-10'
|
||
}`}>
|
||
<h2 className="text-3xl sm:text-5xl md:text-6xl font-bold mb-6 sm:mb-8 leading-tight whitespace-nowrap" style={{ color: colors.primary }}>
|
||
<span className="inline-block">Worauf wir</span>{" "}
|
||
<span className="inline-block">Wert</span>{" "}
|
||
<span className="inline-block">legen</span>
|
||
</h2>
|
||
|
||
<div
|
||
className="text-xl sm:text-2xl md:text-3xl leading-relaxed"
|
||
style={{
|
||
color: colors.secondary,
|
||
width: '100%',
|
||
maxWidth: '100%',
|
||
columnCount: 1,
|
||
columnGap: '3rem',
|
||
columnFill: 'balance',
|
||
textAlign: 'justify'
|
||
}}
|
||
>
|
||
Sicherheit ist für uns keine Nebensache, sondern die Grundlage jeder Website. Wir setzen auf moderne Technologien, zertifizierte Partner und höchste Datenschutzstandards. Unsere Systeme sind darauf ausgelegt, Ausfälle zu vermeiden und langfristig stabile Ergebnisse zu liefern – damit Ihre Online-Präsenz so zuverlässig ist wie Ihr Unternehmen selbst.
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Services Grid */}
|
||
<section
|
||
id="services"
|
||
ref={servicesRef}
|
||
className="relative overflow-hidden px-4 sm:px-8 py-12 sm:py-20 rounded-t-[2rem] sm:rounded-t-[3rem] rounded-b-[2rem] sm:rounded-b-[3rem] mx-2 sm:mx-4 backdrop-blur-sm"
|
||
style={{ backgroundColor: colors.primary }}
|
||
>
|
||
<BackgroundBeams className="opacity-70 mix-blend-screen pointer-events-none" />
|
||
<div className="pointer-events-none absolute inset-0 bg-gradient-to-b from-black/30 via-transparent to-black/70" />
|
||
|
||
<div className="relative z-10 max-w-7xl mx-auto">
|
||
<div className="text-center mb-12 sm:mb-16">
|
||
<h2 className={`text-3xl sm:text-5xl md:text-6xl font-bold mb-4 sm:mb-6 transition-all duration-1000 bg-clip-text text-transparent bg-gradient-to-b from-neutral-50/90 via-neutral-200/80 to-neutral-400/70 ${
|
||
servicesInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'
|
||
}`}>
|
||
Unsere Leistungen
|
||
</h2>
|
||
<p className={`text-lg sm:text-xl transition-all duration-1000 delay-200 text-neutral-100/80 ${
|
||
servicesInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'
|
||
}`}>
|
||
Alles aus einer Hand für Ihren digitalen Erfolg
|
||
</p>
|
||
</div>
|
||
|
||
<div
|
||
className={`relative z-10 transition-all duration-1000 ${
|
||
servicesInView ? "opacity-100 translate-y-0" : "opacity-0 translate-y-10"
|
||
}`}
|
||
>
|
||
<HeroScrollDemo />
|
||
</div>
|
||
|
||
</div>
|
||
</section>
|
||
|
||
{/* Process Section */}
|
||
<section
|
||
id="process"
|
||
ref={processRef}
|
||
className="relative px-4 sm:px-8 py-12 sm:py-20 rounded-t-[2rem] sm:rounded-t-[3rem] rounded-b-[2rem] sm:rounded-b-[3rem] mx-2 sm:mx-4 backdrop-blur-sm"
|
||
style={{ backgroundColor: `${colors.background}F0` }}
|
||
>
|
||
<div className="max-w-6xl mx-auto">
|
||
<div className="text-center mb-12 sm:mb-16">
|
||
<h2 className={`text-3xl sm:text-5xl md:text-6xl font-bold mb-4 sm:mb-6 transition-all duration-1000 ${
|
||
processInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'
|
||
}`} style={{ color: colors.primary }}>
|
||
Unser Ablauf
|
||
</h2>
|
||
<p className={`text-lg sm:text-xl transition-all duration-1000 delay-200 ${
|
||
processInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'
|
||
}`} style={{ color: colors.secondary }}>
|
||
So läuft die Zusammenarbeit ab
|
||
</p>
|
||
</div>
|
||
|
||
<div
|
||
className="rounded-[32px] px-2 py-10 sm:px-6 sm:py-16 transition-all duration-700"
|
||
style={{
|
||
background: `linear-gradient(135deg, ${colors.background}F2, ${colors.background}E8)`
|
||
}}
|
||
>
|
||
<TimelineDemo />
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Pricing Section */}
|
||
<section
|
||
id="references"
|
||
ref={pricingRef}
|
||
className="relative px-4 sm:px-8 py-12 sm:py-20 rounded-t-[2rem] sm:rounded-t-[3rem] rounded-b-[2rem] sm:rounded-b-[3rem] mx-2 sm:mx-4 backdrop-blur-sm"
|
||
style={{ backgroundColor: `${colors.primary}F0` }}
|
||
>
|
||
<div className="max-w-4xl mx-auto text-center">
|
||
<div className="mb-12 sm:mb-16">
|
||
<h2 className={`text-3xl sm:text-5xl md:text-6xl font-bold mb-4 sm:mb-6 transition-all duration-1000 ${
|
||
pricingInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'
|
||
}`} style={{ color: colors.tertiary }}>
|
||
Faire Preise
|
||
</h2>
|
||
<p className={`text-lg sm:text-xl transition-all duration-1000 delay-200 ${
|
||
pricingInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'
|
||
}`} style={{ color: colors.background }}>
|
||
Transparent und flexibel
|
||
</p>
|
||
</div>
|
||
|
||
<div className={`p-8 sm:p-12 rounded-3xl shadow-2xl backdrop-blur-sm transition-all duration-1000 delay-300 ${
|
||
pricingInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'
|
||
}`} style={{ backgroundColor: `${colors.background}F0` }}>
|
||
<h3 className="text-2xl sm:text-3xl font-bold mb-6" style={{ color: colors.primary }}>
|
||
Individuelle Lösungen
|
||
</h3>
|
||
<p className="text-lg sm:text-xl mb-8 leading-relaxed" style={{ color: colors.secondary }}>
|
||
Unsere Preise richten sich nach dem Projektumfang und Ihren Anforderungen.
|
||
Gemeinsam finden wir eine Lösung, die zu Ihrem Budget passt – transparent, fair und flexibel.
|
||
</p>
|
||
<PriceCalculator />
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Target Groups & Value Props */}
|
||
<section
|
||
className="relative px-4 sm:px-8 py-12 sm:py-20 rounded-t-[2rem] sm:rounded-t-[3rem] rounded-b-[2rem] sm:rounded-b-[3rem] mx-2 sm:mx-4 backdrop-blur-sm"
|
||
style={{ backgroundColor: `${colors.background}F0` }}
|
||
>
|
||
<div className="max-w-7xl mx-auto">
|
||
<div className="grid lg:grid-cols-2 gap-12 sm:gap-16">
|
||
{/* Target Groups */}
|
||
<div>
|
||
<h2 className="text-2xl sm:text-4xl font-bold mb-6 sm:mb-8" style={{ color: colors.primary }}>
|
||
Für wen wir arbeiten
|
||
</h2>
|
||
<p className="text-lg sm:text-xl leading-relaxed" style={{ color: colors.secondary }}>
|
||
Wir arbeiten mit Unternehmen, die ihre veraltete Website modernisieren oder ihre Zeit nicht mehr mit Technik und Support verschwenden wollen.
|
||
</p>
|
||
</div>
|
||
|
||
{/* Value Props */}
|
||
<div>
|
||
<h2 className="text-2xl sm:text-4xl font-bold mb-6 sm:mb-8" style={{ color: colors.primary }}>
|
||
Warum wir das tun
|
||
</h2>
|
||
<div
|
||
className="rounded-3xl border shadow-sm"
|
||
style={{
|
||
background: `linear-gradient(135deg, ${colors.background}F5, ${colors.tertiary}1A)`,
|
||
borderColor: `${colors.secondary}55`
|
||
}}
|
||
>
|
||
<div className="p-4 sm:p-8">
|
||
<HoverEffect
|
||
items={valueProps}
|
||
className="py-2"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Contact Section */}
|
||
<section
|
||
ref={contactRef}
|
||
id="contact"
|
||
className="relative px-4 sm:px-8 py-12 sm:py-20 rounded-t-[2rem] sm:rounded-t-[3rem] rounded-b-[2rem] sm:rounded-b-[3rem] mx-2 sm:mx-4 backdrop-blur-sm"
|
||
style={{ backgroundColor: colors.secondary }}
|
||
>
|
||
<div className="max-w-4xl mx-auto">
|
||
<div className="text-center mb-12 sm:mb-16">
|
||
<h2
|
||
className="text-3xl sm:text-5xl md:text-6xl font-bold mb-4 sm:mb-6"
|
||
style={{ color: colors.background }}
|
||
>
|
||
Lassen Sie uns sprechen
|
||
</h2>
|
||
<p
|
||
className="text-lg sm:text-xl opacity-90"
|
||
style={{ color: colors.background }}
|
||
>
|
||
Erzählen Sie uns von Ihrem Projekt
|
||
</p>
|
||
</div>
|
||
|
||
<div className={`transition-all duration-1000 ${
|
||
contactInView ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'
|
||
}`}>
|
||
<ProtectedAppointmentBooking />
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Footer */}
|
||
<footer
|
||
className="relative py-8 sm:py-12 border-t rounded-t-[2rem] sm:rounded-t-[3rem] mx-2 sm:mx-4 backdrop-blur-sm"
|
||
style={{
|
||
backgroundColor: `${colors.primary}F0`,
|
||
borderColor: colors.secondary
|
||
}}
|
||
>
|
||
<div className="max-w-7xl mx-auto px-4 sm:px-8">
|
||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-6 sm:gap-8">
|
||
<div className="col-span-1 sm:col-span-2">
|
||
<div
|
||
className="text-2xl sm:text-3xl font-bold mb-4 relative"
|
||
style={{ color: colors.tertiary }}
|
||
>
|
||
<span className="relative z-10">Webklar</span>
|
||
<div
|
||
className="absolute -inset-2 rounded-xl blur-sm opacity-20"
|
||
style={{ backgroundColor: colors.secondary }}
|
||
></div>
|
||
</div>
|
||
<p
|
||
className="mb-6 leading-relaxed text-sm sm:text-base"
|
||
style={{ color: colors.background }}
|
||
>
|
||
Ihr Partner für Web & Support. Moderne Websites. Klare Kommunikation. Persönlicher Support.
|
||
</p>
|
||
</div>
|
||
<div>
|
||
<h4 className="text-base sm:text-lg font-semibold mb-4" style={{ color: colors.tertiary }}>
|
||
Services
|
||
</h4>
|
||
<ul className="space-y-2 text-sm sm:text-base" style={{ color: colors.background }}>
|
||
{['Webdesign', 'E-Commerce', 'SEO', 'Hosting'].map((item) => (
|
||
<li key={item}>
|
||
<a href="#" className="hover:opacity-80 transition-opacity">{item}</a>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
<div>
|
||
<h4 className="text-base sm:text-lg font-semibold mb-4" style={{ color: colors.tertiary }}>
|
||
Kontakt
|
||
</h4>
|
||
<ul className="space-y-2 text-sm sm:text-base" style={{ color: colors.background }}>
|
||
<li><Link href="/impressum" className="hover:opacity-80 transition-opacity">Impressum</Link></li>
|
||
<li><Link href="/datenschutz" className="hover:opacity-80 transition-opacity">Datenschutz</Link></li>
|
||
<li><Link href="/agb" className="hover:opacity-80 transition-opacity">AGB</Link></li>
|
||
<li><Link href="/kontakte" className="hover:opacity-80 transition-opacity">Kontakte</Link></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div
|
||
className="border-t mt-6 sm:mt-8 pt-6 sm:pt-8 text-center text-sm"
|
||
style={{
|
||
borderColor: colors.secondary,
|
||
color: colors.background
|
||
}}
|
||
>
|
||
<p>© 2025 Webklar. Alle Rechte vorbehalten.</p>
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
|
||
{/* Film Grain Effect */}
|
||
|
||
|
||
{/* Cookie Button */}
|
||
<CookieButton />
|
||
|
||
{/* Appointment Status */}
|
||
<AppointmentStatus />
|
||
</div>
|
||
</>
|
||
);
|
||
}
|