diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index 206d957..a4ab9e5 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -1,6 +1,6 @@ import { Link, useLocation } from 'react-router-dom'; import { useAuth } from '../context/AuthContext'; -import { Swords, Package, Hammer, User, LogOut, Shield, Scroll, Trophy, ShoppingBag } from 'lucide-react'; +import { Swords, Package, Hammer, User, LogOut, Shield, Scroll, Trophy, ShoppingBag, BookOpen } from 'lucide-react'; import { HudBar } from './HudBar'; const NAV = [ @@ -83,6 +83,22 @@ export function Layout({ children }: { children: React.ReactNode }) { ); })} +
+ + + {/* Main content */} diff --git a/frontend/src/pages/GuidePage.tsx b/frontend/src/pages/GuidePage.tsx index d4f53ed..62442b9 100644 --- a/frontend/src/pages/GuidePage.tsx +++ b/frontend/src/pages/GuidePage.tsx @@ -1,8 +1,8 @@ -import { useState } from 'react'; +import { useState, useMemo } from 'react'; import { useQuery } from '@tanstack/react-query'; import { api } from '../api/client'; import type { Monster, Item, Recipe } from '../api/types'; -import { Swords, Shield, Map as MapIcon, Hammer, ShoppingBag, BookOpen, Sparkles } from 'lucide-react'; +import { Swords, Shield, Map as MapIcon, Hammer, ShoppingBag, BookOpen, Sparkles, Search } from 'lucide-react'; // ── Data fetching (public endpoints, no auth) ── @@ -419,12 +419,26 @@ function ShopTab({ items }: { items: Item[] }) { export function GuidePage() { const [tab, setTab] = useState('start'); + const [search, setSearch] = useState(''); const { data: monsters = [] } = useQuery({ queryKey: ['guide-monsters'], queryFn: guideApi.monsters }); const { data: items = [] } = useQuery({ queryKey: ['guide-items'], queryFn: guideApi.items }); const { data: materials = [] } = useQuery({ queryKey: ['guide-materials'], queryFn: guideApi.materials }); const { data: recipes = [] } = useQuery({ queryKey: ['guide-recipes'], queryFn: guideApi.recipes }); + const q = search.toLowerCase().trim(); + const filteredMonsters = useMemo(() => q ? monsters.filter(m => m.name.toLowerCase().includes(q) || m.zone?.toLowerCase().includes(q)) : monsters, [monsters, q]); + const filteredItems = useMemo(() => q ? items.filter(i => i.name.toLowerCase().includes(q) || i.rarity.toLowerCase().includes(q) || i.description?.toLowerCase().includes(q)) : items, [items, q]); + const filteredRecipes = useMemo(() => { + if (!q) return recipes; + const matMap = new Map(materials.map(m => [m.id, m])); + return recipes.filter(r => + r.name.toLowerCase().includes(q) || + r.resultItem?.name.toLowerCase().includes(q) || + r.ingredients.some(ing => matMap.get(ing.materialId)?.name.toLowerCase().includes(q)) + ); + }, [recipes, materials, q]); + return (
{/* Header */} @@ -437,6 +451,31 @@ export function GuidePage() {

+ {/* Search */} +
+ + setSearch(e.target.value)} + placeholder="Rechercher un monstre, item, matériau, recette…" + style={{ + width: '100%', padding: '10px 12px 10px 34px', fontSize: 13, + background: '#1e2535', border: '1px solid #2a3448', borderRadius: 8, + color: '#dce4f0', outline: 'none', boxSizing: 'border-box', + }} + /> + {search && ( + + )} +
+ {/* Tab navigation */}
} {tab === 'zones' && } - {tab === 'bestiary' && } - {tab === 'items' && } - {tab === 'craft' && } + {tab === 'bestiary' && } + {tab === 'items' && } + {tab === 'craft' && } {tab === 'forge' && } - {tab === 'shop' && } + {tab === 'shop' && }
); }