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: login button in nav

authored by

Patrick Dewey and committed by
Tangled
74bbd0bd cd6db49f

+128 -57
+65
internal/web/components/header.templ
··· 33 33 </a> 34 34 <!-- Navigation links --> 35 35 <div class="flex items-center gap-4"> 36 + if !props.IsAuthenticated { 37 + <div class="flex items-center gap-4"> 38 + <button 39 + x-data 40 + @click="$dispatch('open-login')" 41 + class="text-sm font-semibold text-brown-100 hover:text-white transition-colors" 42 + > 43 + Log In 44 + </button> 45 + </div> 46 + } 36 47 if props.IsAuthenticated { 37 48 <!-- Notification bell --> 38 49 <a href="/notifications" class="relative hover:opacity-80 transition p-1" title="Notifications"> ··· 194 205 </div> 195 206 </div> 196 207 </nav> 208 + if !props.IsAuthenticated { 209 + @LoginModal() 210 + } 211 + } 212 + 213 + // LoginModal renders the login dialog for unauthenticated users 214 + templ LoginModal() { 215 + <dialog id="login-modal" class="modal-dialog" x-data @open-login.window="$el.showModal()"> 216 + <div class="modal-content"> 217 + <div class="flex items-center justify-between mb-4"> 218 + <h3 class="modal-title mb-0">Log in with your Atmosphere account</h3> 219 + <button 220 + type="button" 221 + @click="$el.closest('dialog').close()" 222 + class="text-brown-400 hover:text-brown-600 transition-colors" 223 + > 224 + @IconX() 225 + </button> 226 + </div> 227 + <form method="POST" action="/auth/login" class="space-y-4"> 228 + <div class="relative"> 229 + <label { "for" }="login-handle" class="block text-sm font-medium text-brown-900 mb-2">Handle</label> 230 + <input 231 + type="text" 232 + id="login-handle" 233 + name="handle" 234 + placeholder="your-handle.bsky.social" 235 + autocomplete="off" 236 + required 237 + class="w-full form-input-lg" 238 + /> 239 + <div id="autocomplete-results" class="hidden handle-dropdown"></div> 240 + </div> 241 + <button 242 + type="submit" 243 + class="btn-primary w-full py-3 font-semibold" 244 + > 245 + Log In 246 + </button> 247 + </form> 248 + <div class="mt-4 text-sm text-brown-600 text-center"> 249 + <a href="/join/create" class="font-medium text-brown-800 hover:text-brown-900 transition-colors hover:underline">Create an account</a> 250 + <span class="mx-1.5 text-brown-400">&middot;</span> 251 + <a href="/about" class="text-brown-600 hover:text-brown-800 transition-colors hover:underline">Learn more</a> 252 + </div> 253 + <details class="mt-4"> 254 + <summary class="text-brown-500 text-sm cursor-pointer hover:text-brown-700 transition-colors">What's an Atmosphere account?</summary> 255 + <p class="text-brown-600 mt-2 text-sm leading-relaxed"> 256 + One account { "for" } the entire <a href="/atproto" class="link">AT Protocol</a> ecosystem. Sign up once and use it across Arabica, <a href="https://bsky.app" class="link" target="_blank" rel="noopener noreferrer">Bluesky</a>, <a href="https://leaflet.pub" class="link" target="_blank" rel="noopener noreferrer">Leaflet</a>, and more. Your data is portable — you own it. 257 + </p> 258 + </details> 259 + <script src="/static/js/handle-autocomplete.js?v=0.2.0"></script> 260 + </div> 261 + </dialog> 197 262 } 198 263 199 264 // Helper function to get profile identifier (handle or DID)
+1 -1
internal/web/components/shared.templ
··· 287 287 <details class="mt-4"> 288 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 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>. 290 + One account { "for" } the entire <a href="/atproto" class="link">AT Protocol</a> ecosystem. Sign up once and use it across Arabica, <a href="https://bsky.app" class="link" target="_blank" rel="noopener noreferrer">Bluesky</a>, <a href="https://leaflet.pub" class="link" target="_blank" rel="noopener noreferrer">Leaflet</a>, and more. Your data is portable — you own it. 291 291 </p> 292 292 </details> 293 293 <script src="/static/js/handle-autocomplete.js?v=0.2.0"></script>
+1 -1
internal/web/pages/brew_form.templ
··· 1 1 package pages 2 2 3 3 import ( 4 + "fmt" 4 5 "tangled.org/arabica.social/arabica/internal/models" 5 6 "tangled.org/arabica.social/arabica/internal/web/components" 6 - "fmt" 7 7 ) 8 8 9 9 type BrewFormProps struct {
+58 -53
internal/web/pages/create_account.templ
··· 12 12 @components.Layout(layout, CreateAccountContent(props)) 13 13 } 14 14 15 - // CreateAccountContent renders the PDS server selection for account creation. 15 + // CreateAccountContent renders the Atmosphere account creation page. 16 16 templ CreateAccountContent(props CreateAccountProps) { 17 17 <div class="page-container-md"> 18 18 <div class="flex items-center gap-3 mb-8"> 19 19 @components.BackButton() 20 - <h1 class="text-4xl font-bold text-brown-900">Create Account</h1> 20 + <h1 class="text-4xl font-bold text-brown-900">Create an Atmosphere Account</h1> 21 21 </div> 22 - <p class="text-brown-800 leading-relaxed mb-6"> 23 - Create an account on a Personal Data Server (PDS) to start tracking your brews. 24 - Your data is stored on the server you choose and is portable — you can move it later. 22 + <p class="text-brown-800 leading-relaxed mb-2"> 23 + An Atmosphere account is your passport to Arabica and the wider <a href="/atproto" class="link-bold">AT Protocol</a> ecosystem. 24 + One account works across every compatible app — no more creating new logins. 25 + </p> 26 + <p class="text-sm text-brown-600 mb-6"> 27 + Choose a provider below. Your data is portable — you can move to a different provider at any time. 25 28 </p> 26 29 if props.Error != "" { 27 30 <div class="mb-6 rounded-lg border border-red-300 bg-red-50 p-4 text-red-800 text-sm"> 28 31 { props.Error } 29 32 </div> 30 33 } 31 - <div class="space-y-4"> 32 - @pdsCard("https://arabica.systems") { 33 - <p class="flex items-baseline gap-2 text-lg font-semibold text-brown-900"> 34 - Arabica 35 - <span class="relative -top-px inline-flex items-center rounded-full bg-amber-100 px-2 py-0.5 text-xs font-medium text-amber-800"> 36 - Invite Only 37 - </span> 38 - </p> 39 - <p class="text-sm text-brown-700">The official Arabica PDS.</p> 40 - <p class="flex items-center gap-1 text-xs text-brown-500"> 41 - arabica.systems · 42 - @locationPin() 43 - United States 44 - </p> 45 - } 46 - @pdsCard("https://selfhosted.social") { 47 - <p class="flex items-baseline gap-2 text-lg font-semibold text-brown-900"> 48 - selfhosted.social 49 - <span class="relative -top-px inline-flex items-center rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800"> 50 - Open 51 - </span> 52 - </p> 53 - <p class="text-sm text-brown-700"> 54 - Indie PDS hosted by 55 - <a href="https://bsky.app/profile/baileytownsend.dev" target="_blank" rel="noopener noreferrer" class="link-bold">{ "@baileytownsend.dev" }</a>. 56 - </p> 57 - <p class="flex items-center gap-1 text-xs text-brown-500"> 58 - selfhosted.social · 59 - @locationPin() 60 - United States 61 - </p> 62 - } 63 - // @pdsCard("https://bsky.app") { 64 - // <p class="flex items-baseline gap-2 text-lg font-semibold text-brown-900"> 65 - // Bluesky 66 - // <span class="relative -top-px inline-flex items-center rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800"> 67 - // Open 68 - // </span> 69 - // </p> 70 - // <p class="text-sm text-brown-700">Maintained by Bluesky PBC.</p> 71 - // <p class="flex items-center gap-1 text-xs text-brown-500"> 72 - // bsky.social · 73 - // @locationPin() 74 - // United States 75 - // </p> 76 - // } 34 + <!-- App providers --> 35 + <div class="mb-6"> 36 + <h2 class="text-sm font-medium text-brown-600 uppercase tracking-wider mb-3">App Providers</h2> 37 + <p class="text-sm text-brown-500 mb-3">These apps host your account and data { "for" } you.</p> 38 + <div class="space-y-3"> 39 + @pdsCard("https://arabica.systems") { 40 + <p class="flex items-baseline gap-2 text-lg font-semibold text-brown-900"> 41 + Arabica 42 + <span class="relative -top-px inline-flex items-center rounded-full bg-amber-100 px-2 py-0.5 text-xs font-medium text-amber-800"> 43 + Invite Only 44 + </span> 45 + </p> 46 + <p class="text-sm text-brown-700">The official Arabica provider.</p> 47 + <p class="flex items-center gap-1 text-xs text-brown-500"> 48 + arabica.systems · 49 + @locationPin() 50 + United States 51 + </p> 52 + } 53 + </div> 54 + </div> 55 + <!-- Independent providers --> 56 + <div class="mb-6"> 57 + <h2 class="text-sm font-medium text-brown-600 uppercase tracking-wider mb-3">Independent Providers</h2> 58 + <p class="text-sm text-brown-500 mb-3">Account hosts run by the community. They hold your account and data, independent of any single app.</p> 59 + <div class="space-y-3"> 60 + @pdsCard("https://selfhosted.social") { 61 + <p class="flex items-baseline gap-2 text-lg font-semibold text-brown-900"> 62 + selfhosted.social 63 + <span class="relative -top-px inline-flex items-center rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-800"> 64 + Open 65 + </span> 66 + </p> 67 + <p class="text-sm text-brown-700"> 68 + Community provider hosted by 69 + <a href="https://bsky.app/profile/baileytownsend.dev" target="_blank" rel="noopener noreferrer" class="link-bold">{ "@baileytownsend.dev" }</a>. 70 + </p> 71 + <p class="flex items-center gap-1 text-xs text-brown-500"> 72 + selfhosted.social · 73 + @locationPin() 74 + United States 75 + </p> 76 + } 77 + </div> 78 + </div> 79 + <!-- Self-hosted note --> 80 + <div class="text-sm text-brown-500 mb-6"> 81 + <strong class="text-brown-700">Self-hosted:</strong> Technical users can <a href="https://atproto.com/guides/self-hosting" target="_blank" rel="noopener noreferrer" class="link">run their own provider</a> { "for" } full control over their data. 77 82 </div> 78 - <p class="text-sm text-brown-600 mt-6 text-center"> 79 - Already have an account? 83 + <p class="text-sm text-brown-600 text-center"> 84 + Already have an Atmosphere account? 80 85 <a href="/login" class="link-bold">Log in here</a>. 81 86 </p> 82 87 </div>
-1
internal/web/pages/home.templ
··· 26 26 <div hx-get="/api/popular-recipes" hx-trigger="load" hx-swap="innerHTML"></div> 27 27 } else { 28 28 @components.WelcomeHero() 29 - @components.WelcomeLoginCard() 30 29 } 31 30 @CommunityFeedSection(props.IsAuthenticated) 32 31 if props.IsAuthenticated {
+3 -1
static/js/handle-autocomplete.js
··· 3 3 * Provides typeahead search for Bluesky handles 4 4 */ 5 5 (function () { 6 - const input = document.getElementById("handle"); 6 + const input = 7 + document.getElementById("login-handle") || 8 + document.getElementById("handle"); 7 9 const results = document.getElementById("autocomplete-results"); 8 10 9 11 // Exit early if elements don't exist (user might be authenticated)