Retour au catalogue

Search Fullscreen

Recherche plein ecran avec categories et recherches recentes.

searchsimple Both Responsive a11y
minimaluniversalstacked
Theme
"use client";

import { useState } from "react";
import { Search, X, Clock, ArrowRight, Tag } from "lucide-react";

interface SearchCategory {
  label: string;
  count: number;
}

interface SearchFullscreenProps {
  placeholder?: string;
}

const mockCategories: SearchCategory[] = [
  { label: "Articles", count: 42 },
  { label: "Produits", count: 128 },
  { label: "Pages", count: 15 },
  { label: "FAQ", count: 23 },
];

const mockRecent = [
  "Design system composants",
  "Tarifs entreprise",
  "Guide integration API",
  "Contact support technique",
];

const mockSuggestions = [
  "Comment demarrer",
  "Fonctionnalites premium",
  "Cas d'utilisation",
  "Documentation API",
];

export default function SearchFullscreen({
  placeholder = "Que recherchez-vous ?",
}: SearchFullscreenProps) {
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState("");
  const [activeCategory, setActiveCategory] = useState<string | null>(null);

  return (
    <div className="flex items-center justify-center py-12 px-6">
      <button
        onClick={() => setOpen(true)}
        className="flex items-center gap-3 px-5 py-3 rounded-xl text-sm transition-all duration-200 cursor-pointer"
        style={{
          background: "var(--color-background-card)",
          border: "1px solid var(--color-border)",
          color: "var(--color-foreground-muted)",
        }}
      >
        <Search size={16} />
        Rechercher sur le site...
      </button>

      {open && (
        <div
          className="fixed inset-0 z-50 flex flex-col"
          style={{
            background: "var(--color-background)",
            animation: "fs-search-in 0.25s ease-out",
          }}
        >
          {/* Header */}
          <div
            className="flex items-center gap-4 px-6 py-4 shrink-0"
            style={{ borderBottom: "1px solid var(--color-border)" }}
          >
            <Search size={20} style={{ color: "var(--color-foreground-light)" }} />
            <input
              type="text"
              value={query}
              onChange={(e) => setQuery(e.target.value)}
              placeholder={placeholder}
              autoFocus
              className="flex-1 bg-transparent text-lg outline-none"
              style={{ color: "var(--color-foreground)" }}
            />
            <button
              onClick={() => { setOpen(false); setQuery(""); }}
              className="p-2 rounded-lg cursor-pointer transition-colors duration-150"
              style={{ color: "var(--color-foreground-muted)" }}
            >
              <X size={20} />
            </button>
          </div>

          {/* Categories */}
          <div
            className="flex items-center gap-2 px-6 py-3 overflow-x-auto shrink-0"
            style={{ borderBottom: "1px solid var(--color-border)" }}
          >
            {mockCategories.map((cat) => (
              <button
                key={cat.label}
                onClick={() => setActiveCategory(activeCategory === cat.label ? null : cat.label)}
                className="flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium whitespace-nowrap cursor-pointer transition-all duration-200"
                style={{
                  background: activeCategory === cat.label ? "var(--color-accent)" : "var(--color-background-alt)",
                  color: activeCategory === cat.label ? "var(--color-background)" : "var(--color-foreground-muted)",
                  border: `1px solid ${activeCategory === cat.label ? "var(--color-accent)" : "var(--color-border)"}`,
                }}
              >
                <Tag size={12} />
                {cat.label}
                <span className="opacity-60">({cat.count})</span>
              </button>
            ))}
          </div>

          {/* Body */}
          <div className="flex-1 overflow-y-auto px-6 py-8">
            <div className="mx-auto max-w-2xl">
              {/* Recent */}
              <div className="mb-10">
                <h3
                  className="text-xs font-semibold uppercase tracking-wider mb-4"
                  style={{ color: "var(--color-foreground-light)" }}
                >
                  Recherches recentes
                </h3>
                <div className="flex flex-col gap-1">
                  {mockRecent.map((item) => (
                    <button
                      key={item}
                      className="flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm text-left transition-colors duration-150 cursor-pointer"
                      style={{ color: "var(--color-foreground-muted)" }}
                      onMouseEnter={(e) => {
                        (e.currentTarget as HTMLElement).style.background = "var(--color-background-alt)";
                      }}
                      onMouseLeave={(e) => {
                        (e.currentTarget as HTMLElement).style.background = "transparent";
                      }}
                    >
                      <Clock size={14} style={{ color: "var(--color-foreground-light)" }} />
                      <span className="flex-1">{item}</span>
                      <ArrowRight size={14} className="opacity-0 group-hover:opacity-100" />
                    </button>
                  ))}
                </div>
              </div>

              {/* Suggestions */}
              <div>
                <h3
                  className="text-xs font-semibold uppercase tracking-wider mb-4"
                  style={{ color: "var(--color-foreground-light)" }}
                >
                  Suggestions
                </h3>
                <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
                  {mockSuggestions.map((item) => (
                    <button
                      key={item}
                      className="flex items-center gap-3 px-4 py-3 rounded-xl text-sm text-left transition-all duration-200 cursor-pointer"
                      style={{
                        background: "var(--color-background-card)",
                        border: "1px solid var(--color-border)",
                        color: "var(--color-foreground)",
                      }}
                      onMouseEnter={(e) => {
                        (e.currentTarget as HTMLElement).style.borderColor = "var(--color-accent)";
                      }}
                      onMouseLeave={(e) => {
                        (e.currentTarget as HTMLElement).style.borderColor = "var(--color-border)";
                      }}
                    >
                      <Search size={14} style={{ color: "var(--color-accent)" }} />
                      {item}
                    </button>
                  ))}
                </div>
              </div>
            </div>
          </div>
        </div>
      )}

      <style>{`
        @keyframes fs-search-in {
          from { opacity: 0; }
          to   { opacity: 1; }
        }
      `}</style>
    </div>
  );
}

Avis

Search Fullscreen — React Search Section — Incubator