diff --git a/js/app/components/home/cards.tsx b/js/app/components/home/cards.tsx index 7c681b0c4..0d1c36429 100644 --- a/js/app/components/home/cards.tsx +++ b/js/app/components/home/cards.tsx @@ -8,10 +8,24 @@ import { } from "@streamplace/components"; import { Image } from "expo-image"; import useStreamplaceNode from "hooks/useStreamplaceNode"; +import { useEffect, useMemo, useState } from "react"; import { Platform, View } from "react-native"; export type StreamCardSize = "xs" | "sm" | "md" | "lg" | "xl"; +const langNames = new Intl.DisplayNames(["en"], { type: "language" }); + +const displayTag = (tag: string): string => { + if (tag.startsWith("lang:")) { + try { + return langNames.of(tag.slice(5)) ?? tag; + } catch { + return tag; + } + } + return tag; +}; + interface StreamCardProps { size?: StreamCardSize; horizontal?: boolean; @@ -44,15 +58,48 @@ const StreamCard = ({ const { theme } = useTheme(); const isWeb = Platform.OS === "web"; + const tagItems = tags.length > 0 ? tags : category; + const tagsKey = tagItems.join(","); + + const [rowWidth, setRowWidth] = useState(0); + const [itemWidths, setItemWidths] = useState>({}); + + useEffect(() => { + setItemWidths({}); + }, [activity, tagsKey]); + + const visibleTagCount = useMemo(() => { + if (rowWidth === 0) return tagItems.length; + const activityW = activity ? (itemWidths["activity"] ?? 0) : 0; + let used = activityW; + let count = 0; + for (let i = 0; i < tagItems.length; i++) { + const w = itemWidths[`tag-${i}`]; + if (w === undefined) { + count++; + continue; + } + const gap = used > 0 ? 6 : 0; + if (used + gap + w <= rowWidth) { + used += gap + w; + count++; + } else { + break; + } + } + return count; + }, [rowWidth, itemWidths, tagItems, activity]); + // Define dynamic styles const borderRadius = 12; - const contentPadding = 12; + const contentPaddingHoriz = 12; + const contentPaddingVertical = 2; const avatarSize = 40; const livePillHeight = 30; const livePillPaddingHorizontal = 4; - const verticalContentSectionHeight = avatarSize + 2 * contentPadding; - const horizontalContentSectionWidth = avatarSize * 2 + contentPadding; + const contentSectionHeight = avatarSize + 2 * contentPaddingVertical; + const contentSectionWidth = avatarSize * 2 + contentPaddingHoriz; return ( 0) || tags.length > 0) && ( setRowWidth(e.nativeEvent.layout.width)} > {activity && ( + setItemWidths((prev) => ({ + ...prev, + activity: e.nativeEvent.layout.width, + })) + } > {activity} )} - {(tags.length > 0 ? tags : category).map((cat, index) => ( + {tagItems.slice(0, visibleTagCount).map((cat, index) => ( + setItemWidths((prev) => ({ + ...prev, + [`tag-${index}`]: e.nativeEvent.layout.width, + })) + } > - {cat} + {displayTag(cat)} ))}