Refactor to multi-category catalog with polished light mode
- Restructure from single filament table to multi-category product catalog (filamenti, stampaci, ploce, mlaznice, delovi, oprema) - Add shared layout components (SiteHeader, SiteFooter, CategoryNav, Breadcrumb) - Add reusable UI primitives (Badge, Button, Card, Modal, PriceDisplay, EmptyState) - Add catalog components (CatalogPage, ProductTable, ProductGrid, FilamentCard, ProductCard) - Add admin dashboard with sidebar navigation and category management - Add product API endpoints and database migrations - Add SEO pages (politika-privatnosti, uslovi-koriscenja, robots.txt, sitemap.xml) - Fix light mode: gradient text contrast, category nav accessibility, surface tokens, card shadows, CTA section theming
This commit is contained in:
125
src/components/catalog/FilamentRow.tsx
Normal file
125
src/components/catalog/FilamentRow.tsx
Normal file
@@ -0,0 +1,125 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { Filament } from '@/src/types/filament';
|
||||
|
||||
interface FilamentRowProps {
|
||||
filament: Filament;
|
||||
}
|
||||
|
||||
export function FilamentRow({ filament }: FilamentRowProps) {
|
||||
const hasRefill = filament.refill > 0;
|
||||
const hasSpool = filament.spulna > 0;
|
||||
|
||||
// Parse prices from the cena field (format: "3499" or "3499/3999")
|
||||
let refillPrice = 3499;
|
||||
let spoolPrice = 3999;
|
||||
|
||||
if (filament.cena) {
|
||||
const prices = filament.cena.split('/');
|
||||
if (prices.length === 1) {
|
||||
refillPrice = parseInt(prices[0]) || 3499;
|
||||
spoolPrice = parseInt(prices[0]) || 3999;
|
||||
} else if (prices.length === 2) {
|
||||
refillPrice = parseInt(prices[0]) || 3499;
|
||||
spoolPrice = parseInt(prices[1]) || 3999;
|
||||
}
|
||||
}
|
||||
|
||||
const saleActive = filament.sale_active && filament.sale_percentage;
|
||||
const saleRefillPrice = saleActive
|
||||
? Math.round(refillPrice * (1 - filament.sale_percentage! / 100))
|
||||
: refillPrice;
|
||||
const saleSpoolPrice = saleActive
|
||||
? Math.round(spoolPrice * (1 - filament.sale_percentage! / 100))
|
||||
: spoolPrice;
|
||||
|
||||
return (
|
||||
<tr className="hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors">
|
||||
<td className="px-2 sm:px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
|
||||
{filament.tip}
|
||||
</td>
|
||||
<td className="px-2 sm:px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
|
||||
{filament.finish}
|
||||
</td>
|
||||
<td className="px-2 sm:px-6 py-4 whitespace-nowrap">
|
||||
<div className="flex items-center gap-1 sm:gap-2">
|
||||
{filament.boja_hex && (
|
||||
<div
|
||||
className="w-5 h-5 sm:w-7 sm:h-7 rounded border border-gray-300 dark:border-gray-600 flex-shrink-0"
|
||||
style={{ backgroundColor: filament.boja_hex }}
|
||||
title={filament.boja_hex}
|
||||
/>
|
||||
)}
|
||||
<span className="text-xs sm:text-sm text-gray-900 dark:text-gray-100">
|
||||
{filament.boja}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2 sm:px-6 py-4 whitespace-nowrap text-sm">
|
||||
{hasRefill ? (
|
||||
<span className="text-green-600 dark:text-green-400 font-bold">{filament.refill}</span>
|
||||
) : (
|
||||
<span className="text-gray-400 dark:text-gray-500">0</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="px-2 sm:px-6 py-4 whitespace-nowrap text-sm">
|
||||
{hasSpool ? (
|
||||
<span className="text-blue-500 dark:text-blue-400 font-bold">{filament.spulna}</span>
|
||||
) : (
|
||||
<span className="text-gray-400 dark:text-gray-500">0</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="px-2 sm:px-6 py-4 whitespace-nowrap text-sm text-gray-900 dark:text-gray-100">
|
||||
{filament.kolicina}
|
||||
</td>
|
||||
<td className="px-2 sm:px-6 py-4 whitespace-nowrap text-sm font-bold text-gray-900 dark:text-white">
|
||||
{!hasRefill && !hasSpool ? (
|
||||
'-'
|
||||
) : (
|
||||
<>
|
||||
{hasRefill && (
|
||||
<span
|
||||
className={
|
||||
saleActive
|
||||
? 'line-through text-gray-500 dark:text-gray-400'
|
||||
: 'text-green-600 dark:text-green-400'
|
||||
}
|
||||
>
|
||||
{refillPrice.toLocaleString('sr-RS')}
|
||||
</span>
|
||||
)}
|
||||
{hasRefill && saleActive && (
|
||||
<span className="text-green-600 dark:text-green-400 font-bold ml-1">
|
||||
{saleRefillPrice.toLocaleString('sr-RS')}
|
||||
</span>
|
||||
)}
|
||||
{hasRefill && hasSpool && <span className="mx-1">/</span>}
|
||||
{hasSpool && (
|
||||
<span
|
||||
className={
|
||||
saleActive
|
||||
? 'line-through text-gray-500 dark:text-gray-400'
|
||||
: 'text-blue-500 dark:text-blue-400'
|
||||
}
|
||||
>
|
||||
{spoolPrice.toLocaleString('sr-RS')}
|
||||
</span>
|
||||
)}
|
||||
{hasSpool && saleActive && (
|
||||
<span className="text-blue-500 dark:text-blue-400 font-bold ml-1">
|
||||
{saleSpoolPrice.toLocaleString('sr-RS')}
|
||||
</span>
|
||||
)}
|
||||
<span className="ml-1 text-gray-600 dark:text-gray-400">RSD</span>
|
||||
{saleActive && (
|
||||
<span className="ml-2 inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200">
|
||||
-{filament.sale_percentage}%
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user