This repository has no description
0

Configure Feed

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

add description

+61 -20
+22 -3
app/src/app/api/bluesky/profile/route.ts
··· 45 45 46 46 // Step 1: Get the user's DID from their handle 47 47 let did = handle; 48 + let userProfile = null; 49 + 48 50 // If the handle doesn't look like a DID, resolve it 49 51 if (!handle.startsWith('did:')) { 50 52 try { ··· 59 61 60 62 const resolveData = await resolveResponse.json(); 61 63 did = resolveData.did; 64 + 65 + // Step 1.5: Get user profile data including description 66 + try { 67 + const profileResponse = await fetch(`https://bsky.social/xrpc/app.bsky.actor.getProfile?actor=${encodeURIComponent(did)}`); 68 + 69 + if (profileResponse.ok) { 70 + userProfile = await profileResponse.json(); 71 + console.log(`Fetched profile data for ${handle}: ${userProfile.description ? 'Has description' : 'No description'}`); 72 + } else { 73 + console.warn(`Failed to fetch profile data: ${profileResponse.statusText}`); 74 + } 75 + } catch (profileError: any) { 76 + console.warn(`Error fetching profile data: ${profileError.message}`); 77 + } 62 78 } catch (error: any) { 63 79 return NextResponse.json( 64 80 { error: `Failed to resolve handle: ${error.message}` }, ··· 148 164 return NextResponse.json({ 149 165 entries: transformedEntries, 150 166 count: transformedEntries.length, 151 - cursor: fallbackData.cursor 167 + cursor: fallbackData.cursor, 168 + profile: userProfile 152 169 }); 153 170 } 154 171 ··· 185 202 return NextResponse.json({ 186 203 entries: transformedEntries, 187 204 count: transformedEntries.length, 188 - cursor: recordsData.cursor 205 + cursor: recordsData.cursor, 206 + profile: userProfile 189 207 }); 190 208 } catch (error: any) { 191 209 console.error('Error fetching records:', error); ··· 227 245 228 246 return NextResponse.json({ 229 247 entries: filteredEntries, 230 - count: filteredEntries.length // Update count to reflect filtered entries 248 + count: filteredEntries.length, // Update count to reflect filtered entries 249 + profile: userProfile 231 250 }); 232 251 } 233 252
+1
app/src/app/page.module.css
··· 686 686 justify-content: center; 687 687 align-items: center; 688 688 gap: 0.5rem; 689 + padding-top: 1.1rem; 689 690 } 690 691 691 692 .loadMoreButton:hover {
+25 -15
app/src/app/profile/[handle]/page.tsx
··· 28 28 const [error, setError] = useState<string | null>(null); 29 29 const [flushesPerDay, setFlushesPerDay] = useState<number>(0); 30 30 const [chartData, setChartData] = useState<{date: string, count: number}[]>([]); 31 + interface ProfileData { 32 + did?: string; 33 + handle?: string; 34 + displayName?: string; 35 + description?: string; 36 + } 37 + const [profileData, setProfileData] = useState<ProfileData | null>(null); 31 38 32 39 useEffect(() => { 33 40 // Fetch the user's statuses when the component mounts ··· 57 64 const userEntries = data.entries || []; 58 65 setEntries(userEntries); 59 66 setTotalCount(data.count || 0); 67 + 68 + // Set profile data if available 69 + if (data.profile) { 70 + setProfileData(data.profile); 71 + } 60 72 61 73 // Calculate statistics and chart data 62 74 if (userEntries.length > 0) { ··· 110 122 111 123 return ( 112 124 <div className={styles.container}> 113 - <header className={styles.header}> 114 - <div className={styles.headerContent}> 115 - <h1 className={styles.title}>Flushes 🧻</h1> 116 - <p className={styles.subtitle}>https://flushes.app 🚽</p> 117 - <p className={styles.description}> 118 - The world&apos;s first decentralized social media app for sharing when you&apos;re on the toilet. Connect with other bathroom enjoyers all over the world by posting &quot;flushes&quot;! Powered by the AT Protocol. Your status updates are saved to your PDS with the im.flushing lexicon. 119 - </p> 120 - </div> 121 - <div className={styles.headerActions}> 122 - <Link href="/" className={styles.backButton}> 123 - ← Back to Feed 124 - </Link> 125 - </div> 126 - </header> 127 125 128 126 <div className={styles.profileHeader}> 129 127 <div className={styles.profileInfo}> 130 - <h2 className={styles.profileTitle}>@{handle}</h2> 128 + {profileData?.displayName ? ( 129 + <> 130 + <h2 className={`${styles.profileTitle} font-bold`}>{profileData.displayName}</h2> 131 + <h3 className={`${styles.profileHandle} font-medium`}>@{handle}</h3> 132 + </> 133 + ) : ( 134 + <h2 className={`${styles.profileTitle} font-bold`}>@{handle}</h2> 135 + )} 136 + 137 + {profileData?.description && ( 138 + <p className={`${styles.description} font-regular`}>{profileData.description}</p> 139 + )} 140 + 131 141 <a 132 142 href={`https://bsky.app/profile/${handle}`} 133 143 target="_blank"
+13 -2
app/src/app/profile/[handle]/profile.module.css
··· 34 34 } 35 35 36 36 .description { 37 - font-size: 1.1rem; 37 + font-size: 1rem; 38 38 color: var(--text-color); 39 39 margin: 0; 40 40 line-height: 1.5; 41 41 word-wrap: break-word; 42 + white-space: pre-wrap; 43 + overflow-wrap: break-word; 42 44 } 43 45 44 46 .profileHeader { ··· 50 52 .profileInfo { 51 53 display: flex; 52 54 flex-direction: column; 53 - gap: 0.5rem; 55 + gap: 0.8rem; 54 56 } 55 57 56 58 .profileTitle { 57 59 font-size: 1.8rem; 58 60 margin: 0; 61 + color: var(--title-color); 62 + line-height: 1.2; 63 + } 64 + 65 + .profileHandle { 66 + font-size: 1.1rem; 67 + margin: -0.4rem 0 0 0; 59 68 color: var(--primary-color); 69 + font-weight: 500; 60 70 line-height: 1.2; 61 71 } 62 72 ··· 152 162 cursor: pointer; 153 163 margin-top: 1.5rem; 154 164 transition: all 0.2s; 165 + padding-top: 1rem; 155 166 } 156 167 157 168 .shareStatsButton:hover {