clone init

This commit is contained in:
2026-01-16 21:47:58 +01:00
parent ffbb240a23
commit ce1a73f2bc
160 changed files with 64257 additions and 9 deletions

View File

@@ -0,0 +1,36 @@
import { notFound } from 'next/navigation';
import { MDXRemote } from 'next-mdx-remote/rsc';
import { getPostBySlug } from '@/lib/blog';
interface PageProps {
params: {
locale: string;
slug: string;
};
}
export default async function StandardPage({ params: { locale, slug } }: PageProps) {
const page = await getPostBySlug(slug, locale); // Reusing blog logic for now as structure is same
// If not found in blog, try pages directory (we need to implement getPageBySlug)
// Actually, let's implement getPageBySlug in lib/mdx.ts or similar
// For now, let's assume we use a unified loader or separate.
// Let's use a separate loader for pages.
const { getPageBySlug } = await import('@/lib/pages');
const pageData = await getPageBySlug(slug, locale);
if (!pageData) {
notFound();
}
return (
<div className="container mx-auto px-4 py-12 max-w-4xl">
<h1 className="text-4xl font-bold text-primary mb-8">{pageData.frontmatter.title}</h1>
<div className="prose prose-lg max-w-none">
<MDXRemote source={pageData.content} />
</div>
</div>
);
}

View File

@@ -0,0 +1,48 @@
import { notFound } from 'next/navigation';
import { MDXRemote } from 'next-mdx-remote/rsc';
import { getPostBySlug } from '@/lib/blog';
interface BlogPostProps {
params: {
locale: string;
slug: string;
};
}
export default async function BlogPost({ params: { locale, slug } }: BlogPostProps) {
const post = await getPostBySlug(slug, locale);
if (!post) {
notFound();
}
return (
<article className="container mx-auto px-4 py-12 max-w-4xl">
<header className="mb-8 text-center">
<div className="text-text-secondary mb-4">
{new Date(post.frontmatter.date).toLocaleDateString(locale, {
year: 'numeric',
month: 'long',
day: 'numeric'
})}
</div>
<h1 className="text-4xl md:text-5xl font-bold text-primary mb-6">
{post.frontmatter.title}
</h1>
{post.frontmatter.featuredImage && (
<div className="aspect-video relative rounded-xl overflow-hidden shadow-lg mb-8">
<img
src={post.frontmatter.featuredImage}
alt={post.frontmatter.title}
className="w-full h-full object-cover"
/>
</div>
)}
</header>
<div className="prose prose-lg max-w-none">
<MDXRemote source={post.content} />
</div>
</article>
);
}

View File

@@ -0,0 +1,51 @@
import Link from 'next/link';
import { getAllPosts } from '@/lib/blog';
import { useTranslations } from 'next-intl';
interface BlogIndexProps {
params: {
locale: string;
};
}
export default async function BlogIndex({ params: { locale } }: BlogIndexProps) {
const posts = await getAllPosts(locale);
return (
<div className="container mx-auto px-4 py-12">
<h1 className="text-4xl font-bold text-primary mb-8">Blog</h1>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{posts.map((post) => (
<Link key={post.slug} href={`/${locale}/blog/${post.slug}`} className="group">
<article className="bg-white rounded-lg shadow-sm overflow-hidden border border-neutral-dark h-full flex flex-col transition-transform hover:-translate-y-1">
{post.frontmatter.featuredImage && (
<div className="aspect-video relative overflow-hidden">
<img
src={post.frontmatter.featuredImage}
alt={post.frontmatter.title}
className="w-full h-full object-cover transition-transform group-hover:scale-105"
/>
</div>
)}
<div className="p-6 flex flex-col flex-grow">
<div className="text-sm text-text-secondary mb-2">
{new Date(post.frontmatter.date).toLocaleDateString(locale)}
</div>
<h2 className="text-xl font-bold text-text-primary mb-3 group-hover:text-primary transition-colors">
{post.frontmatter.title}
</h2>
<p className="text-text-secondary line-clamp-3 mb-4 flex-grow">
{post.frontmatter.excerpt}
</p>
<span className="text-primary font-medium group-hover:underline">
Read more &rarr;
</span>
</div>
</article>
</Link>
))}
</div>
</div>
);
}

