wip
This commit is contained in:
@@ -37,23 +37,36 @@ export default async function StandardPage({ params: { locale, slug } }: PagePro
|
||||
<Section className="bg-white -mt-8 md:-mt-12 relative z-20 rounded-t-[32px] md:rounded-t-[60px] shadow-2xl py-12 md:py-28">
|
||||
<Container>
|
||||
<div className="sticky-narrative-container">
|
||||
{/* Sticky Narrative Sidebar */}
|
||||
{/* Sticky Narrative Sidebar - Mobile Optimized */}
|
||||
<div className="sticky-narrative-sidebar mb-8 lg:mb-0">
|
||||
<div className="lg:sticky lg:top-32 space-y-4 md:space-y-8">
|
||||
<div className="p-6 md:p-8 bg-neutral-light rounded-2xl md:rounded-3xl border border-neutral-medium">
|
||||
<h3 className="text-lg md:text-xl font-bold text-primary mb-3 md:mb-4">Quick Navigation</h3>
|
||||
{/* Mobile-only chip/stepper feel */}
|
||||
<div className="flex lg:hidden overflow-x-auto pb-4 gap-3 no-scrollbar -mx-4 px-4">
|
||||
<Badge variant="primary" className="whitespace-nowrap px-4 py-2 rounded-full shadow-sm">Overview</Badge>
|
||||
<Badge variant="neutral" className="whitespace-nowrap px-4 py-2 rounded-full shadow-sm opacity-60">Details</Badge>
|
||||
<Badge variant="neutral" className="whitespace-nowrap px-4 py-2 rounded-full shadow-sm opacity-60">Support</Badge>
|
||||
</div>
|
||||
|
||||
<div className="p-6 md:p-8 bg-neutral-light rounded-2xl md:rounded-3xl border border-neutral-medium shadow-sm">
|
||||
<h3 className="text-lg md:text-xl font-bold text-primary mb-3 md:mb-4 flex items-center gap-2">
|
||||
<span className="w-1.5 h-6 bg-accent rounded-full" />
|
||||
Quick Navigation
|
||||
</h3>
|
||||
<nav className="space-y-3 md:space-y-4">
|
||||
<div className="h-1 w-10 md:w-12 bg-accent rounded-full" />
|
||||
<p className="text-sm md:text-base text-text-secondary leading-relaxed">
|
||||
Explore the details of {pageData.frontmatter.title}. KLZ provides comprehensive information on all our services and corporate policies.
|
||||
</p>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div className="p-6 md:p-8 bg-primary-dark rounded-2xl md:rounded-3xl text-white">
|
||||
<h3 className="text-lg md:text-xl font-bold mb-3 md:mb-4">Need Help?</h3>
|
||||
<p className="text-sm md:text-base text-white/70 mb-4 md:mb-6">Our support team is available for any questions regarding this topic.</p>
|
||||
<a href={`/${locale}/contact`} className="text-accent font-bold hover:underline touch-target">Contact Us →</a>
|
||||
<div className="p-6 md:p-8 bg-primary-dark rounded-2xl md:rounded-3xl text-white shadow-xl relative overflow-hidden group">
|
||||
<div className="absolute top-0 right-0 w-24 h-full bg-accent/5 -skew-x-12 translate-x-1/2 transition-transform group-hover:translate-x-1/3" />
|
||||
<h3 className="text-lg md:text-xl font-bold mb-3 md:mb-4 relative z-10">Need Help?</h3>
|
||||
<p className="text-sm md:text-base text-white/70 mb-4 md:mb-6 relative z-10">Our support team is available for any questions regarding this topic.</p>
|
||||
<a href={`/${locale}/contact`} className="inline-flex items-center text-accent font-bold hover:underline touch-target relative z-10 group/link">
|
||||
Contact Us
|
||||
<span className="ml-2 transition-transform group-hover/link:translate-x-1">→</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,6 @@ interface BlogPostProps {
|
||||
}
|
||||
|
||||
import Link from 'next/link';
|
||||
import Image from 'next/image';
|
||||
import VisualLinkPreview from '@/components/blog/VisualLinkPreview';
|
||||
import Callout from '@/components/blog/Callout';
|
||||
import HighlightBox from '@/components/blog/HighlightBox';
|
||||
@@ -20,6 +19,7 @@ import ChatBubble from '@/components/blog/ChatBubble';
|
||||
import SplitHeading from '@/components/blog/SplitHeading';
|
||||
import PostNavigation from '@/components/blog/PostNavigation';
|
||||
import PowerCTA from '@/components/blog/PowerCTA';
|
||||
import ShareButton from '@/components/blog/ShareButton';
|
||||
|
||||
const components = {
|
||||
VisualLinkPreview,
|
||||
@@ -187,6 +187,14 @@ export default async function BlogPost({ params: { locale, slug } }: BlogPostPro
|
||||
</time>
|
||||
<span className="w-1.5 h-1.5 bg-primary rounded-full" />
|
||||
<span>KLZ Cables</span>
|
||||
<div className="ml-auto hidden md:block">
|
||||
<ShareButton
|
||||
title={post.frontmatter.title}
|
||||
text={post.frontmatter.excerpt || ''}
|
||||
url={`https://klz-cables.com/${locale}/blog/${slug}`}
|
||||
locale={locale}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -195,6 +203,15 @@ export default async function BlogPost({ params: { locale, slug } }: BlogPostPro
|
||||
|
||||
{/* Content */}
|
||||
<div className="container mx-auto px-4 py-16 md:py-24 max-w-3xl">
|
||||
{/* Mobile Share Button */}
|
||||
<div className="md:hidden mb-8 flex justify-end">
|
||||
<ShareButton
|
||||
title={post.frontmatter.title}
|
||||
text={post.frontmatter.excerpt || ''}
|
||||
url={`https://klz-cables.com/${locale}/blog/${slug}`}
|
||||
locale={locale}
|
||||
/>
|
||||
</div>
|
||||
{/* If no featured image, show header here */}
|
||||
{!post.frontmatter.featuredImage && (
|
||||
<header className="mb-16 text-center">
|
||||
|
||||
@@ -101,8 +101,12 @@ export default function ContactPage() {
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
name="name"
|
||||
autoComplete="name"
|
||||
enterKeyHint="next"
|
||||
className="w-full px-4 md:px-6 py-2.5 md:py-4 bg-neutral rounded-xl md:rounded-2xl border-2 border-transparent focus:border-primary focus:bg-white transition-all outline-none text-sm md:text-lg"
|
||||
placeholder="Your Name"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1 md:space-y-2">
|
||||
@@ -110,21 +114,29 @@ export default function ContactPage() {
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
autoComplete="email"
|
||||
inputMode="email"
|
||||
enterKeyHint="next"
|
||||
className="w-full px-4 md:px-6 py-2.5 md:py-4 bg-neutral rounded-xl md:rounded-2xl border-2 border-transparent focus:border-primary focus:bg-white transition-all outline-none text-sm md:text-lg"
|
||||
placeholder="your@email.com"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="md:col-span-2 space-y-1 md:space-y-2">
|
||||
<label htmlFor="message" className="text-[10px] md:text-xs font-extrabold text-primary uppercase tracking-widest">{t('form.message')}</label>
|
||||
<textarea
|
||||
id="message"
|
||||
name="message"
|
||||
rows={4}
|
||||
enterKeyHint="send"
|
||||
className="w-full px-4 md:px-6 py-2.5 md:py-4 bg-neutral rounded-xl md:rounded-2xl border-2 border-transparent focus:border-primary focus:bg-white transition-all outline-none text-sm md:text-lg resize-none"
|
||||
placeholder="How can we help you?"
|
||||
required
|
||||
></textarea>
|
||||
</div>
|
||||
<div className="md:col-span-2 pt-2 md:pt-4">
|
||||
<Button type="submit" size="lg" className="w-full shadow-xl shadow-primary/20 md:h-16 md:px-10 md:text-xl">
|
||||
<Button type="submit" size="lg" className="w-full shadow-xl shadow-primary/20 md:h-16 md:px-10 md:text-xl active:scale-[0.98] transition-transform">
|
||||
{t('form.submit')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -12,8 +12,6 @@ import CTA from '@/components/home/CTA';
|
||||
import Reveal from '@/components/Reveal';
|
||||
|
||||
export default function HomePage({ params: { locale } }: { params: { locale: string } }) {
|
||||
const t = useTranslations('Index');
|
||||
|
||||
return (
|
||||
<div className="flex flex-col min-h-screen">
|
||||
<Hero />
|
||||
|
||||
@@ -9,7 +9,6 @@ import Link from 'next/link';
|
||||
import Image from 'next/image';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
import { Section, Container, Heading, Badge, Button } from '@/components/ui';
|
||||
import ProductsIllustration from '@/components/products/ProductsIllustration';
|
||||
import Scribble from '@/components/Scribble';
|
||||
|
||||
interface ProductPageProps {
|
||||
@@ -68,8 +67,7 @@ export default async function ProductPage({ params }: ProductPageProps) {
|
||||
return (
|
||||
<div className="flex flex-col min-h-screen bg-white">
|
||||
<section className="relative min-h-[50vh] flex items-center pt-32 pb-20 overflow-hidden bg-primary-dark">
|
||||
<ProductsIllustration />
|
||||
<Container className="relative z-10">
|
||||
<Container className="relative z-10">
|
||||
<div className="max-w-4xl animate-slide-up">
|
||||
<nav className="flex items-center mb-8 text-white/40 text-sm font-bold uppercase tracking-widest">
|
||||
<Link href={`/${locale}/products`} className="hover:text-accent transition-colors">{t('title')}</Link>
|
||||
@@ -154,8 +152,7 @@ export default async function ProductPage({ params }: ProductPageProps) {
|
||||
<div className="flex flex-col min-h-screen bg-neutral-light">
|
||||
{/* Product Hero */}
|
||||
<section className="relative pt-40 pb-32 overflow-hidden bg-primary-dark">
|
||||
<ProductsIllustration />
|
||||
<Container className="relative z-10">
|
||||
<Container className="relative z-10">
|
||||
<div className="max-w-5xl animate-slide-up">
|
||||
<nav className="flex items-center mb-8 text-white/40 text-sm font-bold uppercase tracking-widest">
|
||||
<Link href={`/${locale}/products`} className="hover:text-accent transition-colors">{t('title')}</Link>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import Link from 'next/link';
|
||||
import Image from 'next/image';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { Section, Container, Heading, Card, Badge, Button } from '@/components/ui';
|
||||
import ProductsIllustration from '@/components/products/ProductsIllustration';
|
||||
import { Section, Container, Card, Badge, Button } from '@/components/ui';
|
||||
import Scribble from '@/components/Scribble';
|
||||
import Reveal from '@/components/Reveal';
|
||||
|
||||
interface ProductsPageProps {
|
||||
params: {
|
||||
@@ -49,7 +49,6 @@ export default function ProductsPage({ params }: ProductsPageProps) {
|
||||
<div className="flex flex-col min-h-screen bg-neutral-light">
|
||||
{/* Hero Section */}
|
||||
<section className="relative min-h-[50vh] md:min-h-[70vh] flex items-center pt-32 pb-20 md:pt-40 md:pb-32 overflow-hidden bg-primary-dark">
|
||||
<ProductsIllustration />
|
||||
<Container className="relative z-10">
|
||||
<div className="max-w-4xl animate-slide-up">
|
||||
<Badge variant="accent" className="mb-4 md:mb-8 bg-white/10 text-white border border-white/20 backdrop-blur-md px-3 py-1 md:px-4 md:py-1.5">
|
||||
@@ -82,48 +81,51 @@ export default function ProductsPage({ params }: ProductsPageProps) {
|
||||
<Container>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 md:gap-8 lg:gap-12">
|
||||
{categories.map((category, idx) => (
|
||||
<Link key={idx} href={category.href} className="group block">
|
||||
<Card className="h-full border-none shadow-sm hover:shadow-2xl transition-all duration-500 rounded-[24px] md:rounded-[48px] overflow-hidden bg-white">
|
||||
<div className="relative h-[200px] md:h-[400px] overflow-hidden">
|
||||
<Image
|
||||
src={category.img}
|
||||
alt={category.title}
|
||||
fill
|
||||
className="object-cover transition-transform duration-1000 group-hover:scale-105"
|
||||
sizes="(max-width: 768px) 100vw, 50vw"
|
||||
/>
|
||||
<div className="absolute inset-0 image-overlay-gradient opacity-80 group-hover:opacity-90 transition-opacity duration-500" />
|
||||
|
||||
<div className="absolute top-3 right-3 md:top-8 md:right-8 w-10 h-10 md:w-20 md:h-20 bg-white/10 backdrop-blur-md rounded-xl md:rounded-[24px] flex items-center justify-center border border-white/20 shadow-2xl transition-all duration-500 group-hover:scale-110 group-hover:bg-white/20">
|
||||
<img src={category.icon} alt="" className="w-6 h-6 md:w-12 md:h-12 brightness-0 invert opacity-80" />
|
||||
</div>
|
||||
<Reveal key={idx} delay={idx * 100}>
|
||||
<Link key={idx} href={category.href} className="group block">
|
||||
<Card className="h-full border-none shadow-sm hover:shadow-2xl transition-all duration-500 rounded-[24px] md:rounded-[48px] overflow-hidden bg-white active:scale-[0.98]">
|
||||
<div className="relative h-[200px] md:h-[400px] overflow-hidden">
|
||||
<Image
|
||||
src={category.img}
|
||||
alt={category.title}
|
||||
fill
|
||||
className="object-cover transition-transform duration-1000 group-hover:scale-105"
|
||||
sizes="(max-width: 768px) 100vw, 50vw"
|
||||
unoptimized
|
||||
/>
|
||||
<div className="absolute inset-0 image-overlay-gradient opacity-80 group-hover:opacity-90 transition-opacity duration-500" />
|
||||
|
||||
<div className="absolute top-3 right-3 md:top-8 md:right-8 w-10 h-10 md:w-20 md:h-20 bg-white/10 backdrop-blur-md rounded-xl md:rounded-[24px] flex items-center justify-center border border-white/20 shadow-2xl transition-all duration-500 group-hover:scale-110 group-hover:bg-white/20">
|
||||
<img src={category.icon} alt="" className="w-6 h-6 md:w-12 md:h-12 brightness-0 invert opacity-80" />
|
||||
</div>
|
||||
|
||||
<div className="absolute bottom-4 left-4 md:bottom-10 md:left-10 right-4 md:right-10">
|
||||
<Badge variant="accent" className="mb-2 md:mb-4 shadow-lg bg-accent text-primary-dark border-none text-[10px] md:text-xs">
|
||||
{t('categoryLabel')}
|
||||
</Badge>
|
||||
<h2 className="text-xl md:text-4xl font-bold text-white leading-tight transition-transform duration-500 group-hover:translate-x-1">
|
||||
{category.title}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-5 md:p-10">
|
||||
<p className="text-text-secondary text-sm md:text-lg leading-relaxed mb-4 md:mb-8 line-clamp-2 md:line-clamp-none">
|
||||
{category.desc}
|
||||
</p>
|
||||
<div className="flex items-center text-primary font-bold text-base md:text-lg group-hover:text-accent-dark transition-colors">
|
||||
<span className="border-b-2 border-primary/10 group-hover:border-accent-dark transition-colors pb-1">
|
||||
{t('viewProducts')}
|
||||
</span>
|
||||
<div className="ml-3 md:ml-4 w-8 h-8 md:w-10 md:h-10 rounded-full bg-primary-light flex items-center justify-center text-primary group-hover:bg-accent group-hover:text-primary-dark transition-all duration-300 shadow-sm">
|
||||
<svg className="w-4 h-4 md:w-5 md:h-5 transition-transform group-hover:translate-x-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
|
||||
</svg>
|
||||
<div className="absolute bottom-4 left-4 md:bottom-10 md:left-10 right-4 md:right-10">
|
||||
<Badge variant="accent" className="mb-2 md:mb-4 shadow-lg bg-accent text-primary-dark border-none text-[10px] md:text-xs">
|
||||
{t('categoryLabel')}
|
||||
</Badge>
|
||||
<h2 className="text-xl md:text-4xl font-bold text-white leading-tight transition-transform duration-500 group-hover:translate-x-1">
|
||||
{category.title}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</Link>
|
||||
<div className="p-5 md:p-10">
|
||||
<p className="text-text-secondary text-sm md:text-lg leading-relaxed mb-4 md:mb-8 line-clamp-2 md:line-clamp-none">
|
||||
{category.desc}
|
||||
</p>
|
||||
<div className="flex items-center text-primary font-bold text-base md:text-lg group-hover:text-accent-dark transition-colors">
|
||||
<span className="border-b-2 border-primary/10 group-hover:border-accent-dark transition-colors pb-1">
|
||||
{t('viewProducts')}
|
||||
</span>
|
||||
<div className="ml-3 md:ml-4 w-8 h-8 md:w-10 md:h-10 rounded-full bg-primary-light flex items-center justify-center text-primary group-hover:bg-accent group-hover:text-primary-dark transition-all duration-300 shadow-sm">
|
||||
<svg className="w-4 h-4 md:w-5 md:h-5 transition-transform group-hover:translate-x-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 8l4 4m0 0l-4 4m4-4H3" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</Link>
|
||||
</Reveal>
|
||||
))}
|
||||
</div>
|
||||
</Container>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { Section, Container, Heading, Card, Badge, Button } from '@/components/ui';
|
||||
import { Section, Container, Heading, Badge, Button } from '@/components/ui';
|
||||
import Image from 'next/image';
|
||||
import Reveal from '@/components/Reveal';
|
||||
|
||||
export default function TeamPage() {
|
||||
const t = useTranslations('Team');
|
||||
@@ -34,9 +35,9 @@ export default function TeamPage() {
|
||||
{/* Michael Bodemer Section - Sticky Narrative Split Layout */}
|
||||
<section className="relative bg-white overflow-hidden">
|
||||
<div className="flex flex-col lg:flex-row">
|
||||
<div className="w-full lg:w-1/2 p-6 md:p-24 lg:p-32 flex flex-col justify-center bg-primary-dark text-white relative">
|
||||
<Reveal className="w-full lg:w-1/2 p-6 md:p-24 lg:p-32 flex flex-col justify-center bg-primary-dark text-white relative order-2 lg:order-1">
|
||||
<div className="absolute top-0 right-0 w-32 h-full bg-accent/5 -skew-x-12 translate-x-1/2" />
|
||||
<div className="relative z-10 animate-fade-in">
|
||||
<div className="relative z-10">
|
||||
<Badge variant="accent" className="mb-4 md:mb-8">Managing Director</Badge>
|
||||
<Heading level={2} className="text-white mb-6 md:mb-10 text-3xl md:text-6xl">
|
||||
<span className="text-white">{t('michael.name')}</span>
|
||||
@@ -47,21 +48,21 @@ export default function TeamPage() {
|
||||
"{t('michael.quote')}"
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-base md:text-xl leading-relaxed text-white/70 mb-6 md:mb-12 max-w-xl line-clamp-4 md:line-clamp-none">
|
||||
<p className="text-base md:text-xl leading-relaxed text-white/70 mb-6 md:mb-12 max-w-xl">
|
||||
{t('michael.description')}
|
||||
</p>
|
||||
<Button
|
||||
href="https://www.linkedin.com/in/michael-bodemer-33b493122/"
|
||||
variant="accent"
|
||||
size="lg"
|
||||
className="group w-full md:w-auto md:h-16 md:px-10 md:text-xl"
|
||||
className="group w-full md:w-auto md:h-16 md:px-10 md:text-xl active:scale-95 transition-transform"
|
||||
>
|
||||
{t('michael.linkedin')}
|
||||
<span className="ml-3 transition-transform group-hover:translate-x-2">→</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full lg:w-1/2 relative min-h-[300px] md:min-h-[600px] lg:min-h-screen overflow-hidden">
|
||||
</Reveal>
|
||||
<div className="w-full lg:w-1/2 relative min-h-[400px] md:min-h-[600px] lg:min-h-screen overflow-hidden order-1 lg:order-2">
|
||||
<Image
|
||||
src="/uploads/2024/12/DSC07768-Large.webp"
|
||||
alt={t('michael.name')}
|
||||
@@ -69,7 +70,7 @@ export default function TeamPage() {
|
||||
className="object-cover scale-105 hover:scale-100 transition-transform duration-1000"
|
||||
sizes="(max-width: 1024px) 100vw, 50vw"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-primary-dark/20 to-transparent" />
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-primary-dark/60 lg:bg-gradient-to-r lg:from-primary-dark/20 to-transparent" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -118,7 +119,7 @@ export default function TeamPage() {
|
||||
{/* Klaus Mintel Section - Reversed Split Layout */}
|
||||
<section className="relative bg-white overflow-hidden">
|
||||
<div className="flex flex-col lg:flex-row">
|
||||
<div className="w-full lg:w-1/2 relative min-h-[300px] md:min-h-[600px] lg:min-h-screen overflow-hidden order-2 lg:order-1">
|
||||
<div className="w-full lg:w-1/2 relative min-h-[400px] md:min-h-[600px] lg:min-h-screen overflow-hidden order-1">
|
||||
<Image
|
||||
src="/uploads/2024/12/DSC07963-Large.webp"
|
||||
alt={t('klaus.name')}
|
||||
@@ -126,11 +127,11 @@ export default function TeamPage() {
|
||||
className="object-cover scale-105 hover:scale-100 transition-transform duration-1000"
|
||||
sizes="(max-width: 1024px) 100vw, 50vw"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-l from-primary-dark/20 to-transparent" />
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-white/60 lg:bg-gradient-to-l lg:from-primary-dark/20 to-transparent" />
|
||||
</div>
|
||||
<div className="w-full lg:w-1/2 p-6 md:p-24 lg:p-32 flex flex-col justify-center bg-neutral-light text-primary relative order-1 lg:order-2">
|
||||
<Reveal className="w-full lg:w-1/2 p-6 md:p-24 lg:p-32 flex flex-col justify-center bg-neutral-light text-primary relative order-2">
|
||||
<div className="absolute top-0 left-0 w-32 h-full bg-primary/5 skew-x-12 -translate-x-1/2" />
|
||||
<div className="relative z-10 animate-fade-in">
|
||||
<div className="relative z-10">
|
||||
<Badge variant="primary" className="mb-4 md:mb-8">Founder & Visionary</Badge>
|
||||
<Heading level={2} className="text-primary mb-6 md:mb-10 text-3xl md:text-6xl">
|
||||
{t('klaus.name')}
|
||||
@@ -141,20 +142,20 @@ export default function TeamPage() {
|
||||
"{t('klaus.quote')}"
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-base md:text-xl leading-relaxed text-text-secondary mb-6 md:mb-12 max-w-xl line-clamp-4 md:line-clamp-none">
|
||||
<p className="text-base md:text-xl leading-relaxed text-text-secondary mb-6 md:mb-12 max-w-xl">
|
||||
{t('klaus.description')}
|
||||
</p>
|
||||
<Button
|
||||
href="https://www.linkedin.com/in/klaus-mintel-b80a8b193/"
|
||||
variant="primary"
|
||||
size="lg"
|
||||
className="group w-full md:w-auto md:h-16 md:px-10 md:text-xl"
|
||||
className="group w-full md:w-auto md:h-16 md:px-10 md:text-xl active:scale-95 transition-transform"
|
||||
>
|
||||
{t('klaus.linkedin')}
|
||||
<span className="ml-3 transition-transform group-hover:translate-x-2">→</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -170,16 +171,25 @@ export default function TeamPage() {
|
||||
<p className="text-base md:text-xl text-text-secondary leading-relaxed">
|
||||
Our core principles guide every decision we make and every cable we deliver.
|
||||
</p>
|
||||
|
||||
{/* Mobile-only progress indicator */}
|
||||
<div className="flex lg:hidden mt-8 gap-2">
|
||||
{[0, 1, 2, 3, 4, 5].map((i) => (
|
||||
<div key={i} className="h-1.5 flex-1 bg-neutral-medium rounded-full overflow-hidden">
|
||||
<div className="h-full bg-accent w-0 group-active:w-full transition-all duration-500" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="sticky-narrative-content grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-10">
|
||||
{[0, 1, 2, 3, 4, 5].map((idx) => (
|
||||
<div key={idx} className="p-6 md:p-10 bg-neutral-light rounded-2xl md:rounded-[40px] border border-transparent hover:border-accent hover:bg-white hover:shadow-2xl transition-all duration-500 group">
|
||||
<div key={idx} className="p-6 md:p-10 bg-neutral-light rounded-2xl md:rounded-[40px] border border-transparent hover:border-accent hover:bg-white hover:shadow-2xl transition-all duration-500 group active:scale-[0.98] touch-target-none">
|
||||
<div className="w-10 h-10 md:w-16 md:h-16 bg-white rounded-xl md:rounded-2xl flex items-center justify-center mb-4 md:mb-8 shadow-sm group-hover:bg-accent transition-colors duration-500">
|
||||
<span className="text-primary font-extrabold text-lg md:text-2xl group-hover:text-primary-dark">0{idx + 1}</span>
|
||||
</div>
|
||||
<h3 className="text-lg md:text-2xl font-bold mb-2 md:mb-4 text-primary">{t(`manifesto.items.${idx}.title`)}</h3>
|
||||
<p className="text-sm md:text-lg text-text-secondary leading-relaxed line-clamp-3 md:line-clamp-none">{t(`manifesto.items.${idx}.description`)}</p>
|
||||
<p className="text-sm md:text-lg text-text-secondary leading-relaxed">{t(`manifesto.items.${idx}.description`)}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -12,6 +12,7 @@ export default function Header() {
|
||||
const t = useTranslations('Navigation');
|
||||
const pathname = usePathname();
|
||||
const [isScrolled, setIsScrolled] = useState(false);
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
|
||||
// Extract locale from pathname
|
||||
const currentLocale = pathname.split('/')[1] || 'en';
|
||||
@@ -27,6 +28,20 @@ export default function Header() {
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
return () => window.removeEventListener('scroll', handleScroll);
|
||||
}, []);
|
||||
|
||||
// Close mobile menu on route change
|
||||
useEffect(() => {
|
||||
setIsMobileMenuOpen(false);
|
||||
}, [pathname]);
|
||||
|
||||
// Prevent scroll when mobile menu is open
|
||||
useEffect(() => {
|
||||
if (isMobileMenuOpen) {
|
||||
document.body.style.overflow = 'hidden';
|
||||
} else {
|
||||
document.body.style.overflow = 'unset';
|
||||
}
|
||||
}, [isMobileMenuOpen]);
|
||||
|
||||
// Function to get path for a different locale
|
||||
const getPathForLocale = (newLocale: string) => {
|
||||
@@ -45,8 +60,8 @@ export default function Header() {
|
||||
const headerClass = cn(
|
||||
"fixed top-0 left-0 right-0 z-50 transition-all duration-500 safe-area-p",
|
||||
{
|
||||
"bg-transparent py-4 md:py-8": isHomePage && !isScrolled,
|
||||
"bg-primary py-3 md:py-4 shadow-2xl": !isHomePage || isScrolled,
|
||||
"bg-transparent py-4 md:py-8": isHomePage && !isScrolled && !isMobileMenuOpen,
|
||||
"bg-primary py-3 md:py-4 shadow-2xl": !isHomePage || isScrolled || isMobileMenuOpen,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -114,15 +129,79 @@ export default function Header() {
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu Button */}
|
||||
<button className={cn("lg:hidden touch-target p-2 rounded-xl bg-white/10 backdrop-blur-md border border-white/20", textColorClass)}>
|
||||
<button
|
||||
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
||||
className={cn("lg:hidden touch-target p-2 rounded-xl bg-white/10 backdrop-blur-md border border-white/20 z-50", textColorClass)}
|
||||
aria-label="Toggle Menu"
|
||||
>
|
||||
<svg className="w-7 h-7" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
|
||||
{isMobileMenuOpen ? (
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||
) : (
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
|
||||
)}
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile Menu Overlay */}
|
||||
<div className={cn(
|
||||
"fixed inset-0 bg-primary-dark z-40 lg:hidden transition-all duration-500 ease-in-out flex flex-col",
|
||||
isMobileMenuOpen ? "opacity-100 translate-y-0" : "opacity-0 -translate-y-full pointer-events-none"
|
||||
)}>
|
||||
<div className="flex-grow flex flex-col justify-center items-center p-8 space-y-8">
|
||||
{menuItems.map((item, idx) => (
|
||||
<Link
|
||||
key={item.href}
|
||||
href={`/${currentLocale}${item.href === '/' ? '' : item.href}`}
|
||||
className={cn(
|
||||
"text-3xl font-extrabold text-white hover:text-accent transition-all transform",
|
||||
isMobileMenuOpen ? "translate-y-0 opacity-100" : "translate-y-10 opacity-0"
|
||||
)}
|
||||
style={{ transitionDelay: `${idx * 100}ms` }}
|
||||
>
|
||||
{item.label}
|
||||
</Link>
|
||||
))}
|
||||
|
||||
<div className={cn(
|
||||
"pt-8 border-t border-white/10 w-full flex flex-col items-center space-y-8 transition-all duration-500 delay-500",
|
||||
isMobileMenuOpen ? "translate-y-0 opacity-100" : "translate-y-10 opacity-0"
|
||||
)}>
|
||||
<div className="flex items-center space-x-8 text-xl font-extrabold tracking-widest uppercase text-white">
|
||||
<Link
|
||||
href={getPathForLocale('en')}
|
||||
className={`hover:text-accent transition-colors ${currentLocale === 'en' ? 'text-accent' : 'opacity-60'}`}
|
||||
>
|
||||
EN
|
||||
</Link>
|
||||
<div className="w-px h-6 bg-white/20" />
|
||||
<Link
|
||||
href={getPathForLocale('de')}
|
||||
className={`hover:text-accent transition-colors ${currentLocale === 'de' ? 'text-accent' : 'opacity-60'}`}
|
||||
>
|
||||
DE
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
href={`/${currentLocale}/contact`}
|
||||
variant="accent"
|
||||
size="lg"
|
||||
className="w-full max-w-xs py-6 text-xl shadow-2xl"
|
||||
>
|
||||
{t('contact')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom Branding */}
|
||||
<div className="p-12 flex justify-center opacity-20">
|
||||
<Image src="/logo-white.svg" alt="KLZ" width={80} height={80} unoptimized />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
{/* Removed spacer div that caused white gap */}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
49
components/blog/ShareButton.tsx
Normal file
49
components/blog/ShareButton.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { Button } from '@/components/ui';
|
||||
|
||||
interface ShareButtonProps {
|
||||
title: string;
|
||||
text: string;
|
||||
url: string;
|
||||
locale: string;
|
||||
}
|
||||
|
||||
export default function ShareButton({ title, text, url, locale }: ShareButtonProps) {
|
||||
const handleShare = async () => {
|
||||
if (navigator.share) {
|
||||
try {
|
||||
await navigator.share({
|
||||
title,
|
||||
text,
|
||||
url,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error sharing:', error);
|
||||
}
|
||||
} else {
|
||||
// Fallback to copy link
|
||||
try {
|
||||
await navigator.clipboard.writeText(url);
|
||||
alert(locale === 'de' ? 'Link kopiert!' : 'Link copied!');
|
||||
} catch (error) {
|
||||
console.error('Error copying link:', error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={handleShare}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="flex items-center gap-2 rounded-full px-6"
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 100 5.368 3 3 0 000-5.368z" />
|
||||
</svg>
|
||||
{locale === 'de' ? 'Teilen' : 'Share'}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import Scribble from '@/components/Scribble';
|
||||
import { Section } from '../../components/ui';
|
||||
import { useTranslations } from 'next-intl';
|
||||
|
||||
export default function VideoSection() {
|
||||
const t = useTranslations('Home.video');
|
||||
@@ -29,11 +27,6 @@ export default function VideoSection() {
|
||||
)
|
||||
})}
|
||||
</h2>
|
||||
<div className="mt-12 flex justify-center">
|
||||
<div className="w-24 h-24 rounded-full border-2 border-white/30 flex items-center justify-center group cursor-pointer hover:bg-white transition-all duration-500">
|
||||
<div className="w-0 h-0 border-t-[12px] border-t-transparent border-l-[20px] border-l-white border-b-[12px] border-b-transparent ml-2 group-hover:border-l-primary-dark transition-colors" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default function ProductsIllustration() {
|
||||
return (
|
||||
<div className="absolute inset-0 z-0 overflow-hidden pointer-events-none bg-primary">
|
||||
<svg
|
||||
viewBox="0 0 1000 500"
|
||||
className="w-full h-full"
|
||||
preserveAspectRatio="xMidYMid slice"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id="scan-beam" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" stopColor="#82ed20" stopOpacity="0" />
|
||||
<stop offset="50%" stopColor="#82ed20" stopOpacity="0.5" />
|
||||
<stop offset="100%" stopColor="#82ed20" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
{/* 3D Cable Wireframe Construction */}
|
||||
<g transform="translate(100, 250) rotate(-10)">
|
||||
|
||||
{/* Inner Core Strands (Twisted) */}
|
||||
{[...Array(5)].map((_, i) => (
|
||||
<path
|
||||
key={`strand-${i}`}
|
||||
d={`M 0 ${i*10 - 20} Q 400 ${i*10 - 60} 800 ${i*10 - 20}`}
|
||||
stroke="white"
|
||||
strokeWidth="2"
|
||||
strokeOpacity="0.8"
|
||||
fill="none"
|
||||
>
|
||||
<animate attributeName="d"
|
||||
values={`M 0 ${i*10 - 20} Q 400 ${i*10 - 60} 800 ${i*10 - 20};
|
||||
M 0 ${i*10 - 20} Q 400 ${i*10 + 20} 800 ${i*10 - 20};
|
||||
M 0 ${i*10 - 20} Q 400 ${i*10 - 60} 800 ${i*10 - 20}`}
|
||||
dur="4s"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
</path>
|
||||
))}
|
||||
|
||||
{/* Insulation Layers (Ellipses along the path) */}
|
||||
{[...Array(8)].map((_, i) => (
|
||||
<ellipse
|
||||
key={`ring-${i}`}
|
||||
cx={100 + i * 100}
|
||||
cy="0"
|
||||
rx="40"
|
||||
ry="80"
|
||||
stroke="white"
|
||||
strokeWidth="1"
|
||||
strokeOpacity="0.2"
|
||||
fill="none"
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Outer Sheath (Top and Bottom Lines) */}
|
||||
<path d="M 0 -80 L 800 -80" stroke="white" strokeWidth="1" strokeOpacity="0.3" strokeDasharray="10 5" />
|
||||
<path d="M 0 80 L 800 80" stroke="white" strokeWidth="1" strokeOpacity="0.3" strokeDasharray="10 5" />
|
||||
|
||||
{/* Scanning Ring (Animated) */}
|
||||
<g>
|
||||
<ellipse cx="0" cy="0" rx="50" ry="90" stroke="#82ed20" strokeWidth="2" strokeOpacity="0.8" fill="none">
|
||||
<animate attributeName="cx" from="0" to="800" dur="3s" repeatCount="indefinite" />
|
||||
<animate attributeName="rx" values="50;45;50" dur="0.5s" repeatCount="indefinite" />
|
||||
</ellipse>
|
||||
{/* Scan Beam */}
|
||||
<rect x="-50" y="-100" width="100" height="200" fill="url(#scan-beam)" opacity="0.3">
|
||||
<animate attributeName="x" from="-50" to="750" dur="3s" repeatCount="indefinite" />
|
||||
</rect>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
{/* Floating Data/Tech Elements */}
|
||||
<g transform="translate(0, 0)">
|
||||
{[...Array(20)].map((_, i) => (
|
||||
<rect
|
||||
key={`bit-${i}`}
|
||||
x={Math.random() * 1000}
|
||||
y={Math.random() * 500}
|
||||
width={Math.random() * 20 + 5}
|
||||
height="2"
|
||||
fill="white"
|
||||
fillOpacity="0.3"
|
||||
>
|
||||
<animate attributeName="opacity" values="0;0.5;0" dur={`${Math.random() * 2 + 1}s`} repeatCount="indefinite" />
|
||||
<animate attributeName="width" values="5;30;5" dur={`${Math.random() * 2 + 1}s`} repeatCount="indefinite" />
|
||||
</rect>
|
||||
))}
|
||||
</g>
|
||||
|
||||
</svg>
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-primary/80 via-transparent to-primary/80" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user