194 lines
6.1 KiB
TypeScript
194 lines
6.1 KiB
TypeScript
'use client';
|
|
|
|
import React from 'react';
|
|
import { BaseCard, BaseCardProps, CardSize, CardLayout } from './BaseCard';
|
|
import { Badge, BadgeGroup } from '@/components/ui';
|
|
import { ProductCategory } from '@/lib/data';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
// CategoryCard specific props
|
|
export interface CategoryCardProps extends Omit<BaseCardProps, 'title' | 'description' | 'image' | 'footer'> {
|
|
/** Category data from WordPress */
|
|
category: ProductCategory;
|
|
/** Display product count */
|
|
showCount?: boolean;
|
|
/** Display description */
|
|
showDescription?: boolean;
|
|
/** Display as icon instead of image */
|
|
useIcon?: boolean;
|
|
/** Icon component (if useIcon is true) */
|
|
icon?: React.ReactNode;
|
|
/** Category type */
|
|
categoryType?: 'product' | 'blog';
|
|
/** Locale for formatting */
|
|
locale?: string;
|
|
}
|
|
|
|
// Helper to get category image
|
|
const getCategoryImage = (category: ProductCategory): string | undefined => {
|
|
// In a real implementation, this would use getMediaById
|
|
// For now, return a placeholder based on category ID
|
|
if (category.id % 3 === 0) {
|
|
return '/media/6517-medium-voltage-category.webp';
|
|
} else if (category.id % 3 === 1) {
|
|
return '/media/6521-low-voltage-category.webp';
|
|
} else {
|
|
return '/media/10863-klz-directory-2-scaled.webp';
|
|
}
|
|
};
|
|
|
|
// Helper to get icon for category
|
|
const getCategoryIcon = (category: ProductCategory): React.ReactNode => {
|
|
const iconMap = {
|
|
1: '🔌', // Low Voltage
|
|
2: '⚡', // Medium Voltage
|
|
3: '🏭', // Industrial
|
|
4: '🏗️', // Construction
|
|
5: '🏠', // Residential
|
|
};
|
|
|
|
return iconMap[category.id as keyof typeof iconMap] || '📁';
|
|
};
|
|
|
|
// Helper to get category color variant
|
|
const getCategoryVariant = (category: ProductCategory): 'primary' | 'secondary' | 'success' | 'info' => {
|
|
const variants = ['primary', 'secondary', 'success', 'info'] as const;
|
|
return variants[category.id % variants.length];
|
|
};
|
|
|
|
export const CategoryCard: React.FC<CategoryCardProps> = ({
|
|
category,
|
|
size = 'md',
|
|
layout = 'vertical',
|
|
showCount = true,
|
|
showDescription = true,
|
|
useIcon = false,
|
|
icon,
|
|
categoryType = 'product',
|
|
locale = 'de',
|
|
className = '',
|
|
...props
|
|
}) => {
|
|
// Get category data
|
|
const title = category.name;
|
|
const description = showDescription && category.description ?
|
|
category.description.replace(/<[^>]*>/g, '').substring(0, 100) + (category.description.length > 100 ? '...' : '') :
|
|
'';
|
|
const count = showCount ? category.count : 0;
|
|
const image = useIcon ? undefined : getCategoryImage(category);
|
|
const categoryIcon = icon || getCategoryIcon(category);
|
|
|
|
// Build badge with count
|
|
const badge = showCount && count > 0 ? (
|
|
<Badge variant="neutral" size={size === 'sm' ? 'sm' : 'md'}>
|
|
{count} {locale === 'de' ? 'Produkte' : 'Products'}
|
|
</Badge>
|
|
) : null;
|
|
|
|
// Build header with icon
|
|
const header = useIcon ? (
|
|
<span className="text-3xl" role="img" aria-label="Category icon">
|
|
{categoryIcon}
|
|
</span>
|
|
) : null;
|
|
|
|
// Build footer with link text
|
|
const footer = (
|
|
<span className={cn(
|
|
'font-medium transition-colors',
|
|
getCategoryVariant(category) === 'primary' && 'text-primary hover:text-primary-dark',
|
|
getCategoryVariant(category) === 'secondary' && 'text-secondary hover:text-secondary-dark',
|
|
getCategoryVariant(category) === 'success' && 'text-success hover:text-success-dark',
|
|
getCategoryVariant(category) === 'info' && 'text-info hover:text-info-dark'
|
|
)}>
|
|
{locale === 'de' ? 'Anzeigen' : 'View'} →
|
|
</span>
|
|
);
|
|
|
|
// Build description with count
|
|
const descriptionContent = (
|
|
<div>
|
|
{description && <div className="text-gray-600 mb-2">{description}</div>}
|
|
{showCount && count > 0 && (
|
|
<div className="text-sm font-semibold text-gray-700">
|
|
{count} {locale === 'de' ? 'Produkte' : 'Products'}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
|
|
// Build icon content for vertical layout
|
|
const iconContent = useIcon ? (
|
|
<div className={cn(
|
|
'flex items-center justify-center rounded-lg',
|
|
getCategoryVariant(category) === 'primary' && 'bg-primary/10 text-primary',
|
|
getCategoryVariant(category) === 'secondary' && 'bg-secondary/10 text-secondary',
|
|
getCategoryVariant(category) === 'success' && 'bg-success/10 text-success',
|
|
getCategoryVariant(category) === 'info' && 'bg-info/10 text-info',
|
|
size === 'sm' && 'w-12 h-12 text-xl',
|
|
size === 'md' && 'w-16 h-16 text-2xl',
|
|
size === 'lg' && 'w-20 h-20 text-3xl'
|
|
)}>
|
|
{categoryIcon}
|
|
</div>
|
|
) : null;
|
|
|
|
// Override title to include icon for horizontal layout
|
|
const titleContent = useIcon && layout === 'horizontal' ? (
|
|
<div className="flex items-center gap-2">
|
|
{iconContent}
|
|
<span>{title}</span>
|
|
</div>
|
|
) : title;
|
|
|
|
return (
|
|
<BaseCard
|
|
title={titleContent}
|
|
description={descriptionContent}
|
|
image={useIcon ? undefined : image}
|
|
imageAlt={title}
|
|
size={size}
|
|
layout={layout}
|
|
href={category.path}
|
|
badge={badge}
|
|
header={useIcon && layout === 'vertical' ? null : header}
|
|
footer={footer}
|
|
hoverable={true}
|
|
variant="elevated"
|
|
className={className}
|
|
{...props}
|
|
>
|
|
{/* For vertical layout with icon, add icon above title */}
|
|
{useIcon && layout === 'vertical' && (
|
|
<div className="mb-2">
|
|
{iconContent}
|
|
</div>
|
|
)}
|
|
</BaseCard>
|
|
);
|
|
};
|
|
|
|
// CategoryCard variations
|
|
export const CategoryCardVertical: React.FC<CategoryCardProps> = (props) => (
|
|
<CategoryCard {...props} layout="vertical" />
|
|
);
|
|
|
|
export const CategoryCardHorizontal: React.FC<CategoryCardProps> = (props) => (
|
|
<CategoryCard {...props} layout="horizontal" />
|
|
);
|
|
|
|
export const CategoryCardSmall: React.FC<CategoryCardProps> = (props) => (
|
|
<CategoryCard {...props} size="sm" />
|
|
);
|
|
|
|
export const CategoryCardLarge: React.FC<CategoryCardProps> = (props) => (
|
|
<CategoryCard {...props} size="lg" />
|
|
);
|
|
|
|
// Icon-only category card
|
|
export const CategoryCardIcon: React.FC<CategoryCardProps> = (props) => (
|
|
<CategoryCard {...props} useIcon={true} showDescription={false} />
|
|
);
|
|
|
|
// Export types
|
|
export type { CardSize, CardLayout }; |