This repository has no description
0

Configure Feed

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

add nav and new pages

+657 -23
+128
app/src/app/about/about.module.css
··· 1 + .container { 2 + max-width: 800px; 3 + margin: 0 auto; 4 + padding: 2rem 1.5rem; 5 + color: var(--foreground-rgb); 6 + } 7 + 8 + .header { 9 + text-align: center; 10 + margin-bottom: 3rem; 11 + } 12 + 13 + .title { 14 + font-size: 2.5rem; 15 + font-weight: 800; 16 + margin-bottom: 0.5rem; 17 + color: var(--primary-color); 18 + } 19 + 20 + .subtitle { 21 + font-size: 1.25rem; 22 + color: var(--secondary-foreground); 23 + max-width: 600px; 24 + margin: 0 auto; 25 + } 26 + 27 + .section { 28 + margin-bottom: 3rem; 29 + background-color: var(--card-background); 30 + border-radius: 1rem; 31 + padding: 2rem; 32 + border: 1px solid var(--tile-border); 33 + } 34 + 35 + .section h2 { 36 + margin-top: 0; 37 + margin-bottom: 1.25rem; 38 + font-size: 1.5rem; 39 + font-weight: 700; 40 + color: var(--primary-color); 41 + } 42 + 43 + .section p { 44 + margin-bottom: 1.25rem; 45 + line-height: 1.6; 46 + } 47 + 48 + .section a { 49 + color: var(--link-color); 50 + text-decoration: none; 51 + font-weight: 500; 52 + transition: color 0.2s ease; 53 + } 54 + 55 + .section a:hover { 56 + text-decoration: underline; 57 + } 58 + 59 + .featureList { 60 + margin: 1.5rem 0; 61 + padding-left: 1.5rem; 62 + } 63 + 64 + .featureList li { 65 + margin-bottom: 0.75rem; 66 + line-height: 1.6; 67 + } 68 + 69 + .actionLinks { 70 + display: flex; 71 + flex-wrap: wrap; 72 + gap: 1rem; 73 + margin-top: 1.5rem; 74 + } 75 + 76 + .actionLink { 77 + background-color: var(--card-background); 78 + border: 1px solid var(--primary-color); 79 + color: var(--primary-color); 80 + padding: 0.75rem 1.25rem; 81 + border-radius: 0.5rem; 82 + text-decoration: none; 83 + font-weight: 500; 84 + transition: all 0.2s ease; 85 + } 86 + 87 + .actionLink:hover { 88 + background-color: var(--primary-color); 89 + color: white; 90 + } 91 + 92 + /* Responsive styles */ 93 + @media (max-width: 768px) { 94 + .container { 95 + padding: 1.5rem 1rem; 96 + } 97 + 98 + .section { 99 + padding: 1.5rem; 100 + } 101 + 102 + .title { 103 + font-size: 2rem; 104 + } 105 + 106 + .subtitle { 107 + font-size: 1.1rem; 108 + } 109 + } 110 + 111 + @media (max-width: 480px) { 112 + .title { 113 + font-size: 1.75rem; 114 + } 115 + 116 + .section h2 { 117 + font-size: 1.3rem; 118 + } 119 + 120 + .actionLinks { 121 + flex-direction: column; 122 + } 123 + 124 + .actionLink { 125 + width: 100%; 126 + text-align: center; 127 + } 128 + }
+65
app/src/app/about/page.tsx
··· 1 + import styles from './about.module.css'; 2 + import Link from 'next/link'; 3 + 4 + export default function AboutPage() { 5 + return ( 6 + <div className={styles.container}> 7 + <div className={styles.header}> 8 + <h1 className={styles.title}>About Flushes</h1> 9 + <p className={styles.subtitle}>The world's 1st decentralized toilet. </p> 10 + </div> 11 + 12 + <div className={styles.section}> 13 + <h2>Our History</h2> 14 + <p> 15 + Flushes was created as part of an elaborate bit over the course of a single weekend, but it soon gained a tiny cult following who we now refer to as "flushers". To learn more about what inspired Flushes, read the <a href="https://dame.is/blog/creating-a-decentralized-bathroom-at-protocol" target="_blank" rel="noopener noreferrer">Creating a Decentralized Bathroom</a> blog post on @dame.is's blog. 16 + </p> 17 + </div> 18 + 19 + <div className={styles.section}> 20 + <h2>How It Works</h2> 21 + <p> 22 + Flushes uses the im.flushing.right.now lexicon, a custom record type 23 + on the AT Protocol. When you post a flush, you're creating a record with: 24 + </p> 25 + <ul className={styles.featureList}> 26 + <li>A descriptive text (always starting with "is...")</li> 27 + <li>A bathroom-related emoji</li> 28 + <li>A timestamp</li> 29 + </ul> 30 + <p> 31 + These records are stored in your ATProto personal data server (PDS) and are fully controlled by you. 32 + You can delete them at any time from your Bluesky account using tools like <a href="https://pdsls.dev" target="_blank" rel="noopener noreferrer">pdsls.dev</a> 33 + </p> 34 + </div> 35 + 36 + <div className={styles.section}> 37 + <h2>The Team</h2> 38 + <p> 39 + Flushes was created by <a href="https://bsky.app/profile/dame.is" target="_blank" rel="noopener noreferrer">Dame</a> as 40 + a fun side project exploring the possibilities of the AT Protocol and Bluesky. 41 + </p> 42 + <p> 43 + Our psuedonmyous bathroom technician is <a href="https://bsky.app/profile/plumber.flushes.app" target="_blank" rel="noopener noreferrer">@plumber.flushes.app</a>, 44 + who's always ready to fix your plumbing problems. 45 + </p> 46 + <p> 47 + Flushes is now an experimental social network led by <a href="https://atpota.to/" target="_blank" rel="noopener noreferrer">atpotato</a>. 48 + </p> 49 + </div> 50 + 51 + <div className={styles.section}> 52 + <h2>Get Involved</h2> 53 + <p> 54 + Have ideas for improving Flushes? Want to report a bug? 55 + Reach out on <a href="https://bsky.app/profile/flushes.app" target="_blank" rel="noopener noreferrer">Bluesky</a>. 56 + </p> 57 + <div className={styles.actionLinks}> 58 + <Link href="/shortcut" className={styles.actionLink}>Get the Shortcut</Link> 59 + <Link href="/stats" className={styles.actionLink}>View Flush Stats</Link> 60 + <Link href="/" className={styles.actionLink}>Return to Feed</Link> 61 + </div> 62 + </div> 63 + </div> 64 + ); 65 + }
+36 -3
app/src/app/globals.css
··· 1 1 /* Light mode variables */ 2 2 :root { 3 3 --primary-color: #5badf0; 4 + --primary-hover: #4a97d8; 4 5 --secondary-color: #1968a8; 6 + --secondary-hover: #155690; 7 + --success-color: #4caf50; 8 + --success-hover: #43a047; 5 9 --background-color: #f9f9f9; 10 + --background-start-rgb: 249, 249, 249; 11 + --background-end-rgb: 255, 255, 255; 6 12 --card-background: #ffffff; 13 + --card-rgb: 255, 255, 255; 14 + --foreground-rgb: #333333; 15 + --secondary-foreground: #666666; 16 + --link-color: #0070f3; 7 17 --text-color: #333; 8 18 --title-color: #272727; 9 19 --error-color: #ff5252; ··· 30 40 --emoji-button-border: #ddd; 31 41 --emoji-grid-bg: #fcfcfc; 32 42 --tile-border: rgba(0, 0, 0, 0.1); 43 + --hover-overlay: rgba(0, 0, 0, 0.05); 33 44 } 34 45 35 46 /* Dark mode variables */ 36 47 [data-theme="dark"] { 37 48 --primary-color: #5badf0; 49 + --primary-hover: #4a97d8; 38 50 --secondary-color: #69c0ff; 51 + --secondary-hover: #5aafeb; 52 + --success-color: #4caf50; 53 + --success-hover: #43a047; 39 54 --background-color: #121212; 55 + --background-start-rgb: 18, 18, 18; 56 + --background-end-rgb: 30, 30, 30; 40 57 --card-background: #1e1e1e; 58 + --card-rgb: 30, 30, 30; 59 + --foreground-rgb: #dddddd; 60 + --secondary-foreground: #aaaaaa; 61 + --link-color: #5badf0; 41 62 --text-color: #dddddd; 42 63 --title-color: #e0e0e0; 43 64 --error-color: #ff7070; ··· 64 85 --emoji-button-border: #444; 65 86 --emoji-grid-bg: #252525; 66 87 --tile-border: rgba(255, 255, 255, 0.1); 88 + --hover-overlay: rgba(255, 255, 255, 0.05); 67 89 } 68 90 69 91 /* Automatically use dark mode if user prefers it */ 70 92 @media (prefers-color-scheme: dark) { 71 93 :root:not([data-theme="light"]) { 72 94 --primary-color: #5badf0; 95 + --primary-hover: #4a97d8; 73 96 --secondary-color: #69c0ff; 97 + --secondary-hover: #5aafeb; 98 + --success-color: #4caf50; 99 + --success-hover: #43a047; 74 100 --background-color: #121212; 101 + --background-start-rgb: 18, 18, 18; 102 + --background-end-rgb: 30, 30, 30; 75 103 --card-background: #1e1e1e; 104 + --card-rgb: 30, 30, 30; 105 + --foreground-rgb: #dddddd; 106 + --secondary-foreground: #aaaaaa; 107 + --link-color: #5badf0; 76 108 --text-color: #dddddd; 77 109 --title-color: #e0e0e0; 78 110 --error-color: #ff7070; ··· 99 131 --emoji-button-border: #444; 100 132 --emoji-grid-bg: #252525; 101 133 --tile-border: rgba(255, 255, 255, 0.1); 134 + --hover-overlay: rgba(255, 255, 255, 0.05); 102 135 } 103 136 104 137 body { ··· 123 156 } 124 157 125 158 main { 126 - max-width: 800px; 127 - margin: 0 auto; 128 - padding: 2rem; 159 + min-height: calc(100vh - 60px); 160 + width: 100%; 161 + padding-bottom: 2rem; 129 162 } 130 163 131 164 a {
+3 -14
app/src/app/layout.tsx
··· 2 2 import './globals.css'; 3 3 import { AuthProvider } from '@/lib/auth-context'; 4 4 import { ThemeProvider } from '@/lib/theme-context'; 5 - import ThemeToggle from '@/components/ThemeToggle'; 6 5 import ClientOnly from '@/components/ClientOnly'; 7 - import ProfileSearch from '@/components/ProfileSearch'; 6 + import NavigationBar from '@/components/NavigationBar'; 8 7 import { Analytics } from "@vercel/analytics/react" 9 8 10 9 // Configure this layout as having dynamic runtime to fix SSR issues with theme ··· 47 46 <body> 48 47 <AuthProvider> 49 48 <ThemeProvider> 50 - <header style={{ 51 - display: 'flex', 52 - justifyContent: 'center', 53 - alignItems: 'center', 54 - padding: '0.5rem 1rem', 55 - backgroundColor: 'var(--card-background)', 56 - borderBottom: '1px solid var(--tile-border)' 57 - }}> 49 + <header> 58 50 <ClientOnly> 59 - <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}> 60 - <ProfileSearch /> 61 - <ThemeToggle /> 62 - </div> 51 + <NavigationBar /> 63 52 </ClientOnly> 64 53 </header> 65 54 <main>{children}</main>
+2 -3
app/src/app/page.module.css
··· 1 1 .container { 2 2 max-width: 800px; 3 3 margin: 0 auto; 4 - padding: 2rem 1rem; 5 4 } 6 5 7 6 .header { ··· 36 35 } 37 36 38 37 .description { 39 - font-size: 1.1rem; 38 + font-size: 0.9rem; 40 39 color: var(--text-color); 41 40 margin: 0; 42 - line-height: 1.5; 41 + line-height: 1.4; 43 42 word-wrap: break-word; 44 43 } 45 44
+3 -3
app/src/app/page.tsx
··· 359 359 <h1 className={styles.title}>Flushes 🧻</h1> 360 360 <p className={styles.subtitle}>https://flushes.app 🚽</p> 361 361 <p className={styles.description}> 362 - 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.<br /> 362 + The world&apos;s 1st decentralized social media app for sharing when you&apos;re on the toilet. Powered by the AT Protocol. Your flushes are saved to your PDS via the im.flushing lexicon.<br /> 363 363 <span className={styles.creditLine}> 364 364 Made by <a href="https://bsky.app/profile/dame.is" target="_blank" rel="noopener noreferrer">@dame.is</a>. 365 - Like the app? Consider contributing to <a href="https://ko-fi.com/dameis" target="_blank" rel="noopener noreferrer" className={styles.kofiLink}>my toilet paper fund</a>. 365 + Like the app? Donate to<a href="https://ko-fi.com/dameis" target="_blank" rel="noopener noreferrer" className={styles.kofiLink}>my toilet paper fund</a>. 366 366 </span> 367 367 </p> 368 368 </div> ··· 466 466 <div className={styles.feedHeaderLeft}> 467 467 <h2>Recent flushes</h2> 468 468 <p className={styles.feedSubheader}> 469 - Click on a username to see their flushing profile. 469 + Click on a username to see their flushes profile. 470 470 </p> 471 471 </div> 472 472 <button
+61
app/src/app/shortcut/page.tsx
··· 1 + 'use client'; 2 + 3 + import { useState } from 'react'; 4 + import Link from 'next/link'; 5 + import styles from './shortcut.module.css'; 6 + 7 + export default function ShortcutPage() { 8 + const [isCopied, setIsCopied] = useState(false); 9 + 10 + const handleDownload = () => { 11 + // Usually this would be a direct link to the shortcut file 12 + window.open('https://www.icloud.com/shortcuts/d1caee7798dc4de3bef4defa0085dd72', '_blank'); 13 + }; 14 + 15 + return ( 16 + <div className={styles.container}> 17 + <div className={styles.header}> 18 + <h1 className={styles.title}>Apple Shortcut</h1> 19 + <p className={styles.subtitle}>Flush faster or add an NFC sticker to your bathroom for automatic flushing</p> 20 + </div> 21 + 22 + <div className={styles.shortcutCard}> 23 + <div className={styles.cardContent}> 24 + <h2>Apple Shortcut</h2> 25 + <p>Add the official Flushes shortcut to your iPhone for quicker posting.</p> 26 + <div className={styles.featureList}> 27 + <div className={styles.feature}> 28 + <span className={styles.icon}>⚡️</span> 29 + <span>Quick access from home screen or action button</span> 30 + </div> 31 + <div className={styles.feature}> 32 + <span className={styles.icon}>🔐</span> 33 + <span>Securely stores your credentials on-device</span> 34 + </div> 35 + <div className={styles.feature}> 36 + <span className={styles.icon}>📱</span> 37 + <span>NFC sticker compatible</span> 38 + </div> 39 + </div> 40 + <button onClick={handleDownload} className={styles.downloadButton}> 41 + Download Shortcut 42 + </button> 43 + </div> 44 + <div className={styles.shortcutImage}> 45 + {/* Replace with actual image of your shortcut */} 46 + <div className={styles.placeholderImage}> 47 + <span>📱</span> 48 + </div> 49 + </div> 50 + </div> 51 + 52 + <div className={styles.helpSection}> 53 + <h2>Need Help?</h2> 54 + <p> 55 + Check out our <Link href="/about">About page</Link> for more information or 56 + reach out on <a href="https://bsky.app/profile/flushes.app" target="_blank" rel="noopener noreferrer">Bluesky</a>. 57 + </p> 58 + </div> 59 + </div> 60 + ); 61 + }
+161
app/src/app/shortcut/shortcut.module.css
··· 1 + .container { 2 + max-width: 1000px; 3 + margin: 0 auto; 4 + padding: 2rem 1.5rem; 5 + color: var(--foreground-rgb); 6 + } 7 + 8 + .header { 9 + text-align: center; 10 + margin-bottom: 3rem; 11 + } 12 + 13 + .title { 14 + font-size: 2.5rem; 15 + font-weight: 800; 16 + margin-bottom: 0.5rem; 17 + color: var(--primary-color); 18 + } 19 + 20 + .subtitle { 21 + font-size: 1.25rem; 22 + color: var(--secondary-foreground); 23 + max-width: 600px; 24 + margin: 0 auto; 25 + } 26 + 27 + .shortcutCard { 28 + display: flex; 29 + background-color: var(--card-background); 30 + border-radius: 1rem; 31 + overflow: hidden; 32 + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12); 33 + margin-bottom: 3rem; 34 + border: 1px solid var(--tile-border); 35 + } 36 + 37 + .cardContent { 38 + flex: 1; 39 + padding: 2rem; 40 + } 41 + 42 + .shortcutImage { 43 + width: 300px; 44 + background-color: var(--background-start-rgb); 45 + display: flex; 46 + align-items: center; 47 + justify-content: center; 48 + } 49 + 50 + .placeholderImage { 51 + width: 200px; 52 + height: 300px; 53 + background-color: rgba(var(--card-rgb), 0.3); 54 + border-radius: 1.5rem; 55 + display: flex; 56 + align-items: center; 57 + justify-content: center; 58 + font-size: 5rem; 59 + } 60 + 61 + .featureList { 62 + margin: 1.5rem 0; 63 + } 64 + 65 + .feature { 66 + display: flex; 67 + align-items: center; 68 + margin-bottom: 1rem; 69 + } 70 + 71 + .icon { 72 + margin-right: 1rem; 73 + font-size: 1.25rem; 74 + } 75 + 76 + .downloadButton { 77 + background-color: var(--primary-color); 78 + color: white; 79 + border: none; 80 + padding: 0.75rem 1.5rem; 81 + border-radius: 0.5rem; 82 + font-size: 1rem; 83 + font-weight: 600; 84 + cursor: pointer; 85 + transition: background-color 0.2s ease; 86 + margin-top: 1rem; 87 + } 88 + 89 + .downloadButton:hover { 90 + background-color: var(--primary-hover); 91 + } 92 + 93 + .alternativeSection, 94 + .helpSection { 95 + margin-bottom: 3rem; 96 + padding: 2rem; 97 + background-color: var(--card-background); 98 + border-radius: 1rem; 99 + border: 1px solid var(--tile-border); 100 + } 101 + 102 + .copyButton { 103 + background-color: var(--secondary-color); 104 + color: white; 105 + border: none; 106 + padding: 0.75rem 1.5rem; 107 + border-radius: 0.5rem; 108 + font-size: 1rem; 109 + font-weight: 600; 110 + cursor: pointer; 111 + transition: background-color 0.2s ease; 112 + margin-top: 1rem; 113 + } 114 + 115 + .copyButton:hover { 116 + background-color: var(--secondary-hover); 117 + } 118 + 119 + .copied { 120 + background-color: var(--success-color); 121 + } 122 + 123 + .copied:hover { 124 + background-color: var(--success-hover); 125 + } 126 + 127 + /* Responsive styles */ 128 + @media (max-width: 768px) { 129 + .shortcutCard { 130 + flex-direction: column; 131 + } 132 + 133 + .shortcutImage { 134 + width: 100%; 135 + padding: 2rem; 136 + } 137 + 138 + .placeholderImage { 139 + width: 100%; 140 + max-width: 200px; 141 + height: 250px; 142 + } 143 + 144 + .title { 145 + font-size: 2rem; 146 + } 147 + } 148 + 149 + @media (max-width: 480px) { 150 + .container { 151 + padding: 1.5rem 1rem; 152 + } 153 + 154 + .title { 155 + font-size: 1.75rem; 156 + } 157 + 158 + .subtitle { 159 + font-size: 1rem; 160 + } 161 + }
+124
app/src/components/NavigationBar.module.css
··· 1 + .navbar { 2 + display: flex; 3 + justify-content: space-between; 4 + align-items: center; 5 + padding: 0.75rem 1.5rem; 6 + background-color: var(--card-background); 7 + border-bottom: 1px solid var(--tile-border); 8 + position: sticky; 9 + top: 0; 10 + z-index: 100; 11 + width: 100%; 12 + } 13 + 14 + .navStart, .navEnd { 15 + display: flex; 16 + align-items: center; 17 + gap: 1rem; 18 + } 19 + 20 + .navSearch { 21 + flex: 0 1 300px; 22 + margin: 0 1rem; 23 + } 24 + 25 + .logo { 26 + display: flex; 27 + align-items: center; 28 + text-decoration: none; 29 + color: var(--foreground-rgb); 30 + font-weight: bold; 31 + font-size: 1.5rem; 32 + margin-right: 1.5rem; 33 + } 34 + 35 + .logoText { 36 + display: inline-block; 37 + color: var(--primary-color); 38 + font-weight: 800; 39 + letter-spacing: -0.5px; 40 + } 41 + 42 + .navLinks { 43 + display: flex; 44 + gap: 1rem; 45 + } 46 + 47 + .navLink { 48 + color: var(--foreground-rgb); 49 + text-decoration: none; 50 + font-size: 1rem; 51 + padding: 0.5rem 0.75rem; 52 + border-radius: 0.5rem; 53 + transition: background-color 0.2s ease; 54 + } 55 + 56 + .navLink:hover { 57 + background-color: var(--hover-overlay); 58 + } 59 + 60 + .navLink.active { 61 + font-weight: 600; 62 + color: var(--link-color); 63 + } 64 + 65 + .authButton { 66 + background-color: var(--primary-color); 67 + color: white; 68 + border: none; 69 + padding: 0.5rem 1rem; 70 + border-radius: 0.5rem; 71 + cursor: pointer; 72 + font-size: 1rem; 73 + font-weight: 500; 74 + transition: background-color 0.2s ease; 75 + text-decoration: none; 76 + display: inline-block; 77 + } 78 + 79 + .authButton:hover { 80 + background-color: var(--primary-hover); 81 + } 82 + 83 + /* Responsive styles */ 84 + @media (max-width: 768px) { 85 + .navbar { 86 + flex-wrap: wrap; 87 + padding: 0.5rem 1rem; 88 + } 89 + 90 + .navStart { 91 + width: 100%; 92 + justify-content: space-between; 93 + margin-bottom: 0.5rem; 94 + } 95 + 96 + .navLinks { 97 + overflow-x: auto; 98 + white-space: nowrap; 99 + padding-bottom: 0.25rem; 100 + gap: 0.5rem; 101 + } 102 + 103 + .navSearch { 104 + flex: 1 1 100%; 105 + order: 3; 106 + margin: 0.5rem 0; 107 + } 108 + 109 + .navEnd { 110 + justify-content: flex-end; 111 + margin-left: auto; 112 + } 113 + } 114 + 115 + @media (max-width: 480px) { 116 + .navLink { 117 + padding: 0.5rem 0.5rem; 118 + font-size: 0.9rem; 119 + } 120 + 121 + .logo { 122 + font-size: 1.25rem; 123 + } 124 + }
+74
app/src/components/NavigationBar.tsx
··· 1 + 'use client'; 2 + 3 + import React from 'react'; 4 + import Link from 'next/link'; 5 + import { usePathname } from 'next/navigation'; 6 + import styles from './NavigationBar.module.css'; 7 + import ProfileSearch from './ProfileSearch'; 8 + import ThemeToggle from './ThemeToggle'; 9 + import { useAuth } from '@/lib/auth-context'; 10 + 11 + export default function NavigationBar() { 12 + const pathname = usePathname(); 13 + const { isAuthenticated, clearAuth, handle } = useAuth(); 14 + 15 + const handleLogout = () => { 16 + clearAuth(); 17 + }; 18 + 19 + // Check if a link is active 20 + const isActive = (path: string) => { 21 + return pathname === path; 22 + }; 23 + 24 + return ( 25 + <nav className={styles.navbar}> 26 + <div className={styles.navStart}> 27 + <Link href="/" className={styles.logo}> 28 + <span className={styles.logoText}>Flushes</span> 29 + </Link> 30 + 31 + <div className={styles.navLinks}> 32 + <Link href="/" className={`${styles.navLink} ${isActive('/') ? styles.active : ''}`}> 33 + Feed 34 + </Link> 35 + <Link href="/stats" className={`${styles.navLink} ${isActive('/stats') ? styles.active : ''}`}> 36 + Stats 37 + </Link> 38 + <Link href="/shortcut" className={`${styles.navLink} ${isActive('/shortcut') ? styles.active : ''}`}> 39 + Shortcut 40 + </Link> 41 + <Link href="/about" className={`${styles.navLink} ${isActive('/about') ? styles.active : ''}`}> 42 + About 43 + </Link> 44 + {isAuthenticated && handle && ( 45 + <Link 46 + href={`/profile/${handle}`} 47 + className={`${styles.navLink} ${pathname.startsWith('/profile/') ? styles.active : ''}`} 48 + > 49 + Profile 50 + </Link> 51 + )} 52 + </div> 53 + </div> 54 + 55 + <div className={styles.navSearch}> 56 + <ProfileSearch /> 57 + </div> 58 + 59 + <div className={styles.navEnd}> 60 + <ThemeToggle /> 61 + 62 + {isAuthenticated ? ( 63 + <button onClick={handleLogout} className={styles.authButton}> 64 + Logout 65 + </button> 66 + ) : ( 67 + <Link href="/auth/login" className={styles.authButton}> 68 + Login 69 + </Link> 70 + )} 71 + </div> 72 + </nav> 73 + ); 74 + }