11import { cn } from '@/lib/utils' ;
2+ import { lineClampClassFor } from '@/utils/lineClamp.utils' ;
23
34interface CreatorBioProps {
45 /** Raw bio string from the creator profile. Anything falsy or whitespace-only is treated as missing. */
@@ -9,10 +10,29 @@ interface CreatorBioProps {
910 variant ?: 'card' | 'profile' ;
1011 /** If true, returns null instead of a fallback when bio is missing. */
1112 allowEmpty ?: boolean ;
13+ /**
14+ * When true and `bio` is empty, swap the generic "no bio" fallback for
15+ * the pending-onboarding placeholder (#291) so visitors know the creator
16+ * is still setting things up rather than seeing a blank section.
17+ */
18+ isOnboardingPending ?: boolean ;
19+ /**
20+ * Clamp the rendered bio to at most this many lines on the card (#282).
21+ * Only effective for the `card` variant — the `profile` variant always
22+ * shows the full bio, so the truncation stays purely cosmetic and the
23+ * full text remains accessible on the creator profile page.
24+ *
25+ * Pass `null` (or omit) to disable clamping; the default is `3` lines on
26+ * the card, which matches the card grid's row height and keeps layouts
27+ * uniform across varying bio lengths. Short bios are unaffected.
28+ */
29+ maxLines ?: number | null ;
1230 className ?: string ;
1331}
1432
1533const DEFAULT_FALLBACK = "This creator hasn't shared a bio yet." ;
34+ /** Default maximum bio lines on the card. */
35+ const DEFAULT_CARD_MAX_LINES = 3 ;
1636
1737const variantClasses : Record < 'card' | 'profile' , { value : string ; fallback : string } > = {
1838 card : {
@@ -36,6 +56,8 @@ const CreatorBio: React.FC<CreatorBioProps> = ({
3656 fallback = DEFAULT_FALLBACK ,
3757 variant = 'card' ,
3858 allowEmpty = false ,
59+ isOnboardingPending = false ,
60+ maxLines,
3961 className,
4062} ) => {
4163 const trimmed = bio ?. trim ( ) ;
@@ -46,14 +68,42 @@ const CreatorBio: React.FC<CreatorBioProps> = ({
4668 return null ;
4769 }
4870
71+ const effectiveFallback = isOnboardingPending
72+ ? 'This creator is still setting up their profile. Bio coming soon.'
73+ : fallback ;
4974 return (
50- < p className = { cn ( styles . fallback , className ) } aria-label = "Bio not provided" >
51- { fallback }
75+ < p
76+ className = { cn ( styles . fallback , className ) }
77+ aria-label = {
78+ isOnboardingPending
79+ ? 'Bio pending — onboarding in progress'
80+ : 'Bio not provided'
81+ }
82+ >
83+ { effectiveFallback }
5284 </ p >
5385 ) ;
5486 }
5587
56- return < p className = { cn ( styles . value , className ) } > { trimmed } </ p > ;
88+ // Card defaults to a 3-line clamp; explicit null disables it. Profile
89+ // variant ignores the prop so the full bio stays visible on the detail
90+ // page.
91+ const effectiveMaxLines =
92+ variant === 'card' && maxLines === undefined
93+ ? DEFAULT_CARD_MAX_LINES
94+ : maxLines ;
95+ const clampClass = lineClampClassFor ( variant , effectiveMaxLines ) ;
96+
97+ return (
98+ < p
99+ // Preserve the full bio in the accessible name so screen readers
100+ // can read the unclamped text — the visual truncation is cosmetic.
101+ title = { clampClass ? trimmed : undefined }
102+ className = { cn ( styles . value , clampClass , className ) }
103+ >
104+ { trimmed }
105+ </ p >
106+ ) ;
57107} ;
58108
59109export default CreatorBio ;
0 commit comments