Skip to content

Commit 526ca74

Browse files
authored
chore: improve search result UI (#1039)
1 parent 1022781 commit 526ca74

File tree

1 file changed

+153
-44
lines changed

1 file changed

+153
-44
lines changed

app/search/page.tsx

Lines changed: 153 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1-
import { Card, CardBody, CardHeader } from "@heroui/react";
1+
import {
2+
faBox,
3+
faCube,
4+
faSearch,
5+
faTag,
6+
} from "@fortawesome/free-solid-svg-icons";
7+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
8+
import { Card, CardBody, CardHeader, Chip, Divider } from "@heroui/react";
29
import type { Metadata, ResolvingMetadata } from "next";
310
import NextLink from "next/link";
11+
import { format } from "timeago.js";
412
import { PER_PAGE } from "../_lib/constants";
513
import { getHasuraClient } from "../_lib/hasuraClient";
614
import { Pagination } from "./_components/pagination";
@@ -41,59 +49,160 @@ export default async function Page(props: { searchParams: SearchParams }) {
4149
limit: perPage,
4250
offset: (page - 1) * perPage,
4351
});
44-
if (!data || data.packages.length === 0) {
45-
return (
46-
<div className="flex flex-col items-center justify-center h-screen">
47-
no packages found
48-
</div>
49-
);
50-
}
5152

52-
const totalCount = data.packages_aggregate?.aggregate?.count ?? 0;
53+
const totalCount = data?.packages_aggregate?.aggregate?.count ?? 0;
5354
const currentLast = page * perPage;
5455
const currentPos = {
5556
first: currentLast - (perPage - 1),
5657
last: currentLast > totalCount ? totalCount : currentLast,
5758
};
5859
const numPages = Math.ceil(totalCount / perPage);
5960

60-
const header = (
61-
<span>
62-
Displaying&nbsp;
63-
<span className="font-bold">
64-
{currentPos.first}-{currentPos.last}
65-
</span>
66-
&nbsp;of&nbsp;<span className="font-bold">{totalCount}</span>
67-
&nbsp;total results
68-
</span>
69-
);
61+
// Empty state
62+
if (!data || data.packages.length === 0) {
63+
return (
64+
<div className="container mx-auto max-w-4xl px-6 py-12">
65+
{/* Header */}
66+
<div className="text-center mb-8">
67+
<div className="flex items-center justify-center gap-3 mb-4">
68+
<div className="flex items-center justify-center w-12 h-12 bg-gradient-to-br from-primary-500 to-secondary-500 rounded-lg">
69+
<FontAwesomeIcon
70+
icon={faSearch}
71+
className="text-white text-lg"
72+
/>
73+
</div>
74+
<h1 className="text-3xl md:text-4xl font-bold">
75+
{query
76+
? `Search results for "${query}"`
77+
: "All packages"}
78+
</h1>
79+
</div>
80+
</div>
81+
82+
{/* Empty state */}
83+
<div className="text-center py-16">
84+
<FontAwesomeIcon
85+
icon={faBox}
86+
className="text-default-300 text-6xl mb-6"
87+
/>
88+
<h2 className="text-2xl font-semibold mb-3">
89+
No packages found
90+
</h2>
91+
<p className="text-default-500 text-lg">
92+
{query
93+
? `We couldn't find any packages matching "${query}". Try a different search term.`
94+
: "No packages are available at the moment."}
95+
</p>
96+
</div>
97+
</div>
98+
);
99+
}
70100

