feat: optymalizacja GlobalSearch, nawigacji oraz filtrów w sklepie
This commit is contained in:
@@ -1,20 +1,40 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { useState, useRef, useEffect, useMemo } 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";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
const allProducts = getProducts();
|
||||
|
||||
export function GlobalSearch() {
|
||||
const [query, setQuery] = useState("");
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
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()))
|
||||
: [];
|
||||
const results = useMemo(() => {
|
||||
if (query.length < 2) return [];
|
||||
const q = query.toLowerCase();
|
||||
return allProducts
|
||||
.filter(p =>
|
||||
p.name.toLowerCase().includes(q) ||
|
||||
p.brand.toLowerCase().includes(q) ||
|
||||
p.category.toLowerCase().includes(q) ||
|
||||
(p.sku && p.sku.toLowerCase().includes(q))
|
||||
)
|
||||
.slice(0, 20);
|
||||
}, [query]);
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent) => {
|
||||
if (e.key === 'Enter' && query.length > 1) {
|
||||
router.push(`/sklep?search=${encodeURIComponent(query)}`);
|
||||
setIsOpen(false);
|
||||
setQuery('');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -29,7 +49,15 @@ export function GlobalSearch() {
|
||||
<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" />
|
||||
<button aria-label="Szukaj" onClick={() => {
|
||||
if (query.length > 1) {
|
||||
router.push(`/sklep?search=${encodeURIComponent(query)}`);
|
||||
setIsOpen(false);
|
||||
setQuery('');
|
||||
}
|
||||
}}>
|
||||
<Search className="size-5 text-accent mr-3 shrink-0 hover:text-primary transition-colors cursor-pointer" />
|
||||
</button>
|
||||
<input
|
||||
autoFocus
|
||||
type="text"
|
||||
@@ -37,8 +65,9 @@ export function GlobalSearch() {
|
||||
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)}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
<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">
|
||||
<button type="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>
|
||||
|
||||
@@ -76,20 +76,33 @@ export function Header() {
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const miastaSections = [
|
||||
{
|
||||
title: "Montaż w Twoim mieście",
|
||||
title: "Dolny Śląsk — centrum",
|
||||
items: [
|
||||
{ label: "Klimatyzacja Wrocław", href: "/klimatyzacja/wroclaw", description: "Montaż i serwis we Wrocławiu" },
|
||||
{ label: "Klimatyzacja Legnica", href: "/klimatyzacja/legnica", description: "Obsługujemy Legnicę i okolice" },
|
||||
{ label: "Klimatyzacja Wałbrzych", href: "/klimatyzacja/walbrzych", description: "Montaż w Wałbrzychu" },
|
||||
{ label: "Klimatyzacja Jelenia Góra", href: "/klimatyzacja/jelenia-gora", description: "Dolny Śląsk — południe" },
|
||||
{ label: "→ Wszystkie miasta", href: "/klimatyzacja#miasta", description: "Cały Dolny Śląsk" },
|
||||
{ label: "Klimatyzacja Oława", href: "/klimatyzacja/olawa", description: "25 km od Wrocławia" },
|
||||
{ label: "Klimatyzacja Oleśnica", href: "/klimatyzacja/olesnica", description: "30 km od Wrocławia" },
|
||||
{ label: "Klimatyzacja Środa Śląska", href: "/klimatyzacja/sroda-slaska", description: "35 km od Wrocławia" },
|
||||
{ label: "Klimatyzacja Trzebnica", href: "/klimatyzacja/trzebnica", description: "25 km od Wrocławia" },
|
||||
{ label: "Klimatyzacja Siechnice", href: "/klimatyzacja/siechnice", description: "15 km od Wrocławia" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Dolny Śląsk — regiony",
|
||||
items: [
|
||||
{ label: "Klimatyzacja Legnica", href: "/klimatyzacja/legnica", description: "Legnica i okolice" },
|
||||
{ label: "Klimatyzacja Wałbrzych", href: "/klimatyzacja/walbrzych", description: "Wałbrzych i Kotlina" },
|
||||
{ label: "Klimatyzacja Jelenia Góra", href: "/klimatyzacja/jelenia-gora", description: "Karkonosze i okolice" },
|
||||
{ label: "Klimatyzacja Lubin", href: "/klimatyzacja/lubin", description: "Zagłębie Miedziowe" },
|
||||
{ label: "Klimatyzacja Głogów", href: "/klimatyzacja/glogow", description: "Głogów i powiat" },
|
||||
{ label: "Klimatyzacja Świdnica", href: "/klimatyzacja/swidnica", description: "Świdnica i okolice" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* ----------------- DESKTOP: TOP BAR ----------------- */}
|
||||
@@ -156,6 +169,11 @@ export function Header() {
|
||||
sections={acSections}
|
||||
align="left"
|
||||
/>
|
||||
<NavDropdown
|
||||
label="Miasta"
|
||||
sections={miastaSections}
|
||||
align="left"
|
||||
/>
|
||||
<Link
|
||||
href="/pompy-ciepla"
|
||||
className="text-sm font-medium text-primary hover:text-accent transition-colors"
|
||||
|
||||
@@ -100,6 +100,42 @@ export function MobileMenu({ isOpen, onClose }: MobileMenuProps) {
|
||||
</div>
|
||||
</details>
|
||||
|
||||
{/* Nowa sekcja: Miasta */}
|
||||
<div className="border-b border-border py-3">
|
||||
<details className="collapse collapse-arrow rounded-none">
|
||||
<summary className="collapse-title text-sm font-medium text-primary hover:text-accent py-0 px-0 min-h-0">
|
||||
Montaż w miastach
|
||||
</summary>
|
||||
<div className="collapse-content px-0 pb-2">
|
||||
<ul className="flex flex-col gap-2 pl-4 pb-2 mt-2">
|
||||
{[
|
||||
{ label: "Klimatyzacja Wrocław", href: "/klimatyzacja/wroclaw" },
|
||||
{ label: "Klimatyzacja Legnica", href: "/klimatyzacja/legnica" },
|
||||
{ label: "Klimatyzacja Wałbrzych", href: "/klimatyzacja/walbrzych" },
|
||||
{ label: "Klimatyzacja Jelenia Góra", href: "/klimatyzacja/jelenia-gora" },
|
||||
{ label: "Klimatyzacja Lubin", href: "/klimatyzacja/lubin" },
|
||||
{ label: "Klimatyzacja Głogów", href: "/klimatyzacja/glogow" },
|
||||
{ label: "Klimatyzacja Świdnica", href: "/klimatyzacja/swidnica" },
|
||||
{ label: "Klimatyzacja Oława", href: "/klimatyzacja/olawa" },
|
||||
{ label: "Klimatyzacja Oleśnica", href: "/klimatyzacja/olesnica" },
|
||||
{ label: "→ Wszystkie miasta", href: "/klimatyzacja#miasta" },
|
||||
].map((item, idx) => (
|
||||
<li key={idx}>
|
||||
<Link
|
||||
href={item.href}
|
||||
onClick={onClose}
|
||||
className="text-sm text-text-muted hover:text-accent transition-colors flex items-center justify-between py-1"
|
||||
>
|
||||
<span>{item.label}</span>
|
||||
<ChevronRight className="size-3.5 opacity-60" />
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
{/* 2. Pompy Ciepła */}
|
||||
<div className="border-b border-border py-3">
|
||||
<Link
|
||||
|
||||
Reference in New Issue
Block a user