Skip to content

Commit 1835c50

Browse files
committed
revamp search page layout
1 parent 1b06db2 commit 1835c50

File tree

1 file changed

+68
-50
lines changed

1 file changed

+68
-50
lines changed

src/components/SearchPage.tsx

Lines changed: 68 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ import { Subreddit } from "../types/subreddit";
2121
import SubredditCard from "./SubredditCard";
2222
import { RedditApiClient } from "../api/RedditApiClient";
2323
import CreatedEditedLabel from "./CreatedEditedLabel";
24+
import SegmentedControl from "./SegmentedControl";
25+
26+
const columnClasses: { [key: number]: string } = {
27+
1: "lg:columns-1",
28+
2: "lg:columns-2",
29+
3: "lg:columns-3",
30+
4: "lg:columns-4",
31+
5: "lg:columns-5",
32+
};
2433

2534
export interface SearchPageProps {
2635
query: string;
@@ -39,6 +48,7 @@ const SearchPage: React.FC<SearchPageProps> = memo(({ query, sort: initialSort,
3948
const [hasMore, setHasMore] = useState(true);
4049
const [sort, setSort] = useState<string>(initialSort);
4150
const [time, setTime] = useState<string>(initialTime);
51+
const [numColumns, setNumColumns] = useState(3);
4252
const observer = useRef<IntersectionObserver | null>(null);
4353
const sentinel = useRef<HTMLDivElement | null>(null);
4454

@@ -79,11 +89,11 @@ const SearchPage: React.FC<SearchPageProps> = memo(({ query, sort: initialSort,
7989
} else {
8090
setSearchSubreddits([]);
8191
}
82-
}, [userQuery]);
92+
}, [userQuery, sort]);
8393

8494
useEffect(() => {
8595
fetchSubredditSuggestions();
86-
}, [userQuery]);
96+
}, [userQuery, fetchSubredditSuggestions]);
8797

