"use client" import * as React from "react" import { usePathname } from "next/navigation" import { IconArrowUpRight, IconChevronLeft, IconChevronRight, } from "@tabler/icons-react" import { cn } from "cn" import { useSearchRegistry } from "@/hooks/use-search-registry" import { DirectoryAddButton, DirectoryAddProvider, } from "@/components/directory-add-button" import { Button, buttonVariants } from "@/styles/base-nova/ui/button" import { Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemMedia, ItemSeparator, ItemTitle, } from "@/styles/base-nova/ui/item" import { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, } from "@/styles/base-nova/ui/pagination" import { Skeleton } from "@/styles/base-nova/ui/skeleton" import { SearchDirectory } from "./directory-search" function getHomepageUrl(homepage: string) { const url = new URL(homepage) url.searchParams.set("utm_source", "ui.shadcn.com") url.searchParams.set("utm_medium", "referral") url.searchParams.set("utm_campaign", "directory") return url.toString() } function getPageHref(pathname: string, query: string, page: number) { const searchParams = new URLSearchParams() if (query) { searchParams.set("q", query) } if (page > 1) { searchParams.set("page", page.toString()) } const search = searchParams.toString() return search ? `${pathname}?${search}` : pathname } function getPageNumbers(current: number, total: number) { if (total <= 7) { return Array.from({ length: total }, (_, i) => i + 1) as ( | number | "ellipsis" )[] } const pages: (number | "ellipsis")[] = [1] // Show ellipsis or page 2 directly if only one number would be hidden. if (current > 4) { pages.push("ellipsis") } else if (current >= 4) { pages.push(2) } const start = Math.max(2, current - 1) const end = Math.min(total - 1, current + 1) for (let i = start; i <= end; i++) { pages.push(i) } // Show ellipsis or second-to-last page directly if only one number would be hidden. if (current < total - 3) { pages.push("ellipsis") } else if (current <= total - 3) { pages.push(total - 1) } pages.push(total) return pages } type DirectoryPaginationLinkProps = React.ComponentProps<"a"> & { isActive?: boolean size?: React.ComponentProps["size"] } function DirectoryPaginationLink({ className, isActive, size = "icon", ...props }: DirectoryPaginationLinkProps) { return ( ) } function DirectoryPaginationPrevious({ className, text = "Previous", ...props }: DirectoryPaginationLinkProps & { text?: string }) { return ( {text} ) } function DirectoryPaginationNext({ className, text = "Next", ...props }: DirectoryPaginationLinkProps & { text?: string }) { return ( {text} ) } export function DirectoryList() { return (
}>
) } function DirectoryListContent() { const pathname = usePathname() const { isLoading, paginatedRegistries, page, query, registries, totalPages, setPage, setQuery, } = useSearchRegistry() const previousHref = page > 1 ? getPageHref(pathname, query, page - 1) : undefined const nextHref = page < totalPages ? getPageHref(pathname, query, page + 1) : undefined const handlePageChange = React.useCallback( ( event: React.MouseEvent, targetPage: number, disabled = false ) => { if ( event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey ) { return } if (disabled || targetPage === page) { event.preventDefault() return } event.preventDefault() void setPage(targetPage) }, [page, setPage] ) if (isLoading) { return } return ( <> {paginatedRegistries.map((registry, index) => (
{registry.name}{" "} {registry.description && ( {registry.description} )} {index < paginatedRegistries.length - 1 && ( )} ))} {totalPages > 1 && ( handlePageChange(event, page - 1, page <= 1) } className={cn( page <= 1 ? "pointer-events-none opacity-50" : "cursor-pointer" )} /> {getPageNumbers(page, totalPages).map((p, i) => p === "ellipsis" ? ( ) : ( handlePageChange(event, p)} className="cursor-pointer" > {p} ) )} = totalPages || undefined} tabIndex={page >= totalPages ? -1 : undefined} onClick={(event) => handlePageChange(event, page + 1, page >= totalPages) } className={cn( page >= totalPages ? "pointer-events-none opacity-50" : "cursor-pointer" )} /> )} ) } function DirectoryListSkeleton() { return ( <> {Array.from({ length: 10 }, (_, index) => ( {index < 9 && } ))} ) }