View File

@@ -0,0 +1,89 @@
import { useTranslations } from 'next-intl';
import { Section, Container, Button } from '@/components/ui';
export default function ContactPage() {
const t = useTranslations('Navigation'); // Reusing navigation translations for now
return (
<div className="flex flex-col min-h-screen">
<Section className="bg-neutral">
<Container>
<div className="max-w-3xl mx-auto text-center mb-12">
<h1 className="text-4xl font-bold mb-4">Get in Touch</h1>
<p className="text-xl text-text-secondary">
Have questions about our products or need a custom solution? We're here to help.
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-12 max-w-5xl mx-auto">
{/* Contact Info */}
<div className="space-y-8">
<div>
<h3 className="text-xl font-bold mb-4">Contact Information</h3>
<div className="space-y-4 text-text-secondary">
<p className="flex items-start">
<svg className="w-6 h-6 text-primary mr-3 mt-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
<span>
Raiffeisenstraße 22<br />
73630 Remshalden<br />
Germany
</span>
</p>
<p className="flex items-center">
<svg className="w-6 h-6 text-primary mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z" />
</svg>
<a href="tel:+4988192537298" className="hover:text-primary transition-colors">+49 881 92537298</a>
</p>
<p className="flex items-center">
<svg className="w-6 h-6 text-primary mr-3" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
</svg>
<a href="mailto:info@klz-vertriebs-gmbh.com" className="hover:text-primary transition-colors">info@klz-vertriebs-gmbh.com</a>
</p>
</div>
</div>
<div>
<h3 className="text-xl font-bold mb-4">Business Hours</h3>
<ul className="space-y-2 text-text-secondary">
<li className="flex justify-between">
<span>Monday - Friday</span>
<span>8:00 AM - 5:00 PM</span>
</li>
<li className="flex justify-between">
<span>Saturday - Sunday</span>
<span>Closed</span>
</li>
</ul>
</div>
</div>
{/* Contact Form Placeholder */}
<div className="bg-white p-8 rounded-lg shadow-sm border border-neutral-dark">
<h3 className="text-xl font-bold mb-6">Send us a message</h3>
<form className="space-y-4">
<div>
<label htmlFor="name" className="block text-sm font-medium text-text-primary mb-1">Name</label>
<input type="text" id="name" className="w-full px-4 py-2 border border-neutral-dark rounded-md focus:ring-primary focus:border-primary" />
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium text-text-primary mb-1">Email</label>
<input type="email" id="email" className="w-full px-4 py-2 border border-neutral-dark rounded-md focus:ring-primary focus:border-primary" />
</div>
<div>
<label htmlFor="message" className="block text-sm font-medium text-text-primary mb-1">Message</label>
<textarea id="message" rows={4} className="w-full px-4 py-2 border border-neutral-dark rounded-md focus:ring-primary focus:border-primary"></textarea>
</div>
<Button type="submit" className="w-full">Send Message</Button>
</form>
</div>
</div>
</Container>
</Section>
</div>
);
}

31
app/[locale]/layout.tsx Normal file
View File

@@ -0,0 +1,31 @@
import {NextIntlClientProvider} from 'next-intl';
import {getMessages} from 'next-intl/server';
import '../../styles/globals.css';
import Header from '@/components/Header';
import Footer from '@/components/Footer';
export default async function LocaleLayout({
children,
params: {locale}
}: {
children: React.ReactNode;
params: {locale: string};
}) {
// Providing all messages to the client
// side is the easiest way to get started
const messages = await getMessages();
return (
<html lang={locale}>
<body className="flex flex-col min-h-screen">
<NextIntlClientProvider messages={messages}>
<Header />
<main className="flex-grow">
{children}
</main>
<Footer />
</NextIntlClientProvider>
</body>
</html>
);
}

