Refactor Search component to use Dialog for improved user experience; integrate Pagination component for better navigation of search results

This commit is contained in:
ecwu
2024-12-21 22:27:07 +08:00
parent de4aca9498
commit c6fbe5c031
3 changed files with 82 additions and 78 deletions

View File

@@ -1,8 +1,8 @@
import * as React from "react" import * as React from "react";
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react" import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react";
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils";
import { ButtonProps, buttonVariants } from "@/components/ui/button" import { ButtonProps, buttonVariants } from "@/components/ui/button";
const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => ( const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
<nav <nav
@@ -11,8 +11,8 @@ const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
className={cn("mx-auto flex w-full justify-center", className)} className={cn("mx-auto flex w-full justify-center", className)}
{...props} {...props}
/> />
) );
Pagination.displayName = "Pagination" Pagination.displayName = "Pagination";
const PaginationContent = React.forwardRef< const PaginationContent = React.forwardRef<
HTMLUListElement, HTMLUListElement,
@@ -23,21 +23,21 @@ const PaginationContent = React.forwardRef<
className={cn("flex flex-row items-center gap-1", className)} className={cn("flex flex-row items-center gap-1", className)}
{...props} {...props}
/> />
)) ));
PaginationContent.displayName = "PaginationContent" PaginationContent.displayName = "PaginationContent";
const PaginationItem = React.forwardRef< const PaginationItem = React.forwardRef<
HTMLLIElement, HTMLLIElement,
React.ComponentProps<"li"> React.ComponentProps<"li">
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<li ref={ref} className={cn("", className)} {...props} /> <li ref={ref} className={cn("", className)} {...props} />
)) ));
PaginationItem.displayName = "PaginationItem" PaginationItem.displayName = "PaginationItem";
type PaginationLinkProps = { type PaginationLinkProps = {
isActive?: boolean isActive?: boolean;
} & Pick<ButtonProps, "size"> & } & Pick<ButtonProps, "size"> &
React.ComponentProps<"a"> React.ComponentProps<"a">;
const PaginationLink = ({ const PaginationLink = ({
className, className,
@@ -56,8 +56,8 @@ const PaginationLink = ({
)} )}
{...props} {...props}
/> />
) );
PaginationLink.displayName = "PaginationLink" PaginationLink.displayName = "PaginationLink";
const PaginationPrevious = ({ const PaginationPrevious = ({
className, className,
@@ -70,10 +70,10 @@ const PaginationPrevious = ({
{...props} {...props}
> >
<ChevronLeft className="h-4 w-4" /> <ChevronLeft className="h-4 w-4" />
<span>Previous</span> {/* <span>Previous</span> */}
</PaginationLink> </PaginationLink>
) );
PaginationPrevious.displayName = "PaginationPrevious" PaginationPrevious.displayName = "PaginationPrevious";
const PaginationNext = ({ const PaginationNext = ({
className, className,
@@ -85,11 +85,11 @@ const PaginationNext = ({
className={cn("gap-1 pr-2.5", className)} className={cn("gap-1 pr-2.5", className)}
{...props} {...props}
> >
<span>Next</span> {/* <span>Next</span> */}
<ChevronRight className="h-4 w-4" /> <ChevronRight className="h-4 w-4" />
</PaginationLink> </PaginationLink>
) );
PaginationNext.displayName = "PaginationNext" PaginationNext.displayName = "PaginationNext";
const PaginationEllipsis = ({ const PaginationEllipsis = ({
className, className,
@@ -103,8 +103,8 @@ const PaginationEllipsis = ({
<MoreHorizontal className="h-4 w-4" /> <MoreHorizontal className="h-4 w-4" />
<span className="sr-only">More pages</span> <span className="sr-only">More pages</span>
</span> </span>
) );
PaginationEllipsis.displayName = "PaginationEllipsis" PaginationEllipsis.displayName = "PaginationEllipsis";
export { export {
Pagination, Pagination,
@@ -114,4 +114,4 @@ export {
PaginationPrevious, PaginationPrevious,
PaginationNext, PaginationNext,
PaginationEllipsis, PaginationEllipsis,
} };

View File

@@ -42,6 +42,7 @@ import WhisperButton from "@/components/WhisperButton";
import AddToolMsg from "./AddToolMsg"; import AddToolMsg from "./AddToolMsg";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { ChatInput } from "@/components/ui/chat/chat-input"; import { ChatInput } from "@/components/ui/chat/chat-input";
import { import {
ChatBubble, ChatBubble,
@@ -508,6 +509,7 @@ export default function ChatBOX(props: {
setSelectedChatIndex={props.setSelectedChatIndex} setSelectedChatIndex={props.setSelectedChatIndex}
db={props.db} db={props.db}
chatStore={chatStore} chatStore={chatStore}
show={showSearch}
setShow={setShowSearch} setShow={setShowSearch}
/> />
)} )}

View File

@@ -4,6 +4,27 @@ import { StateUpdater, useRef, useState, Dispatch } from "preact/hooks";
import { ChatStore } from "@/types/chatstore"; import { ChatStore } from "@/types/chatstore";
import { MessageDetail } from "./chatgpt"; import { MessageDetail } from "./chatgpt";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination";
import { Input } from "./components/ui/input";
interface ChatStoreSearchResult { interface ChatStoreSearchResult {
key: IDBValidKey; key: IDBValidKey;
cs: ChatStore; cs: ChatStore;
@@ -15,6 +36,7 @@ export default function Search(props: {
db: Promise<IDBPDatabase<ChatStore>>; db: Promise<IDBPDatabase<ChatStore>>;
setSelectedChatIndex: Dispatch<StateUpdater<number>>; setSelectedChatIndex: Dispatch<StateUpdater<number>>;
chatStore: ChatStore; chatStore: ChatStore;
show: boolean;
setShow: (show: boolean) => void; setShow: (show: boolean) => void;
}) { }) {
const [searchResult, setSearchResult] = useState<ChatStoreSearchResult[]>([]); const [searchResult, setSearchResult] = useState<ChatStoreSearchResult[]>([]);
@@ -24,29 +46,15 @@ export default function Search(props: {
const searchAbortRef = useRef<AbortController | null>(null); const searchAbortRef = useRef<AbortController | null>(null);
return ( return (
<div <Dialog open={props.show} onOpenChange={props.setShow}>
onClick={() => props.setShow(false)} <DialogContent className="sm:max-w-[425px]">
className="left-0 top-0 overflow-scroll flex justify-center absolute w-screen h-full bg-black bg-opacity-50 z-10" <DialogHeader>
> <DialogTitle>Search</DialogTitle>
<div <DialogDescription>Search messages by content.</DialogDescription>
onClick={(event: any) => { </DialogHeader>
event.stopPropagation();
}}
className="m-2 p-2 bg-base-300 rounded-lg h-fit w-2/3 z-20"
>
<div className="flex justify-between">
<span className="m-1 p-1 font-bold">Search</span>
<button
className="m-1 p-1 btn btn-sm btn-secondary"
onClick={() => props.setShow(false)}
>
Close
</button>
</div>
<div> <div>
<input <Input
autoFocus autoFocus
className="input input-bordered w-full border"
type="text" type="text"
placeholder="Type Something..." placeholder="Type Something..."
onInput={async (event: any) => { onInput={async (event: any) => {
@@ -160,40 +168,34 @@ export default function Search(props: {
})} })}
</div> </div>
{searchResult.length > 0 && ( {searchResult.length > 0 && (
<div className="flex justify-center my-2"> <Pagination>
<div className="join"> <PaginationContent>
<button <PaginationItem>
className="join-item btn btn-sm" <PaginationPrevious
disabled={pageIndex === 0} onClick={() => {
onClick={() => { if (pageIndex === 0) return;
if (pageIndex === 0) { setPageIndex(pageIndex - 1);
return; }}
} disabled={pageIndex === 0}
setPageIndex(pageIndex - 1); />
}} </PaginationItem>
> <PaginationItem>
« {pageIndex + 1} of {Math.floor(searchResult.length / 10) + 1}
</button> </PaginationItem>
<button className="join-item btn btn-sm"> <PaginationItem>
Page {pageIndex + 1} /{" "} <PaginationNext
{Math.floor(searchResult.length / 10) + 1} onClick={() => {
</button> if (pageIndex === Math.floor(searchResult.length / 10))
<button return;
className="join-item btn btn-sm" setPageIndex(pageIndex + 1);
disabled={pageIndex === Math.floor(searchResult.length / 10)} }}
onClick={() => { disabled={pageIndex === Math.floor(searchResult.length / 10)}
if (pageIndex === Math.floor(searchResult.length / 10)) { />
return; </PaginationItem>
} </PaginationContent>
setPageIndex(pageIndex + 1); </Pagination>
}}
>
»
</button>
</div>
</div>
)} )}
</div> </DialogContent>
</div> </Dialog>
); );
} }