feat: enhance UI components (replace sliders with daisyUI range, hide tabs scrollbar, add product reviews tab, adjust banner positioning)
This commit is contained in:
@@ -395,22 +395,11 @@ export function KalkulatorClient({ products }: Props) {
|
||||
<span className="text-xs text-text-muted">Powierzchnia</span>
|
||||
<span className="text-xs font-bold text-primary bg-accent/10 px-2 py-0.5 rounded-md">{p.m2} m²</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={{ width: `${((p.m2 - 5) / 95) * 100}%` }}
|
||||
/>
|
||||
<input
|
||||
type="range" min={5} max={100} step={5} value={p.m2}
|
||||
onChange={e => updateRoom(i, Number(e.target.value))}
|
||||
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(${((p.m2 - 5) / 95) * 100}% - 8px)` }}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-between text-xs text-text-muted">
|
||||
<span>5 m²</span>
|
||||
<span>100 m²</span>
|
||||
@@ -712,22 +701,11 @@ export function KalkulatorClient({ products }: Props) {
|
||||
<span className="text-xs text-text-muted">Budżet</span>
|
||||
<span className="text-xs font-bold text-primary bg-accent/10 px-2 py-0.5 rounded-md">{budget.toLocaleString('pl-PL')} zł</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={{ width: `${((budget - 3000) / 22000) * 100}%` }}
|
||||
/>
|
||||
<input
|
||||
type="range" min={3000} max={25000} step={500} value={budget}
|
||||
onChange={e => setBudget(Number(e.target.value))}
|
||||
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(${((budget - 3000) / 22000) * 100}% - 8px)` }}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex justify-between text-xs text-text-muted">
|
||||
<span>3 000 zł</span>
|
||||
<span>25 000 zł</span>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
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
|
||||
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>
|
||||
|
||||
Reference in New Issue
Block a user