182
app/[locale]/page.tsx Normal file
View File

@@ -0,0 +1,182 @@
import { useTranslations } from 'next-intl';
import { Button, Section, Container } from '@/components/ui';
import Link from 'next/link';
import Image from 'next/image';
export default function HomePage() {
const t = useTranslations('Index');
return (
<div className="flex flex-col min-h-screen">
{/* Hero Section */}
<section className="relative h-[80vh] flex items-center justify-center overflow-hidden bg-neutral-dark">
<div className="absolute inset-0 z-0">
<video
className="w-full h-full object-cover"
autoPlay
muted
loop
playsInline
poster="https://klz-cables.com/wp-content/uploads/2025/02/Still-2025-02-10-104337_1.1.1.webp"
>
<source src="https://klz-cables.com/wp-content/uploads/2025/02/header.webm" type="video/webm" />
<source src="https://klz-cables.com/wp-content/uploads/2025/02/header.mp4" type="video/mp4" />
</video>
<div className="absolute inset-0 bg-gradient-to-b from-black/10 to-black/40" />
</div>
<Container className="relative z-10 text-left text-white w-full">
<div className="max-w-4xl">
<h1 className="text-4xl md:text-6xl lg:text-7xl font-bold mb-6 tracking-tight leading-tight">
We are helping to expand the energy cable networks for a <span className="text-[#82ed20] relative inline-block">green</span> future
</h1>
<div className="mt-8">
<Link href="/contact" className="inline-flex items-center text-white text-xl font-medium group">
Let's talk
<span className="ml-2 w-8 h-8 border-2 border-white rounded-full flex items-center justify-center group-hover:bg-white group-hover:text-black transition-all">
&rarr;
</span>
</Link>
</div>
</div>
</Container>
</section>
{/* Product Categories Preview */}
<Section className="bg-neutral-dark py-0">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4">
{[
{
title: 'Low Voltage Cables',
desc: 'Powering everyday essentials with reliability and safety.',
img: 'https://klz-cables.com/wp-content/uploads/2024/12/low-voltage-scaled.webp',
icon: 'https://klz-cables.com/wp-content/uploads/2024/11/Low-Voltage.svg',
href: '/products/low-voltage-cables'
},
{
title: 'Medium Voltage Cables',
desc: 'The perfect balance between power and performance for industrial and urban grids.',
img: 'https://klz-cables.com/wp-content/uploads/2024/12/medium-voltage-scaled.webp',
icon: 'https://klz-cables.com/wp-content/uploads/2024/11/Medium-Voltage.svg',
href: '/products/medium-voltage-cables'
},
{
title: 'High Voltage Cables',
desc: 'Delivering maximum power over long distances—without compromise.',
img: 'https://klz-cables.com/wp-content/uploads/2025/06/na2xsfl2y-rendered.webp',
icon: 'https://klz-cables.com/wp-content/uploads/2024/11/High-Voltage.svg',
href: '/products/high-voltage-cables'
},
{
title: 'Solar Cables',
desc: 'Connecting the suns energy to your sustainable future.',
img: 'https://klz-cables.com/wp-content/uploads/2025/04/3.webp',
icon: 'https://klz-cables.com/wp-content/uploads/2024/11/Solar.svg',
href: '/products/solar-cables'
}
].map((category, idx) => (
<Link key={idx} href={category.href} className="group block relative h-[400px] md:h-[500px] overflow-hidden">
<Image
src={category.img}
alt={category.title}
fill
className="object-cover transition-transform duration-700 group-hover:scale-110"
/>
<div className="absolute inset-0 bg-black/40 group-hover:bg-black/50 transition-colors" />
<div className="absolute inset-0 p-8 flex flex-col justify-center items-center text-center text-white">
<div className="mb-4 transform transition-transform group-hover:-translate-y-2">
<img src={category.icon} alt="" className="w-16 h-16 mx-auto" />
</div>
<h3 className="text-2xl font-bold mb-2 transform transition-transform group-hover:-translate-y-2">{category.title}</h3>
<p className="text-white/90 opacity-0 group-hover:opacity-100 transform translate-y-4 group-hover:translate-y-0 transition-all duration-300">
{category.desc}
</p>
</div>
</Link>
))}
</div>
</Section>
{/* What We Do Section */}
<Section className="bg-neutral-dark text-white">
<Container>
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12">
<div className="lg:col-span-4">
<div className="sticky top-24">
<h2 className="text-5xl font-bold text-primary mb-6">What we do</h2>
<p className="text-xl text-white/80">
We ensure that the electricity flows with quality-tested cables. From low voltage up to high voltage.
</p>
</div>
</div>
<div className="lg:col-span-8 grid grid-cols-1 md:grid-cols-2 gap-x-12 gap-y-16">
{[
{
num: '01',
title: 'Supply to energy suppliers, wind and solar parks, industry and trade',
desc: 'We support your projects from 1 to 220 kV, from simple NYY to high-voltage cables with segment conductors and aluminum sheaths, with a particular focus on medium-voltage cables.'
},
{
num: '02',
title: 'Supply of cables whose quality is certified',
desc: 'Cables are products that have to function 100%. For decades, often 80 to 100 years. Our cables are not only approved by VDE. The most well-known energy suppliers trust us.'
},
{
num: '03',
title: 'We deliver on time because we know the consequences for you',
desc: 'Wind farm North Germany, coordinates XYZ, delivery Wednesday 2-4 p.m., no unloading option. Yes, we know that. We organize the logistics with a back office team that has up to 20 years of cable experience.'
},
{
num: '04',
title: 'The cable alone is not the solution',
desc: 'Stony ground? Perhaps a thicker outer sheath would be better? Damp ground? Can there be transverse watertight protection? We think for you and ask questions.'
}
].map((item, idx) => (
<div key={idx} className="space-y-4">
<span className="text-sm font-mono text-white/60 border-b border-white/20 pb-2 block w-fit">{item.num}</span>
<h3 className="text-2xl font-bold">{item.title}</h3>
<p className="text-white/70 leading-relaxed">{item.desc}</p>
</div>
))}
</div>
</div>
</Container>
</Section>
{/* Video Section */}
<section className="relative h-[60vh] overflow-hidden">
<video
className="w-full h-full object-cover"
autoPlay
muted
loop
playsInline
>
<source src="https://klz-cables.com/wp-content/uploads/2024/12/making-of-metal-cable-on-factory-2023-11-27-04-55-16-utc-2.webm" type="video/mp4" />
</video>
<div className="absolute inset-0 bg-black/50 flex items-center justify-center">
<h2 className="text-3xl md:text-5xl font-bold text-white text-center max-w-4xl px-4 leading-tight">
From a single strand to infinite power the <span className="text-[#82ed20] italic">future</span> starts here.
</h2>
</div>
</section>
{/* CTA Section */}
<Section className="bg-primary text-white py-24">
<Container>
<div className="flex flex-col md:flex-row items-center justify-between gap-8">
<h2 className="text-3xl md:text-4xl font-bold max-w-2xl">
Enough information, let's build something together!
</h2>
<Link href="/contact" className="group flex items-center gap-4 text-xl font-bold text-[#82ed20]">
Reach out now
<span className="w-10 h-10 border-2 border-[#82ed20] rounded-full flex items-center justify-center group-hover:bg-[#82ed20] group-hover:text-primary transition-all">
&rarr;
</span>
</Link>
</div>
</Container>
</Section>
</div>
);
}

