import { Comic, ComicBubble, ComicPage } from "@prisma/client"; import { Hit, SearchResponse } from "meilisearch"; import { GetServerSideProps } from "next"; import Head from "next/head"; import { useRouter } from "next/router"; import { ParsedUrlQuery } from "querystring"; import { useEffect, useState } from "react"; import { LinkButton } from "../../../components/Button"; import HighlightComic from "../../../components/HighlightComic"; import TextInput from "../../../components/TextInput"; import { prisma } from "../../../src/db"; import { searchClient } from "../../../src/search"; interface Params extends ParsedUrlQuery { comic: string; } interface Props { initialSearchQuery: string; comic: Comic; } type ComicPageResult = { id: string; } & Omit & { comic: Comic; bubbles: ComicBubble[]; } export default function Search(props: Props) { const router = useRouter(); const [searchQuery, setSearchQuery] = useState(props.initialSearchQuery); const [results, setResults] = useState>(); const [selected, setSelected] = useState(-1); useEffect(() => { setSearchQuery((Array.isArray(router.query.search) ? router.query.search[0] : router.query.search) || ''); }, [router.query]); useEffect(() => { searchClient.index('comic_pages').search(searchQuery, { attributesToHighlight: ['*'], filter: [ `comic.id=${props.comic.id}`, ], }).then(results => { setResults(results); }); }, [searchQuery]); return
Search {props.comic.title}
{ router.replace({ pathname: `/comic/${props.comic.slug}/search`, query: { search: e.target.value }, }, undefined, { shallow: true, }); setSearchQuery(e.target.value); setSelected(-1); }} placeholder='Type to search...' className='w-full max-w-xl' />
{results &&

~{results.estimatedTotalHits} total results

    {results.hits.map((result, i) => { return
  • { e.preventDefault(); setSelected(i === selected ? -1 : i); }}> {result.title}

  • })}
{selected !== -1 && results.hits[selected] &&

{results.hits[selected].title}

}
}
} export const getServerSideProps: GetServerSideProps = async ({ params, query }) => { const { comic: comicId } = params!; const comic = await prisma.comic.findFirst({ where: { slug: comicId, }, }); if (!comic) return { notFound: true }; const search = (Array.isArray(query.search) ? query.search[0] : query.search) || ''; return { props: { initialSearchQuery: search, comic, }, } } function findHighlighedBubbles(result: Hit) { return result.bubbles.filter((bubble, i) => { if (!result._formatted?.bubbles) throw new Error(); const fmt = result._formatted?.bubbles[i].content; return fmt !== bubble.content; }).map(bubble => bubble.idx); }