71101
return (
72-
<div className="flex flex-col items-center justify-center m-4 gap-4">
73-
{header}
74-
{data.packages.map((pkg) => (
75-
<Card
76-
key={pkg.id}
77-
id={pkg.id}
78-
className="w-full max-w-[500px] p-4"
79-
as={NextLink}
80-
href={`/packages/${pkg.name}/${pkg.version}`}
81-
>
82-
<CardHeader className="justify-between">
83-
<p className="font-bold">{pkg.name}</p>
84-
<p className="text-gray-500">{pkg.version}</p>
85-
</CardHeader>
86-
<CardBody>
87-
<p className="text-gray-500">{pkg.description}</p>
88-
</CardBody>
89-
</Card>
90-
))}
91-
<Pagination
92-
query={query}
93-
page={page}
94-
numPages={numPages}
95-
perPage={perPage}
96-
/>
102+
<div className="container mx-auto max-w-4xl px-6 py-8">
103+
{/* Header */}
104+
<div className="mb-8">
105+
<div className="flex items-center gap-3 mb-4">
106+
<div className="flex items-center justify-center w-12 h-12 bg-gradient-to-br from-primary-500 to-secondary-500 rounded-lg">
107+
<FontAwesomeIcon
108+
icon={faSearch}
109+
className="text-white text-lg"
110+
/>
111+
</div>
112+
<div>
113+
<h1 className="text-3xl md:text-4xl font-bold">
114+
{query
115+
? `Search results for "${query}"`
116+
: "All packages"}
117+
</h1>
118+
<p className="text-default-600 mt-1">
119+
Displaying{" "}
120+
<span className="font-semibold text-primary">
121+
{currentPos.first}-{currentPos.last}
122+
</span>{" "}
123+
of{" "}
124+
<span className="font-semibold text-primary">
125+
{totalCount}
126+
</span>{" "}
127+
packages
128+
</p>
129+
</div>
130+
</div>
131+
</div>
132+
133+
{/* Results */}
134+
<div className="space-y-4 mb-8">
135+
{data.packages.map((pkg) => (
136+
<Card
137+
key={pkg.id}
138+
className="w-full hover:shadow-lg transition-shadow duration-200 hover:scale-[1.01]"
139+
isPressable
140+
as={NextLink}
141+
href={`/packages/${pkg.name}/${pkg.version}`}
142+
>
143+
<CardHeader className="pb-3">
144+
<div className="flex items-start justify-between w-full">
145+
<div className="flex items-center gap-3 flex-1">
146+
<div className="flex items-center justify-center w-10 h-10 bg-gradient-to-br from-primary-100 to-secondary-100 rounded-lg">
147+
<FontAwesomeIcon
148+
icon={faCube}
149+
className="text-primary text-sm"
150+
/>
151+
</div>
152+
<div className="flex-1 min-w-0">
153+
<h3 className="text-lg font-semibold text-foreground truncate">
154+
{pkg.name}
155+
</h3>
156+
<div className="flex items-center gap-2 mt-1">
157+
<FontAwesomeIcon
158+
icon={faTag}
159+
className="text-default-400 text-xs"
160+
/>
161+
<span className="text-sm text-default-500">
162+
v{pkg.version}
163+
</span>
164+
</div>
165+
</div>
166+
</div>
167+
<div className="flex flex-col items-end gap-2 shrink-0 ml-4">
168+
<Chip
169+
size="sm"
170+
variant="flat"
171+
color="primary"
172+
>
173+
C++{pkg.edition.toString().slice(-2)}
174+
</Chip>
175+
<span className="text-xs text-default-400">
176+
{format(pkg.published_at)}
177+
</span>
178+
</div>
179+
</div>
180+
</CardHeader>
181+
{pkg.description && (
182+
<>
183+
<Divider />
184+
<CardBody className="pt-3">
185+
<p className="text-default-600 line-clamp-2">
186+
{pkg.description}
187+
</p>
188+
</CardBody>
189+
</>
190+
)}
191+
</Card>
192+
))}
193+
</div>
194+
195+
{/* Pagination */}
196+
{numPages > 1 && (
197+
<div className="flex justify-center">
198+
<Pagination
199+
query={query}
200+
page={page}
201+
numPages={numPages}
202+
perPage={perPage}
203+
/>
204+
</div>
205+
)}
97206
</div>
98207
);
99208
}

0 commit comments

Comments
 (0)