feat: complete website implementation
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { Search } from "lucide-react";
|
||||
import { getProducts } from "@/content/products";
|
||||
import Link from "next/link";
|
||||
import Image from "next/image";
|
||||
import { formatCurrency } from "@/lib/utils";
|
||||
|
||||
export function GlobalSearch() {
|
||||
const [query, setQuery] = useState("");
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const products = getProducts();
|
||||
const results = query.length > 1
|
||||
? products.filter(p => p.name.toLowerCase().includes(query.toLowerCase()) || p.brand.toLowerCase().includes(query.toLowerCase()) || p.category.toLowerCase().includes(query.toLowerCase()))
|
||||
: [];
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
onClick={() => setIsOpen(true)}
|
||||
className="p-2 text-primary hover:text-accent hover:bg-background rounded-lg transition-colors outline-none cursor-pointer"
|
||||
aria-label="Szukaj na stronie"
|
||||
>
|
||||
<Search className="size-5" />
|
||||
</button>
|
||||
|
||||
<dialog className={`modal ${isOpen ? "modal-open" : ""}`}>
|
||||
<div className="modal-box p-0 max-w-2xl bg-white rounded-2xl overflow-hidden mt-[-20vh]">
|
||||
<div className="flex items-center border-b border-border px-4 py-3 bg-slate-50">
|
||||
<Search className="size-5 text-accent mr-3 shrink-0" />
|
||||
<input
|
||||
autoFocus
|
||||
type="text"
|
||||
placeholder="Wpisz nazwę klimatyzatora (np. Rotenso, Pular)..."
|
||||
className="flex-1 outline-none text-base placeholder:text-text-muted/50 bg-transparent py-2 text-primary font-medium"
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
/>
|
||||
<button onClick={() => setIsOpen(false)} className="text-xs font-semibold text-text-muted hover:text-primary transition-colors bg-white px-2 py-1 rounded border border-border shadow-sm">
|
||||
ESC
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{query.length > 1 ? (
|
||||
<div className="max-h-[60vh] overflow-y-auto p-2 bg-white">
|
||||
{results.length > 0 ? (
|
||||
<div className="flex flex-col gap-1">
|
||||
{results.map((product) => (
|
||||
<Link
|
||||
key={product.slug}
|
||||
href={`/sklep/${product.slug}`}
|
||||
onClick={() => setIsOpen(false)}
|
||||
className="flex items-center gap-4 p-3 hover:bg-slate-50 rounded-lg transition-colors group border border-transparent hover:border-border"
|
||||
>
|
||||
<div className="w-16 h-16 bg-white border border-border rounded-md overflow-hidden relative shrink-0">
|
||||
<Image
|
||||
src={product.image || 'https://images.unsplash.com/photo-1621905251189-08b45d6a269e?w=800&q=80'}
|
||||
alt={product.name}
|
||||
fill
|
||||
className="object-contain p-1 mix-blend-multiply"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 flex flex-col">
|
||||
<span className="text-[10px] font-bold text-text-muted uppercase tracking-wider">{product.brand}</span>
|
||||
<span className="text-sm font-semibold text-primary group-hover:text-accent transition-colors">{product.name}</span>
|
||||
<span className="text-xs text-text-muted mt-0.5">{product.power} kW • {product.category}</span>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<span className="text-sm font-bold text-primary block">{formatCurrency(product.price)}</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="p-8 text-center text-text-muted">
|
||||
Brak wyników dla <span className="font-semibold">"{query}"</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="p-8 text-center text-text-muted/50 text-sm bg-white">
|
||||
Wpisz co najmniej 2 znaki, aby rozpocząć wyszukiwanie w sklepie
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<form method="dialog" className="modal-backdrop">
|
||||
<button onClick={() => setIsOpen(false)}>close</button>
|
||||
</form>
|
||||
</dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user