This commit is contained in:
2026-01-17 01:50:54 +01:00
parent c12b32ed5e
commit c8f61257c9
62 changed files with 1297 additions and 1028 deletions

View File

@@ -0,0 +1,25 @@
import React from 'react';
interface ProductTabsProps {
children: React.ReactNode;
technicalData?: React.ReactNode;
}
export default function ProductTabs({ children, technicalData }: ProductTabsProps) {
return (
<div className="space-y-12">
<div className="prose max-w-none">
{children}
</div>
{technicalData && (
<div className="pt-8 border-t border-neutral-dark">
<h2 className="text-2xl font-bold text-primary-dark mb-6">Technical Specifications</h2>
<div className="not-prose">
{technicalData}
</div>
</div>
)}
</div>
);
}

View File

@@ -21,7 +21,8 @@ interface ProductTechnicalDataProps {
}
export default function ProductTechnicalData({ data }: ProductTechnicalDataProps) {
const { technicalItems, voltageTables } = data;
if (!data) return null;
const { technicalItems = [], voltageTables = [] } = data;
return (
<div className="space-y-8">

View File

@@ -0,0 +1,63 @@
import Link from 'next/link';
import { getAllProducts } from '@/lib/mdx';
interface RelatedProductsProps {
currentSlug: string;
categories: string[];
locale: string;
}
export default async function RelatedProducts({ currentSlug, categories, locale }: RelatedProductsProps) {
const allProducts = await getAllProducts(locale);
// Filter products: same category, not current product
const related = allProducts
.filter(p =>
p.slug !== currentSlug &&
p.frontmatter.categories.some(cat => categories.includes(cat))
)
.slice(0, 4); // Limit to 4
if (related.length === 0) return null;
return (
<div className="mt-16 pt-8 border-t border-neutral-dark">
<h2 className="text-2xl font-bold text-primary-dark mb-6">Related Products</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
{related.map((product) => (
<Link
key={product.slug}
href={`/${locale}/products/${product.slug}`}
className="group block bg-white rounded-lg overflow-hidden shadow-sm hover:shadow-md transition-shadow border border-neutral-dark"
>
<div className="aspect-[4/3] relative bg-neutral-light">
{product.frontmatter.images?.[0] ? (
<img
src={product.frontmatter.images[0]}
alt={product.frontmatter.title}
className="w-full h-full object-contain p-4 group-hover:scale-105 transition-transform duration-300"
/>
) : (
<div className="w-full h-full flex items-center justify-center text-text-secondary">
No Image
</div>
)}
</div>
<div className="p-4">
<h3 className="font-semibold text-lg text-text-primary group-hover:text-primary transition-colors">
{product.frontmatter.title}
</h3>
<div className="mt-2 flex flex-wrap gap-1">
{product.frontmatter.categories.slice(0, 1).map((cat, idx) => (
<span key={idx} className="text-xs bg-neutral text-text-secondary px-2 py-1 rounded">
{cat}
</span>
))}
</div>
</div>
</Link>
))}
</div>
</div>
);
}

View File

@@ -0,0 +1,101 @@
'use client';
import React, { useState } from 'react';
interface RequestQuoteFormProps {
productName: string;
}
export default function RequestQuoteForm({ productName }: RequestQuoteFormProps) {
const [email, setEmail] = useState('');
const [request, setRequest] = useState('');
const [status, setStatus] = useState<'idle' | 'submitting' | 'success' | 'error'>('idle');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setStatus('submitting');
// Simulate API call
await new Promise((resolve) => setTimeout(resolve, 1000));
// Here you would typically send the data to your backend
console.log('Form submitted:', { productName, email, request });
setStatus('success');
setEmail('');
setRequest('');
};
if (status === 'success') {
return (
<div className="bg-green-50 border border-green-200 text-green-800 p-6 rounded-lg">
<h3 className="text-lg font-semibold mb-2">Request Sent!</h3>
<p>Thank you for your interest in {productName}. We will get back to you shortly.</p>
<button
onClick={() => setStatus('idle')}
className="mt-4 text-sm font-medium underline hover:text-green-900"
>
Send another request
</button>
</div>
);
}
return (
<div className="bg-neutral-light p-6 rounded-lg border border-neutral-dark">
<h3 className="text-xl font-semibold mb-4 text-primary-dark">Request Cable</h3>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label htmlFor="product" className="block text-sm font-medium text-text-secondary mb-1">
Product
</label>
<input
type="text"
id="product"
value={productName}
disabled
className="w-full px-3 py-2 bg-neutral border border-neutral-dark rounded text-text-secondary cursor-not-allowed"
/>
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium text-text-primary mb-1">
Email <span className="text-red-500">*</span>
</label>
<input
type="email"
id="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full px-3 py-2 bg-white border border-neutral-dark rounded focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"
placeholder="your@email.com"
/>
</div>
<div>
<label htmlFor="request" className="block text-sm font-medium text-text-primary mb-1">
Request <span className="text-red-500">*</span>
</label>
<textarea
id="request"
required
rows={4}
value={request}
onChange={(e) => setRequest(e.target.value)}
className="w-full px-3 py-2 bg-white border border-neutral-dark rounded focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"
placeholder="Describe your request, e.g. the cross section etc."
/>
</div>
<button
type="submit"
disabled={status === 'submitting'}
className="w-full bg-primary text-white font-medium py-2 px-4 rounded hover:bg-primary-dark transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
{status === 'submitting' ? 'Sending...' : 'Request Cable'}
</button>
</form>
</div>
);
}