8898
useEffect(() => {
8999
setUserQuery(query);
@@ -99,7 +109,7 @@ const SearchPage: React.FC<SearchPageProps> = memo(({ query, sort: initialSort,
99109
? `https://www.reddit.com/r/${subreddit}/search.json?q=${userQuery}&sort=${sort}&t=${time}&restrict_sr=on&sr_detail=true`
100110
: `https://www.reddit.com/search.json?q=${userQuery}&sr_detail=true&sort=${sort}&t=${time}`;
101111

102-
RedditApiClient.fetch(searchUrl)
112+
RedditApiClient.fetch(searchUrl)
103113
.then((response) => response.json())
104114
.then((data) => {
105115
const fetchedPosts = data.data.children.map((child: { data: Post }) => child.data);
@@ -137,7 +147,7 @@ const SearchPage: React.FC<SearchPageProps> = memo(({ query, sort: initialSort,
137147

138148
return (
139149
<div className="dark:bg-custom-black dark:text-white min-h-screen">
140-
<div className="mx-auto md:w-8/12 xl:w-1/2 max-w-[95vw] flex flex-col justify-center relative py-4">
150+
<div className="max-w-[95vw] mx-auto relative py-4">
141151
<nav aria-label="Breadcrumb" className="flex items-center justify-between mb-5">
142152
<ol className="flex items-center gap-1 text-sm text-gray-600">
143153
<li>
@@ -152,10 +162,7 @@ const SearchPage: React.FC<SearchPageProps> = memo(({ query, sort: initialSort,
152162
<h1 className="text-gray-500 font-bold text-lg mr-1 whitespace-nowrap">Search Results</h1>
153163
</ol>
154164
<div className="search-input">
155-
<SearchInput
156-
initialSearchInSubreddit={!!subreddit}
157-
currentSubreddit={subreddit}
158-
/>
165+
<SearchInput initialSearchInSubreddit={!!subreddit} currentSubreddit={subreddit} />
159166
</div>
160167
</nav>
161168

@@ -167,60 +174,68 @@ const SearchPage: React.FC<SearchPageProps> = memo(({ query, sort: initialSort,
167174
<div className="mb-4 flex flex-wrap gap-3">
168175
{filterOptions.map((optionGroup, index) =>
169176
optionGroup.label === "Time" && !["relevance", "top", "comments"].includes(sort) ? null : (
170-
<div
171-
className="flex items-center"
172-
key={index}
173-
>
174-
<label className="mr-2 font-medium text-sm text-gray-700 dark:text-gray-300">
177+
<div className="flex items-center overflow-x-auto hide-scrollbar" key={index}>
178+
<label className="mr-2 font-medium text-xs text-gray-700 dark:text-gray-300">
175179
{optionGroup.label}
176180
</label>
177-
<select
178-
value={optionGroup.label === "Sort by" ? sort : time}
179-
onChange={(e) => {
181+
<SegmentedControl
182+
options={optionGroup.options}
183+
currentValue={optionGroup.label === "Sort by" ? sort : time}
184+
onChange={(value) => {
180185
switch (optionGroup.label) {
181186
case "Sort by":
182-
setSort(e.target.value);
187+
setSort(value);
183188
break;
184189
case "Time":
185-
setTime(e.target.value);
190+
setTime(value);
186191
break;
187192
}
188193
}}
189-
className="text-sm border border-gray-200 dark:border-gray-600 rounded-md px-1 py-1 font-medium text-gray-800 dark:text-gray-200 dark:bg-gray-800 focus:ring-2 focus:ring-blue-500 focus:border-transparent"
190-
>
191-
{optionGroup.options.map((option) => (
192-
<option key={option.value} value={option.value}>
193-
{option.key}
194-
</option>
195-
))}
196-
</select>
194+
label={optionGroup.label}
195+
/>
197196
</div>
198197
)
199198
)}
200199
</div>
201200

202201
{searchSubreddits.length > 0 && !subreddit && (
203-
<div className="my-2 w-full">
202+
<div className="my-2 w-full">
204203
<div className="font-semibold mb-2">Subreddits</div>
205204
{searchSubreddits.slice(0, 4).map((subreddit, index) => (
206205
<SubredditCard key={index} subreddit={subreddit} />
207206
))}
208207
</div>
209208
)}
210209

211-
<div className="font-semibold mt-5 mb-2">
212-
Posts
210+
<div className="hidden md:flex items-center gap-2.5 shrink-0 mb-4 w-full justify-start">
211+
<label htmlFor="columns" className="text-[11px] font-medium text-zinc-600 uppercase tracking-wide">
212+
Cols
213+
</label>
214+
<input
215+
id="columns"
216+
type="range"
217+
min="1"
218+
max="5"
219+
value={numColumns}
220+
onChange={(e) => setNumColumns(Number(e.target.value))}
221+
className="w-20 h-0.75 bg-zinc-800 rounded-full appearance-none cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:h-3 [&::-webkit-slider-thumb]:bg-blue-400 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:cursor-pointer [&::-webkit-slider-thumb]:shadow-[0_0_6px_rgba(96,165,250,0.5)]"
222+
/>
223+
<span className="text-xs font-mono text-zinc-400 w-4 text-center tabular-nums">{numColumns}</span>
213224
</div>
214225

215-
{posts.map((post) => (
216-
<a href={parsePermalink(post.permalink)} key={post.id}>
226+
<div className="font-semibold mt-5 mb-2">Posts</div>
227+
228+
<div className={`columns-1 ${columnClasses[numColumns]} gap-4`}>
229+
{posts.map((post) => (
217230
<div
218231
key={post.id}
219-
className="bg-slate-200 dark:bg-neutral-800 shadow-md rounded-xl p-2 mb-4 w-full mx-auto prose prose-sm text-gray-700 dark:text-gray-300 prose-headings:font-semibold prose-headings:text-xl overflow-auto"
232+
className="bg-slate-200 dark:bg-neutral-800 shadow-md rounded-xl p-2 mb-4 w-full mx-auto prose prose-sm text-gray-700 dark:text-gray-300 prose-headings:font-semibold prose-headings:text-xl break-inside-avoid"
220233
>
221234
<div>
222235
<div className="flex items-center space-x-2">
223-
<h3 className="font-semibold text-blue-400">{post.author}</h3>
236+
<a href={`/user/${post.author}`}>
237+
<h3 className="font-semibold text-blue-400">{post.author}</h3>
238+
</a>
224239
<AuthorFlairText
225240
author_flair_richtext={post.author_flair_richtext}
226241
author_flair_text={post.author_flair_text}
@@ -233,10 +248,10 @@ const SearchPage: React.FC<SearchPageProps> = memo(({ query, sort: initialSort,
233248
post.sr_detail?.community_icon?.length! > 1
234249
? post.sr_detail?.community_icon.replace("&amp;", "&")
235250
: post.sr_detail?.icon_img?.length! > 1
236-
? post.sr_detail?.icon_img.replace("&amp;", "&")
237-
: post.sr_detail?.header_img?.length! > 1
238-
? post.sr_detail?.header_img.replace("&amp;", "&")
239-
: "/fallback_reddit_icon.png"
251+
? post.sr_detail?.icon_img.replace("&amp;", "&")
252+
: post.sr_detail?.header_img?.length! > 1
253+
? post.sr_detail?.header_img.replace("&amp;", "&")
254+
: "/fallback_reddit_icon.png"
240255
}
241256
className="w-6 h-6 rounded-full"
242257
/>
@@ -247,19 +262,22 @@ const SearchPage: React.FC<SearchPageProps> = memo(({ query, sort: initialSort,
247262
{post.subreddit_name_prefixed}
248263
</a>
249264
</div>
250-
<CreatedEditedLabel
251-
created={post.created}
252-
edited={post.edited}
253-
/>
254-
<h2 className="text-lg font-semibold my-1 dark:text-white">{he.decode(post.title)}</h2>
255-
<LinkFlairText
256-
link_flair_richtext={post.link_flair_richtext}
257-
link_flair_text={post.link_flair_text}
258-
link_flair_background_color={post.link_flair_background_color}
259-
/>
265+
<CreatedEditedLabel created={post.created} edited={post.edited} />
266+
<a href={parsePermalink(post.permalink)} className="block mt-2 group">
267+
<h2 className="text-lg font-semibold my-1 dark:text-white group-hover:underline">
268+
{he.decode(post.title)}
269+
</h2>
270+
<LinkFlairText
271+
link_flair_richtext={post.link_flair_richtext}
272+
link_flair_text={post.link_flair_text}
273+
link_flair_background_color={post.link_flair_background_color}
274+
/>
275+
</a>
260276
</div>
261277
<div
262-
className={`${post.thumbnail === "spoiler" || post.thumbnail === "nsfw" || post.over_18 ? "blur" : ""}`}
278+
className={`${
279+
post.thumbnail === "spoiler" || post.thumbnail === "nsfw" || post.over_18 ? "blur-sm" : ""
280+
}`}
263281
>
264282
{post.secure_media_embed?.media_domain_url ? (
265283
<SecureMediaEmbed url_overridden_by_dest={post.url_overridden_by_dest} {...post.secure_media_embed} />
@@ -289,8 +307,8 @@ const SearchPage: React.FC<SearchPageProps> = memo(({ query, sort: initialSort,
289307
<PostStats score={post.score} num_comments={post.num_comments} />
290308
</div>
291309
</div>
292-
</a>
293-
))}
310+
))}
311+
</div>
294312
<div ref={sentinel} className="h-1"></div>
295313
</div>
296314
</div>

0 commit comments

Comments
 (0)