Monorepo for Tangled tangled.org
760
fork

Configure Feed

Select the types of activity you want to include in your feed.

ogre/footer-stats: progressively hide footer items on long handles #8

When the author handle is very long, the footer overflows past the Tangled logo on issue/PR OG images. The existing two thresholds (hide reactions at >20 chars, hide comments at >28 chars) were insufficient because even with only avatar + username + date visible, the layout could exceed the available 848px.

Add a third threshold (>40 chars) that also hides the date, and reduce username maxWidth from 480 to 440 for the 29-40 char range.

Signed-off-by: eti eti@eti.tf

Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:xu5apv6kmu5jp7g5hwdnej42/sh.tangled.repo.pull/3mkb56vi3ob22
+51 -61
Diff #1
+2
ogre/src/__tests__/fixtures.ts
··· 89 89 title: LONG_TITLE, 90 90 ...overrides, 91 91 }); 92 + 93 +
+4 -4
ogre/src/__tests__/render.test.ts
··· 87 87 await renderAndSave(h(IssueCard, validated), "issue-card-long-title.png"); 88 88 }); 89 89 90 - test("renders issue with long author handle (reactions hidden)", async () => { 90 + test("renders issue with long author handle", async () => { 91 91 const data = createIssueData(avatarDataUri, { 92 - authorHandle: "extremely-long-handle.example.com", 92 + authorHandle: "very.very.long.tangled.org", 93 93 }); 94 94 const validated = issueCardSchema.parse(data); 95 95 await renderAndSave( ··· 146 146 ); 147 147 }); 148 148 149 - test("renders pull request with long author handle (reactions hidden)", async () => { 149 + test("renders pull request with long author handle", async () => { 150 150 const data = createPullRequestData(avatarDataUri, { 151 - authorHandle: "extremely-long-handle.example.com", 151 + authorHandle: "very.very.long.tangled.org", 152 152 }); 153 153 const validated = pullRequestCardSchema.parse(data); 154 154 await renderAndSave(
+2 -2
ogre/src/components/cards/issue.tsx
··· 37 37 38 38 <Row 39 39 style={{ 40 - alignItems: "flex-end", 41 - justifyContent: "space-between", 40 + alignItems: "flex-end", 41 + justifyContent: "space-between", 42 42 }}> 43 43 <FooterStats 44 44 createdAt={data.createdAt}
+43 -55
ogre/src/components/shared/footer-stats.tsx
··· 4 4 import { Avatar } from "./avatar"; 5 5 import { TYPOGRAPHY } from "./constants"; 6 6 7 - // Handles longer than this cause the footer to overflow when combined with 8 - // other stats, so we drop the less-important reaction count first, then the 9 - // comment count once the handle grows longer still. 10 - const LONG_HANDLE_THRESHOLD = 20; 11 - const VERY_LONG_HANDLE_THRESHOLD = 28; 12 - 13 7 interface FooterStatsProps { 14 - createdAt: string; 15 - authorHandle?: string; 16 - authorAvatarUrl?: string; 17 - reactionCount?: number; 18 - commentCount?: number; 8 + createdAt: string; 9 + authorHandle?: string; 10 + authorAvatarUrl?: string; 11 + reactionCount?: number; 12 + commentCount?: number; 19 13 } 20 14 21 15 export function FooterStats({ 22 - createdAt, 23 - authorHandle, 24 - authorAvatarUrl, 25 - reactionCount, 26 - commentCount, 16 + createdAt, 17 + authorHandle, 18 + authorAvatarUrl, 19 + reactionCount, 20 + commentCount, 27 21 }: FooterStatsProps) { 28 - const formattedDate = new Intl.DateTimeFormat("en-GB", { 29 - day: "numeric", 30 - month: "short", 31 - year: "numeric", 32 - }).format(new Date(createdAt)); 22 + const formattedDate = new Intl.DateTimeFormat("en-GB", { 23 + day: "numeric", 24 + month: "short", 25 + year: "numeric", 26 + }).format(new Date(createdAt)); 33 27 34 - const handleLength = authorHandle?.length ?? 0; 35 - // Long handles crowd the footer. Drop reactions first; drop comments too 36 - // for extremely long handles to prevent overflow past the tangled logo. 37 - const isLongHandle = handleLength > LONG_HANDLE_THRESHOLD; 38 - const isVeryLongHandle = handleLength > VERY_LONG_HANDLE_THRESHOLD; 39 - const gap = isLongHandle ? 40 : 64; 40 - const hideReactions = isLongHandle; 41 - const hideComments = isVeryLongHandle; 28 + const handleLength = authorHandle?.length ?? 0; 29 + const showReactions = handleLength <= 16; 30 + const showComments = handleLength <= 11; 42 31 43 - return ( 44 - <Row style={{ gap }}> 45 - {authorHandle && authorAvatarUrl ? ( 46 - <Row style={{ gap: 16, alignItems: "center" }}> 47 - <Avatar src={authorAvatarUrl} size={40} /> 48 - <span 49 - style={{ 50 - ...TYPOGRAPHY.body, 51 - color: "#404040", 52 - maxWidth: 480, 53 - overflow: "hidden", 54 - textOverflow: "ellipsis", 55 - whiteSpace: "nowrap", 56 - }}> 57 - {authorHandle} 58 - </span> 32 + return ( 33 + <Row style={{ gap: 40 }}> 34 + {authorHandle && authorAvatarUrl ? ( 35 + <Row style={{ gap: 16, alignItems: "center" }}> 36 + <Avatar src={authorAvatarUrl} size={40} /> 37 + <span 38 + style={{ 39 + ...TYPOGRAPHY.body, 40 + color: "#404040", 41 + maxWidth: 400, 42 + lineClamp: 1, 43 + display: "block", 44 + }}> 45 + {authorHandle} 46 + </span> 47 + </Row> 48 + ) : null} 49 + <StatItem Icon={Calendar} value={formattedDate} /> 50 + {showReactions && reactionCount ? ( 51 + <StatItem Icon={SmilePlus} value={reactionCount} /> 52 + ) : null} 53 + {showComments && commentCount ? ( 54 + <StatItem Icon={MessageSquare} value={commentCount} /> 55 + ) : null} 59 56 </Row> 60 - ) : null} 61 - <StatItem Icon={Calendar} value={formattedDate} /> 62 - {reactionCount && !hideReactions ? ( 63 - <StatItem Icon={SmilePlus} value={reactionCount} /> 64 - ) : null} 65 - {commentCount && !hideComments ? ( 66 - <StatItem Icon={MessageSquare} value={commentCount} /> 67 - ) : null} 68 - </Row> 69 - ); 57 + ); 70 58 }

History

2 rounds 0 comments
sign up or login to add to the discussion
1 commit
expand
ogre/footer: use char-length thresholds to hide stats on long handles
merge conflicts detected
expand
  • ogre/src/__tests__/fixtures.ts:89
  • ogre/src/__tests__/render.test.ts:87
  • ogre/src/components/cards/issue.tsx:37
  • ogre/src/components/shared/footer-stats.tsx:4
expand 0 comments
eti.tf submitted #0
1 commit
expand
ogre/footer-stats: progressively hide footer items on long handles
expand 0 comments