Refactor Search component to use Dialog for improved user experience; integrate Pagination component for better navigation of search results
This commit is contained in:
@@ -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,
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -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}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
112
src/search.tsx
112
src/search.tsx
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user