Coffee journaling on ATProto (alpha) alpha.arabica.social
coffee
17
fork

Configure Feed

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

feat: rework login box, page header

authored by

Patrick Dewey and committed by
Tangled
cd6db49f 9e43ba72

+71 -69
+64 -60
internal/web/components/shared.templ
··· 202 202 UserDID string 203 203 } 204 204 205 + // WelcomeCard renders the authenticated welcome with action buttons (used on home page) 205 206 templ WelcomeCard(props WelcomeCardProps) { 206 - <div class="card p-8 mb-8"> 207 - <div class="flex items-center gap-3 mb-4"> 208 - <h2 class="text-2xl font-semibold text-brown-900">Welcome to Arabica</h2> 209 - <span class="text-xs bg-amber-400 text-brown-900 px-2 py-1 rounded-md font-semibold shadow-sm">ALPHA</span> 210 - </div> 211 - <p class="text-brown-800 mb-2 text-lg">Track your coffee brewing journey with detailed logs of every cup.</p> 212 - <p class="text-sm text-brown-700 italic mb-6">Note: Arabica is currently in alpha. Features and data structures may change.</p> 213 - if props.IsAuthenticated { 214 - @WelcomeAuthenticated(props.UserDID) 215 - } else { 216 - @WelcomeUnauthenticated() 217 - } 218 - </div> 207 + if props.IsAuthenticated { 208 + @WelcomeAuthenticated(props.UserDID) 209 + } 219 210 } 220 211 221 212 templ WelcomeAuthenticated(userDID string) { 222 - <div class="mb-6"> 223 - <p class="text-sm text-brown-700"> 224 - Logged in as: <span class="font-mono text-brown-900 font-semibold">{ userDID }</span> 225 - <a href="/atproto" class="text-brown-700 hover:text-brown-900 transition-colors">(What is this?)</a> 213 + <div class="text-center mb-8 pt-4"> 214 + <h1 class="text-3xl sm:text-4xl font-semibold text-brown-900 mb-3">Your coffee journey, documented.</h1> 215 + <p class="text-sm text-brown-500 mb-6"> 216 + Logged in as <span class="font-mono text-brown-700 font-medium">{ userDID }</span> 226 217 </p> 218 + <div class="grid grid-cols-2 sm:grid-cols-4 gap-3 max-w-xl mx-auto"> 219 + <a 220 + href="/brews/new" 221 + class="home-action-primary block text-center py-4 px-4 rounded-xl" 222 + > 223 + <span class="text-base font-semibold">Log Brew</span> 224 + </a> 225 + <a 226 + href="/my-coffee" 227 + class="home-action-secondary block text-center py-4 px-4 rounded-xl" 228 + > 229 + <span class="text-base font-semibold">My Coffee</span> 230 + </a> 231 + <a 232 + href="/recipes" 233 + class="home-action-secondary block text-center py-4 px-4 rounded-xl" 234 + > 235 + <span class="text-base font-semibold">Recipes</span> 236 + </a> 237 + <a 238 + href={ templ.SafeURL("/profile/" + userDID) } 239 + class="home-action-secondary block text-center py-4 px-4 rounded-xl" 240 + > 241 + <span class="text-base font-semibold">Profile</span> 242 + </a> 243 + </div> 227 244 </div> 228 - <div class="grid grid-cols-2 sm:grid-cols-4 gap-3"> 229 - <a 230 - href="/brews/new" 231 - class="home-action-primary block text-center py-4 px-4 rounded-xl" 232 - > 233 - <span class="text-base font-semibold">Log Brew</span> 234 - </a> 235 - <a 236 - href="/my-coffee" 237 - class="home-action-secondary block text-center py-4 px-4 rounded-xl" 238 - > 239 - <span class="text-base font-semibold">My Coffee</span> 240 - </a> 241 - <a 242 - href="/recipes" 243 - class="home-action-secondary block text-center py-4 px-4 rounded-xl" 244 - > 245 - <span class="text-base font-semibold">Recipes</span> 246 - </a> 247 - <a 248 - href={ templ.SafeURL("/profile/" + userDID) } 249 - class="home-action-secondary block text-center py-4 px-4 rounded-xl" 250 - > 251 - <span class="text-base font-semibold">Profile</span> 252 - </a> 245 + } 246 + 247 + // WelcomeHero renders the landing hero for unauthenticated users 248 + templ WelcomeHero() { 249 + <div class="text-center mb-8 pt-4"> 250 + <h1 class="text-3xl sm:text-4xl font-semibold text-brown-900 mb-3">Your coffee journey, documented.</h1> 251 + <p class="text-lg text-brown-700 max-w-xl mx-auto mb-3">Log every brew, track your beans and equipment, and share your coffee story with the community.</p> 252 + <p class="text-sm text-brown-500"> 253 + <a href="/atproto" class="hover:text-brown-700 transition-colors">Built on AT Protocol</a> — you own your data. 254 + </p> 253 255 </div> 254 256 } 255 257 256 - templ WelcomeUnauthenticated() { 257 - <div> 258 - <p class="text-brown-800 mb-2 text-center text-lg">Connect with your Atmosphere account to start tracking your brews.</p> 259 - <details class="mb-6 max-w-md mx-auto"> 260 - <summary class="text-brown-600 text-sm italic cursor-pointer text-center hover:text-brown-800 transition-colors">What's an Atmosphere account?</summary> 261 - <p class="text-brown-600 mt-2 text-sm italic"> 262 - Arabica uses the <a href="/atproto" class="link">AT Protocol</a> to power its social features, allowing you to own your data and use one account for all compatible applications. Once you create an account, you can use other apps like <a href="https://bsky.app" class="link" target="_blank" rel="noopener noreferrer">Bluesky</a> and <a href="https://leaflet.pub" class="link" target="_blank" rel="noopener noreferrer">Leaflet</a> with the same account. 263 - <a href="/join/create" class="link">(Create an account)</a> 264 - </p> 265 - </details> 266 - <form method="POST" action="/auth/login" class="max-w-md mx-auto"> 258 + // WelcomeLoginCard renders a compact login card for unauthenticated users 259 + templ WelcomeLoginCard() { 260 + <div class="card p-6 mb-8 max-w-md mx-auto"> 261 + <h2 class="text-lg font-semibold text-brown-900 mb-4 text-center">Log in to get started</h2> 262 + <form method="POST" action="/auth/login"> 267 263 <div class="relative"> 268 - <label for="handle" class="block text-sm font-medium text-brown-900 mb-2">Handle</label> 269 264 <input 270 265 type="text" 271 266 id="handle" 272 267 name="handle" 273 - placeholder="alice.bsky.social" 268 + placeholder="your-handle.bsky.social" 274 269 autocomplete="off" 275 270 required 276 - class="w-full px-4 py-3 border border-brown-300 rounded-lg focus:ring-2 focus:ring-brown-600 focus:border-brown-600 bg-white" 271 + class="w-full form-input-lg" 277 272 /> 278 273 <div id="autocomplete-results" class="hidden handle-dropdown"></div> 279 274 </div> 280 275 <button 281 276 type="submit" 282 - class="btn-primary w-full mt-4 py-3 px-8 text-lg font-semibold" 277 + class="btn-primary w-full mt-3 py-3 px-8 font-semibold" 283 278 > 284 279 Log In 285 280 </button> 286 281 </form> 282 + <div class="mt-4 text-sm text-brown-600 text-center"> 283 + <a href="/join/create" class="font-medium text-brown-800 hover:text-brown-900 transition-colors hover:underline">Create an account</a> 284 + <span class="mx-1.5 text-brown-400">&middot;</span> 285 + <a href="/about" class="text-brown-600 hover:text-brown-800 transition-colors hover:underline">Learn more</a> 286 + </div> 287 + <details class="mt-4"> 288 + <summary class="text-brown-500 text-sm cursor-pointer hover:text-brown-700 transition-colors text-center">What's an Atmosphere account?</summary> 289 + <p class="text-brown-600 mt-2 text-sm leading-relaxed"> 290 + Arabica uses the <a href="/atproto" class="link">AT Protocol</a> { "for" } social features and data ownership. Your account works across compatible apps like <a href="https://bsky.app" class="link" target="_blank" rel="noopener noreferrer">Bluesky</a> and <a href="https://leaflet.pub" class="link" target="_blank" rel="noopener noreferrer">Leaflet</a>. 291 + </p> 292 + </details> 287 293 <script src="/static/js/handle-autocomplete.js?v=0.2.0"></script> 288 294 </div> 289 295 } 290 296 291 297 templ AboutInfoCard() { 292 - // TODO: only show this at the bottom of the page when authenticated already? 293 298 <div class="card p-6 mb-6"> 294 299 <h3 class="text-lg font-bold text-brown-900 mb-3">About Arabica</h3> 295 300 <ul class="text-brown-800 space-y-2 leading-relaxed mb-3"> ··· 299 304 <li><strong>Portable:</strong> Own your coffee brewing history</li> 300 305 <li><strong>Decentralized:</strong> Your data lives in your Personal Data Server (PDS)</li> 301 306 </ul> 302 - // TODO: include a link to the about page here somewhere 303 - // <div class="text-large text-brown-900"><a href="/about" class="text-brown-700 hover:text-brown-900 transition-colors">Learn more</a></div> 307 + <a href="/about" class="text-sm text-brown-700 hover:text-brown-900 transition-colors hover:underline">Learn more</a> 304 308 </div> 305 309 } 306 310
+7 -9
internal/web/pages/home.templ
··· 13 13 14 14 templ HomeContent(props HomeProps) { 15 15 <div class="page-container-lg"> 16 - @components.WelcomeCard(components.WelcomeCardProps{ 17 - IsAuthenticated: props.IsAuthenticated, 18 - UserDID: props.UserDID, 19 - }) 20 16 if props.IsAuthenticated { 17 + @components.WelcomeCard(components.WelcomeCardProps{ 18 + IsAuthenticated: props.IsAuthenticated, 19 + UserDID: props.UserDID, 20 + }) 21 21 <!-- Incomplete records loaded async --> 22 22 <div id="incomplete-records-section" hx-get="/api/incomplete-records" hx-trigger="load, refreshManage from:body" hx-swap="innerHTML"></div> 23 23 <!-- Modal container for entity edit dialogs opened from dashboard --> 24 24 <div id="modal-container"></div> 25 - } 26 - if !props.IsAuthenticated { 27 - @components.AboutInfoCard() 28 - } 29 - if props.IsAuthenticated { 30 25 <!-- Popular recipes loaded async --> 31 26 <div hx-get="/api/popular-recipes" hx-trigger="load" hx-swap="innerHTML"></div> 27 + } else { 28 + @components.WelcomeHero() 29 + @components.WelcomeLoginCard() 32 30 } 33 31 @CommunityFeedSection(props.IsAuthenticated) 34 32 if props.IsAuthenticated {