Updated search bar

This commit is contained in:
2025-09-29 15:42:53 +02:00
parent 37953e5f9b
commit 7e1fc74660
2 changed files with 106 additions and 11 deletions

View File

@@ -1,6 +1,6 @@
import { Settings } from "lucide-react"
import Link from "next/link"
import { SearchBar } from "./search-bar"
import { TopSearchBar } from "./search-bar"
import { ThemeSwitcher } from "./theme-switcher"
export default function Header({ searchBar = false }: { searchBar?: boolean }) {
@@ -10,7 +10,7 @@ export default function Header({ searchBar = false }: { searchBar?: boolean }) {
<Link href="/">
<h1 className="text-lg font-semibold">HypStats</h1>
</Link>
{searchBar && <SearchBar navbar />}
{searchBar && <TopSearchBar />}
<div className="flex gap-2 items-center">
<ThemeSwitcher />
<Link href="/settings">

View File

@@ -1,13 +1,13 @@
"use client"
import { Input } from "@/components/ui/input"
import { cn } from "@/lib/utils"
import { capitalizeFirstLetter, cn } from "@/lib/utils"
import { Search } from "lucide-react"
import { useRouter } from "next/navigation"
import { useEffect, useRef, useState } from "react"
import { Button } from "./ui/button"
export function SearchBar({ navbar }: { navbar?: boolean }) {
export function TopSearchBar() {
const [input, setInput] = useState("")
const ref = useRef<HTMLInputElement>(null)
const router = useRouter()
@@ -31,23 +31,19 @@ export function SearchBar({ navbar }: { navbar?: boolean }) {
async function handleSearch(e: React.FormEvent) {
e.preventDefault()
if (input.trim()) {
router.push(`/player/${encodeURIComponent(input.trim())}`)
}
if (navbar) {
setInput("")
ref.current?.blur()
}
}
return (
<div className={cn("w-full max-w-4xl px-4", !navbar && "mt-8")}>
<div className={cn("w-full max-w-4xl px-4")}>
<form onSubmit={handleSearch}>
<div className="flex gap-2">
<Input
type="text"
placeholder={!navbar ? "Search for a player..." : ""}
className="px-5"
ref={ref}
value={input}
@@ -66,3 +62,102 @@ export function SearchBar({ navbar }: { navbar?: boolean }) {
</div>
)
}
const pages = ["player", "guild"] as const
const guildTypes = ["player", "name", "id"] as const
export function SearchBar() {
const [input, setInput] = useState("")
const [selected, setSelected] = useState<typeof pages[number]>("player")
const [guildType, setGuildType] = useState<typeof guildTypes[number]>("player")
const ref = useRef<HTMLInputElement>(null)
const router = useRouter()
useEffect(() => {
const controller = new AbortController()
window.addEventListener("keydown", (ev) => {
if (!ref.current) return
if (ev.ctrlKey && ev.key === "k") {
ev.preventDefault()
ref.current.focus()
}
}, { signal: controller.signal })
return () => {
controller.abort()
}
})
async function handleSearch(e: React.FormEvent) {
e.preventDefault()
if (!input.trim()) return
switch (selected) {
case "player":
router.push(`/player/${encodeURIComponent(input.trim())}`)
break
case "guild":
router.push(`/guild/${encodeURIComponent(input.trim())}?type=${guildType}`)
break
default:
router.push(`/player/${encodeURIComponent(input.trim())}`)
break
}
}
return (
<div className="px-4 mt-8 w-full max-w-4xl">
<form onSubmit={handleSearch}>
<div className="flex gap-2">
<Input
type="text"
placeholder={`Search for a ${selected}${selected === "player" ? "..." : " using " + guildType + "..."} `}
className="px-5"
ref={ref}
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") {
handleSearch(e)
}
}}
/>
<Button type="submit">
<Search />
</Button>
</div>
<div className="flex gap-4 items-center mt-5">
{pages.map(p => {
return (
<Button
key={p}
variant={selected === p ? "default" : "outline"}
onClick={() => setSelected(p)}
>
{capitalizeFirstLetter(p)}
</Button>
)
})}
</div>
{selected === "guild" && (
<div className="flex gap-4 items-center mt-5">
{guildTypes.map(gt => {
return (
<Button
key={gt}
variant={guildType === gt ? "default" : "outline"}
onClick={() => setGuildType(gt)}
>
{capitalizeFirstLetter(gt)}
</Button>
)
})}
</div>
)}
</form>
</div>
)
}