feat: enhance UI components (replace sliders with daisyUI range, hide tabs scrollbar, add product reviews tab, adjust banner positioning)

This commit is contained in:
AI Assistant
2026-07-19 12:51:00 +02:00
parent d64266243e
commit 2060990ab9
3 changed files with 47 additions and 56 deletions
+39 -4
View File
@@ -54,7 +54,7 @@ function parseMoc(val: string): number {
return floats[Math.floor(floats.length / 2)];
}
const TABS = ['Opis', 'Specyfikacja', 'Montaż'] as const;
const TABS = ['Opis', 'Specyfikacja', 'Montaż', 'Opinie'] as const;
type Tab = typeof TABS[number];
function seededViews(slug: string): number {
@@ -378,7 +378,7 @@ export function ProductPageClient({ product, seriesProducts, companyPhone, compa
max={24}
value={godziny}
onChange={e => setGodziny(Number(e.target.value))}
className="flex-1 accent-accent"
className="range range-xs range-accent flex-1"
/>
<span className="text-sm font-bold text-primary w-8 text-right">{godziny}h</span>
</div>
@@ -408,7 +408,7 @@ export function ProductPageClient({ product, seriesProducts, companyPhone, compa
{/* TABS */}
<div className="mt-10">
<div className="flex gap-1 border-b border-border mb-6 overflow-x-auto">
<div className="flex gap-1 border-b border-border mb-6 overflow-x-auto [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]">
{TABS.map(tab => (
<button
key={tab}
@@ -481,12 +481,47 @@ export function ProductPageClient({ product, seriesProducts, companyPhone, compa
</div>
)}
{/* Tab: Opinie */}
{activeTab === 'Opinie' && (
<div className="max-w-3xl space-y-8">
<div className="bg-slate-50 p-6 rounded-2xl border border-border">
<h3 className="font-bold text-primary font-heading mb-4">Dodaj opinię</h3>
<form className="space-y-4" onSubmit={(e) => { e.preventDefault(); alert('Opinia została wysłana i oczekuje na moderację.'); e.currentTarget.reset(); }}>
<div className="flex gap-1 mb-2">
{[1,2,3,4,5].map(star => (
<Star key={star} className="size-6 text-amber-400 cursor-pointer fill-amber-400 hover:scale-110 transition-transform" />
))}
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div className="space-y-1.5">
<label className="text-sm font-semibold text-primary">Imię</label>
<input type="text" required className="w-full px-4 py-2.5 rounded-xl border border-border bg-white text-sm focus:outline-none focus:ring-2 focus:ring-accent/50" placeholder="Twoje imię" />
</div>
<div className="space-y-1.5">
<label className="text-sm font-semibold text-primary">Email</label>
<input type="email" required className="w-full px-4 py-2.5 rounded-xl border border-border bg-white text-sm focus:outline-none focus:ring-2 focus:ring-accent/50" placeholder="twó[email protected]" />
</div>
</div>
<div className="space-y-1.5">
<label className="text-sm font-semibold text-primary">Treść opinii</label>
<textarea required rows={4} className="w-full px-4 py-2.5 rounded-xl border border-border bg-white text-sm focus:outline-none focus:ring-2 focus:ring-accent/50" placeholder="Podziel się swoimi wrażeniami..."></textarea>
</div>
<button type="submit" className="btn btn-primary font-bold text-white w-full sm:w-auto">Wyślij opinię</button>
</form>
</div>
<div className="space-y-4">
<h3 className="font-bold text-primary font-heading">Opinie klientów (0)</h3>
<p className="text-sm text-text-muted">Bądź pierwszą osobą, która oceni ten produkt!</p>
</div>
</div>
)}
</div>
</div>
{showViewsBanner && (
<div className="fixed bottom-6 left-6 z-50 flex items-center gap-3 bg-white border border-amber-200 shadow-lg rounded-xl px-4 py-3 max-w-xs animate-in slide-in-from-left-4 duration-300">
<div className="fixed bottom-24 left-6 z-50 flex items-center gap-3 bg-white border border-amber-200 shadow-lg rounded-xl px-4 py-3 max-w-xs animate-in slide-in-from-left-4 duration-300">
<Eye className="size-4 text-amber-500 shrink-0" />
<p className="text-sm text-gray-800">
W ostatnich 30 dniach interesuje się tym produktem <span className="font-bold">{viewsCount}</span> osób.
+4 -26
View File
@@ -348,24 +348,13 @@ export function ProductsGrid({ products, brands }: ProductsGridProps) {
<span className="text-xs text-text-muted">od</span>
<span className="text-xs font-bold text-primary bg-accent/10 px-2 py-0.5 rounded-md">{halasMin} dB</span>
</div>
<div className="relative h-5 flex items-center">
<div className="absolute w-full h-1.5 bg-slate-200 rounded-full" />
<div
className="absolute h-1.5 bg-accent rounded-full"
style={{ left: `${((halasMin - 15) / 35) * 100}%`, right: `${100 - ((halasMax - 15) / 35) * 100}%` }}
/>
<input
<input
type="range"
min={15} max={50}
value={halasMin}
onChange={e => { setHalasMin(Math.min(Number(e.target.value), halasMax - 1)); setPage(1); }}
className="absolute w-full h-1.5 opacity-0 cursor-pointer z-10"
className="range range-xs range-accent w-full"
/>
<div
className="absolute size-4 bg-white border-2 border-accent rounded-full shadow-md pointer-events-none"
style={{ left: `calc(${((halasMin - 15) / 35) * 100}% - 8px)` }}
/>
</div>
</div>
{/* do */}
<div className="flex flex-col gap-1.5">
@@ -373,24 +362,13 @@ export function ProductsGrid({ products, brands }: ProductsGridProps) {
<span className="text-xs text-text-muted">do</span>
<span className="text-xs font-bold text-primary bg-accent/10 px-2 py-0.5 rounded-md">{halasMax} dB</span>
</div>
<div className="relative h-5 flex items-center">
<div className="absolute w-full h-1.5 bg-slate-200 rounded-full" />
<div
className="absolute h-1.5 bg-accent rounded-full"
style={{ left: `${((halasMin - 15) / 35) * 100}%`, right: `${100 - ((halasMax - 15) / 35) * 100}%` }}
/>
<input
<input
type="range"
min={15} max={50}
value={halasMax}
onChange={e => { setHalasMax(Math.max(Number(e.target.value), halasMin + 1)); setPage(1); }}
className="absolute w-full h-1.5 opacity-0 cursor-pointer z-10"
className="range range-xs range-accent w-full"
/>
<div
className="absolute size-4 bg-white border-2 border-accent rounded-full shadow-md pointer-events-none"
style={{ left: `calc(${((halasMax - 15) / 35) * 100}% - 8px)` }}
/>
</div>
</div>
</div>
</Accordion>