Skip to content

Commit 3e35b3c

Browse files
committed
update mansory layout
1 parent 7f21f53 commit 3e35b3c

File tree

4 files changed

+399
-350
lines changed

4 files changed

+399
-350
lines changed

src/components/Feed.tsx

Lines changed: 117 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,10 @@ import { useNavigate, useParams } from "react-router-dom";
2828
import SegmentedControl from "./SegmentedControl";
2929
import BackToTopButton from "./BackToTopButton";
3030
import TopPosterStatusBar from "./TopPosterStatusBar";
31+
import { useMobileDetection } from "../utils/useMobileDetection";
3132

3233
const NUM_TOP_POSTERS = 6;
3334

34-
const columnClasses: { [key: number]: string } = {
35-
1: "lg:columns-1",
36-
2: "lg:columns-2",
37-
3: "lg:columns-3",
38-
4: "lg:columns-4",
39-
5: "lg:columns-5",
40-
};
41-
4235
export interface FeedProps {
4336
subreddit: string;
4437
initialTime: string;
@@ -65,13 +58,24 @@ const Feed: React.FC<FeedProps> = memo(({ subreddit, initialTime, initialSort })
6558
);
6659
const [topPosters, setTopPosters] = useState<[string, number][]>([]);
6760

61+
const isMobile = useMobileDetection();
62+
6863
const filteredPosts = useMemo(() => {
6964
if (postTypeFilter === "all") {
7065
return posts;
7166
}
7267
return posts.filter((post) => getPostType(post) === postTypeFilter);
7368
}, [posts, postTypeFilter]);
7469

70+
const columns = useMemo(() => {
71+
const columnsToUse = isMobile ? 1 : numColumns;
72+
const newColumns: Post[][] = Array.from({ length: columnsToUse }, () => []);
73+
filteredPosts.forEach((post, i) => {
74+
newColumns[i % columnsToUse].push(post);
75+
});
76+
return newColumns;
77+
}, [filteredPosts, numColumns, isMobile]);
78+
7579
useEffect(() => {
7680
const authorCounts: { [key: string]: number } = {};
7781
filteredPosts.forEach((post) => {
@@ -241,106 +245,114 @@ const Feed: React.FC<FeedProps> = memo(({ subreddit, initialTime, initialSort })
241245
/>
242246
</div>
243247
</div>
244-
<div className="hidden md:flex items-center gap-2.5 shrink-0 mb-4 w-full justify-start">
245-
<label htmlFor="columns" className="text-[11px] font-medium text-zinc-600 uppercase tracking-wide">
246-
Cols
247-
</label>
248-
<input
249-
id="columns"
250-
type="range"
251-
min="1"
252-
max="5"
253-
value={numColumns}
254-
onChange={(e) => setNumColumns(Number(e.target.value))}
255-
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)]"
256-
/>
257-
<span className="text-xs font-mono text-zinc-400 w-4 text-center tabular-nums">{numColumns}</span>
258-
</div>
259-
<div className={`columns-1 ${columnClasses[numColumns]} gap-4`}>
260-
{filteredPosts.map((post) => (
261-
<div
262-
key={post.id}
263-
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"
264-
>
265-
<div>
266-
<div className="flex items-center space-x-2 mb-2">
267-
<img
268-
src={
269-
post.sr_detail?.community_icon?.length! > 1
270-
? post.sr_detail?.community_icon.replace(/&amp;/g, "&")
271-
: post.sr_detail?.icon_img?.length! > 1
272-
? post.sr_detail?.icon_img.replace(/&amp;/g, "&")
273-
: post.sr_detail?.header_img?.length! > 1
274-
? post.sr_detail?.header_img.replace(/&amp;/g, "&")
275-
: "/fallback_reddit_icon.png"
276-
}
277-
alt={post.author}
278-
className="w-6 h-6 rounded-full bg-gray-300 dark:bg-gray-600"
279-
/>
280-
<a href={`/user/${post.author}`}>
281-
<h3 className="text-blue-500 font-semibold whitespace-nowrap hover:underline">{post.author}</h3>
282-
</a>
283-
<AuthorFlairText
284-
author_flair_richtext={post.author_flair_richtext}
285-
author_flair_text={post.author_flair_text}
286-
author_flair_background_color={post.author_flair_background_color}
287-
/>
288-
</div>
289-
<CreatedEditedLabel created={post.created} edited={post.edited} />
290-
291-
<a href={parsePermalink(post.permalink)} className="block mt-2 group">
292-
<h2 className="text-lg font-bold dark:text-white group-hover:underline">{he.decode(post.title)}</h2>
293-
<LinkFlairText
294-
link_flair_richtext={post.link_flair_richtext}
295-
link_flair_text={post.link_flair_text}
296-
link_flair_background_color={post.link_flair_background_color}
297-
/>
298-
<div
299-
className={`mt-3 ${
300-
post.thumbnail === "spoiler" || post.thumbnail === "nsfw" || post.over_18 ? "blur-sm" : ""
301-
}`}
302-
>
303-
{post.secure_media_embed?.media_domain_url ? (
304-
<SecureMediaEmbed
305-
url_overridden_by_dest={post.url_overridden_by_dest}
306-
{...post.secure_media_embed}
248+
{!isMobile && (
249+
<div className="flex items-center gap-2.5 shrink-0 mb-4 w-full justify-start">
250+
<label htmlFor="columns" className="text-[11px] font-medium text-zinc-600 uppercase tracking-wide">
251+
Cols
252+
</label>
253+
<input
254+
id="columns"
255+
type="range"
256+
min="1"
257+
max="5"
258+
value={numColumns}
259+
onChange={(e) => setNumColumns(Number(e.target.value))}
260+
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)]"
261+
/>
262+
<span className="text-xs font-mono text-zinc-400 w-4 text-center tabular-nums">{numColumns}</span>
263+
</div>
264+
)}
265+
<div className="flex justify-center gap-4">
266+
{columns.map((columnPosts: Post[], columnIndex) => (
267+
<div key={columnIndex} className="flex flex-1 flex-col gap-4 min-w-0">
268+
{columnPosts.map((post) => (
269+
<div
270+
key={post.id}
271+
className="bg-slate-200 dark:bg-neutral-800 shadow-md rounded-xl p-2 w-full mx-auto prose prose-sm text-gray-700 dark:text-gray-300 prose-headings:font-semibold prose-headings:text-xl"
272+
>
273+
<div>
274+
<div className="flex items-center space-x-2 mb-2">
275+
<img
276+
src={
277+
post.sr_detail?.community_icon?.length! > 1
278+
? post.sr_detail?.community_icon.replace(/&amp;/g, "&")
279+
: post.sr_detail?.icon_img?.length! > 1
280+
? post.sr_detail?.icon_img.replace(/&amp;/g, "&")
281+
: post.sr_detail?.header_img?.length! > 1
282+
? post.sr_detail?.header_img.replace(/&amp;/g, "&")
283+
: "/fallback_reddit_icon.png"
284+
}
285+
alt={post.author}
286+
className="w-6 h-6 rounded-full bg-gray-300 dark:bg-gray-600"
287+
/>
288+
<a href={`/user/${post.author}`}>
289+
<h3 className="text-blue-500 font-semibold whitespace-nowrap hover:underline">{post.author}</h3>
290+
</a>
291+
<AuthorFlairText
292+
author_flair_richtext={post.author_flair_richtext}
293+
author_flair_text={post.author_flair_text}
294+
author_flair_background_color={post.author_flair_background_color}
307295
/>
308-
) : post.secure_media ? (
309-
<SecureMedia {...post.secure_media} />
310-
) : post.media_metadata ? (
311-
<div className="relative mt-2">
312-
{post.gallery_data ? (
313-
<PostGallery galleryData={post.gallery_data} mediaMetadata={post.media_metadata} />
314-
) : null}
296+
</div>
297+
<CreatedEditedLabel created={post.created} edited={post.edited} />
298+
299+
<a href={parsePermalink(post.permalink)} className="block mt-2 group">
300+
<h2 className="text-lg font-bold dark:text-white group-hover:underline">
301+
{he.decode(post.title)}
302+
</h2>
303+
<LinkFlairText
304+
link_flair_richtext={post.link_flair_richtext}
305+
link_flair_text={post.link_flair_text}
306+
link_flair_background_color={post.link_flair_background_color}
307+
/>
308+
<div
309+
className={`mt-3 ${
310+
post.thumbnail === "spoiler" || post.thumbnail === "nsfw" || post.over_18 ? "blur-sm" : ""
311+
}`}
312+
>
313+
{post.secure_media_embed?.media_domain_url ? (
314+
<SecureMediaEmbed
315+
url_overridden_by_dest={post.url_overridden_by_dest}
316+
{...post.secure_media_embed}
317+
/>
318+
) : post.secure_media ? (
319+
<SecureMedia {...post.secure_media} />
320+
) : post.media_metadata ? (
321+
<div className="relative mt-2">
322+
{post.gallery_data ? (
323+
<PostGallery galleryData={post.gallery_data} mediaMetadata={post.media_metadata} />
324+
) : null}
325+
</div>
326+
) : post.preview ? (
327+
<PostPreview preview={post.preview} />
328+
) : post.url_overridden_by_dest ? (
329+
isImage(post.url_overridden_by_dest) ? (
330+
<img
331+
src={post.url_overridden_by_dest}
332+
alt="url_overridden_by_dest"
333+
className="mt-4 max-w-full max-h-125 mx-auto border rounded-md p-2 object-contain"
334+
/>
335+
) : (
336+
<FetchImage url={post.url_overridden_by_dest} />
337+
)
338+
) : (
339+
<Thumbnail thumbnail={post.thumbnail || ""} />
340+
)}
341+
342+
{post.poll_data && <PollData poll_data={post.poll_data} />}
343+
344+
{post.selftext_html && <SelfTextHtml selftext_html={post.selftext_html} truncateLines={10} />}
345+
346+
{post.url_overridden_by_dest && post.post_hint === "link" && (
347+
<ExternalLink url_overridden_by_dest={post.url_overridden_by_dest} />
348+
)}
349+
350+
<PostStats score={post.score} num_comments={post.num_comments} />
315351
</div>
316-
) : post.preview ? (
317-
<PostPreview preview={post.preview} />
318-
) : post.url_overridden_by_dest ? (
319-
isImage(post.url_overridden_by_dest) ? (
320-
<img
321-
src={post.url_overridden_by_dest}
322-
alt="url_overridden_by_dest"
323-
className="mt-4 max-w-full max-h-125 mx-auto border rounded-md p-2 object-contain"
324-
/>
325-
) : (
326-
<FetchImage url={post.url_overridden_by_dest} />
327-
)
328-
) : (
329-
<Thumbnail thumbnail={post.thumbnail || ""} />
330-
)}
331-
332-
{post.poll_data && <PollData poll_data={post.poll_data} />}
333-
334-
{post.selftext_html && <SelfTextHtml selftext_html={post.selftext_html} truncateLines={10} />}
335-
336-
{post.url_overridden_by_dest && post.post_hint === "link" && (
337-
<ExternalLink url_overridden_by_dest={post.url_overridden_by_dest} />
338-
)}
339-
340-
<PostStats score={post.score} num_comments={post.num_comments} />
352+
</a>
341353
</div>
342-
</a>
343-
</div>
354+
</div>
355+
))}
344356
</div>
345357
))}
346358
</div>

0 commit comments

Comments
 (0)