@@ -21,6 +21,15 @@ import { Subreddit } from "../types/subreddit";
2121import SubredditCard from "./SubredditCard" ;
2222import { RedditApiClient } from "../api/RedditApiClient" ;
2323import 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
2534export 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 ( "&" , "&" )
235250 : post . sr_detail ?. icon_img ?. length ! > 1
236- ? post . sr_detail ?. icon_img . replace ( "&" , "&" )
237- : post . sr_detail ?. header_img ?. length ! > 1
238- ? post . sr_detail ?. header_img . replace ( "&" , "&" )
239- : "/fallback_reddit_icon.png"
251+ ? post . sr_detail ?. icon_img . replace ( "&" , "&" )
252+ : post . sr_detail ?. header_img ?. length ! > 1
253+ ? post . sr_detail ?. header_img . replace ( "&" , "&" )
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