diff --git a/app/api/busca/route.js b/app/api/busca/route.js new file mode 100644 index 0000000..0415133 --- /dev/null +++ b/app/api/busca/route.js @@ -0,0 +1,12 @@ +import { construirIndiceBusca } from "@/lib/searchIndex"; + +export const dynamic = "force-static"; + +/** Índice de busca carregado sob demanda pelo diálogo de pesquisa (Ctrl/⌘+K). */ +export function GET() { + return Response.json(construirIndiceBusca(), { + headers: { + "Cache-Control": "no-cache, no-store, must-revalidate", + }, + }); +} diff --git a/components/ConnectionsDiagram.jsx b/components/ConnectionsDiagram.jsx index ccd98ed..395b71b 100644 --- a/components/ConnectionsDiagram.jsx +++ b/components/ConnectionsDiagram.jsx @@ -1,7 +1,8 @@ "use client"; -import { useState, useEffect, useMemo, useRef } from "react"; +import { useState, useEffect, useMemo, useRef, Suspense } from "react"; import { createPortal } from "react-dom"; +import { usePathname, useRouter, useSearchParams } from "next/navigation"; import { AlertTriangle, CheckCircle, List, Grid, Search, Sliders, X, Zap } from "lucide-react"; /* @@ -41,7 +42,25 @@ const type_colors = { nc: "#94a3b8", // muted gray }; -export default function ConnectionsDiagram({ connections, serie }) { +/** + * Aceita ?pinos=28,30,31&motivo=... (gerado pela busca do site): mostra só + * esses pinos, pelo número físico, com um aviso para voltar à lista completa. + * O Suspense é exigido por useSearchParams em páginas estáticas. + */ +export default function ConnectionsDiagram(props) { + return ( + + + + ); +} + +function ConnectionsDiagramInner({ connections, serie }) { + const params = useSearchParams(); + const pathname = usePathname(); + const router = useRouter(); + const pinosFiltro = useMemo(() => new Set((params.get("pinos") ?? "").split(",").filter(Boolean)), [params]); + const motivoFiltro = params.get("motivo") ?? ""; const [activeFilter, setActiveFilter] = useState("All"); const [selectedConnection, setSelectedConnection] = useState(null); const [searchQuery, setSearchQuery] = useState(""); @@ -60,7 +79,8 @@ export default function ConnectionsDiagram({ connections, serie }) { searchQuery === "" || connection.nome.toLowerCase().includes(searchQuery.toLowerCase()) || connection.numero.toString().toLowerCase().includes(searchQuery.toLowerCase()); - return matchesFilter && matchesSearch; + const matchesPinos = pinosFiltro.size === 0 || pinosFiltro.has(String(connection.numero)); + return matchesFilter && matchesSearch && matchesPinos; }; const getCategoryColor = (category) => { @@ -70,7 +90,9 @@ export default function ConnectionsDiagram({ connections, serie }) { const nomeCategoria = (cat) => (cat === "Strapping" ? "Inicialização" : cat); - const visibleConnections = useMemo(() => connections.filter(isConnectionVisible), [connections, activeFilter, searchQuery]); + const visibleConnections = useMemo(() => connections.filter(isConnectionVisible), [connections, activeFilter, searchQuery, pinosFiltro]); + + const mostrarTodos = () => router.replace(`${pathname}#connections`, { scroll: false }); const abrir = (connection, evento) => { gatilhoRef.current = evento.currentTarget; @@ -137,6 +159,18 @@ export default function ConnectionsDiagram({ connections, serie }) {

+ {pinosFiltro.size > 0 && ( +
+

+ Filtrado pela busca: {motivoFiltro || "pinos selecionados"} ({pinosFiltro.size}{" "} + {pinosFiltro.size === 1 ? "pino" : "pinos"}) +

+ +
+ )} +
@@ -191,7 +225,7 @@ export default function ConnectionsDiagram({ connections, serie }) {
diff --git a/components/Header.jsx b/components/Header.jsx index ca4be7c..67c72ff 100644 --- a/components/Header.jsx +++ b/components/Header.jsx @@ -4,6 +4,7 @@ import { useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; import Link from "next/link"; import Logo from "@/components/Logo"; +import SearchDialog from "@/components/SearchDialog"; import { usePathname } from "next/navigation"; import { useTheme } from "next-themes"; import { @@ -185,6 +186,7 @@ export default function Header() {