67 lines
2.0 KiB
TypeScript
67 lines
2.0 KiB
TypeScript
|
import { useEffect, useState } from "preact/hooks";
|
||
|
import { RepoData } from "../api/repo.ts";
|
||
|
import { SearchBar } from "../components/SearchBar.tsx";
|
||
|
import RepoViewer from "./RepoViewer.tsx";
|
||
|
|
||
|
|
||
|
export default function Search(props:{query?: string}) {
|
||
|
const [searchValue, setSearchValue] = useState(props.query ?? "");
|
||
|
const [searchResults, setSearchResults] = useState<RepoData[] | null>(null);
|
||
|
useEffect(() => {
|
||
|
// on mount
|
||
|
search(searchValue);
|
||
|
}, [])
|
||
|
useEffect(() => {
|
||
|
const callback = (ev: PopStateEvent)=>{
|
||
|
// pop state
|
||
|
if(ev.state && ev.state.q){
|
||
|
const q = ev.state.q;
|
||
|
setSearchValue(q);
|
||
|
search(q);
|
||
|
}
|
||
|
else{
|
||
|
setSearchValue("");
|
||
|
search("");
|
||
|
}
|
||
|
}
|
||
|
addEventListener("popstate", callback);
|
||
|
return ()=>{
|
||
|
removeEventListener("popstate", callback);
|
||
|
}
|
||
|
}, []);
|
||
|
|
||
|
useEffect(() => {
|
||
|
if (searchValue) {
|
||
|
document.title = `Search: ${searchValue}`;
|
||
|
} else {
|
||
|
document.title = "Search";
|
||
|
}
|
||
|
},[searchValue]);
|
||
|
|
||
|
return (<>
|
||
|
<SearchBar value={searchValue} onChange={(v) => {setSearchValue(v)}} onSubmit={()=>{
|
||
|
//window.location.href = `/?q=${searchValue}`;
|
||
|
history.pushState({q:searchValue}, "", `/?q=${searchValue}`);
|
||
|
search(searchValue);
|
||
|
}} />
|
||
|
<RepoViewer repos={searchResults ?? []} />
|
||
|
</>);
|
||
|
function search(searchValue: string) {
|
||
|
if (searchValue) {
|
||
|
console.log("searching", searchValue);
|
||
|
fetch(`/api/_query?q=${searchValue}`)
|
||
|
.then((res) => res.json())
|
||
|
.then((data) => {
|
||
|
setSearchResults(data);
|
||
|
}
|
||
|
);
|
||
|
} else {
|
||
|
fetch(`/api/_list`)
|
||
|
.then((res) => res.json())
|
||
|
.then((data) => {
|
||
|
setSearchResults(data);
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|