View File

@@ -0,0 +1,84 @@
import { notFound } from 'next/navigation';
import { MDXRemote } from 'next-mdx-remote/rsc';
import { getProductBySlug } from '@/lib/mdx';
import ProductTechnicalData from '@/components/ProductTechnicalData';
import Image from 'next/image';
interface ProductPageProps {
params: {
locale: string;
slug: string[];
};
}
const components = {
ProductTechnicalData,
// Add other components if needed
};
export default async function ProductPage({ params }: ProductPageProps) {
const { locale, slug } = params;
const productSlug = slug[slug.length - 1]; // Use the last segment as the slug
const product = await getProductBySlug(productSlug, locale);
if (!product) {
notFound();
}
return (
<div className="container mx-auto px-4 py-8">
<div className="mb-8">
<h1 className="text-4xl font-bold text-primary mb-4">{product.frontmatter.title}</h1>
<div className="flex flex-wrap gap-2 mb-4">
{product.frontmatter.categories.map((cat, idx) => (
<span key={idx} className="bg-neutral-dark text-text-secondary px-2 py-1 rounded text-sm">
{cat}
</span>
))}
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
<div className="lg:col-span-2">
<div className="prose max-w-none mb-8">
<MDXRemote source={product.content} components={components} />
</div>
</div>
<div className="lg:col-span-1">
{product.frontmatter.images && product.frontmatter.images.length > 0 && (
<div className="sticky top-4">
<div className="bg-white p-4 rounded-lg shadow-sm border border-neutral-dark">
<div className="relative aspect-square mb-4">
{/* Note: Images from WC might be external URLs. Next/Image requires configuration for external domains. */}
{/* For now using standard img tag if domain not configured, or configure domains. */}
<img
src={product.frontmatter.images[0]}
alt={product.frontmatter.title}
className="w-full h-full object-contain"
/>
</div>
<div className="grid grid-cols-4 gap-2">
{product.frontmatter.images.slice(1, 5).map((img, idx) => (
<div key={idx} className="relative aspect-square border border-neutral-dark rounded overflow-hidden">
<img src={img} alt="" className="w-full h-full object-cover" />
</div>
))}
</div>
</div>
<div className="mt-6 bg-primary-light p-6 rounded-lg">
<h3 className="text-lg font-semibold text-primary-dark mb-2">Contact Us</h3>
<p className="text-text-secondary mb-4">Need more information about {product.frontmatter.title}?</p>
<button className="w-full bg-primary text-white py-2 px-4 rounded hover:bg-primary-dark transition-colors">
Request Quote
</button>
</div>
</div>
)}
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,57 @@
import { useTranslations } from 'next-intl';
import { Section, Container } from '@/components/ui';
import Image from 'next/image';
export default function TeamPage() {
const t = useTranslations('Navigation');
const teamMembers = [
{
name: 'Klaus',
role: 'Founder & CEO',
image: '/media/team/klaus.jpg', // Placeholder path
bio: 'With decades of experience in the cable industry, Klaus leads KLZ with a vision for quality and innovation.'
},
{
name: 'Michael',
role: 'Technical Director',
image: '/media/team/michael.jpg', // Placeholder path
bio: 'Expert in high-voltage systems and technical planning, ensuring every project meets the highest standards.'
},
// Add more team members as needed
];
return (
<div className="flex flex-col min-h-screen">
<Section className="bg-neutral-light">
<Container>
<div className="max-w-3xl mx-auto text-center mb-16">
<h1 className="text-4xl font-bold mb-6">Our Team</h1>
<p className="text-xl text-text-secondary">
Meet the experts behind KLZ Cables. We are a dedicated team of professionals committed to powering your success.
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{teamMembers.map((member, idx) => (
<div key={idx} className="bg-white rounded-lg overflow-hidden shadow-sm border border-neutral-dark group hover:-translate-y-1 transition-transform duration-300">
<div className="aspect-[3/4] bg-neutral relative overflow-hidden">
{/* Placeholder for team image */}
<div className="absolute inset-0 flex items-center justify-center text-text-light bg-neutral-dark">
<span className="text-4xl font-bold opacity-20">{member.name[0]}</span>
</div>
{/* <Image src={member.image} alt={member.name} fill className="object-cover" /> */}
</div>
<div className="p-6">
<h3 className="text-xl font-bold text-text-primary mb-1">{member.name}</h3>
<p className="text-primary font-medium mb-4">{member.role}</p>
<p className="text-text-secondary text-sm">{member.bio}</p>
</div>
</div>
))}
</div>
</Container>
</Section>
</div>
);
}