Skip to content

Commit 7e9794b

Browse files
JacobCoffeeclaude
andcommitted
feat: dynamic navbar auth status with profile dropdown
- Added HTMX-loaded auth status in navbar - Shows avatar/dropdown when logged in - Shows guest indicator for guests - Shows login button when not authenticated - Profile page already exists with full stats 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent e1ea977 commit 7e9794b

File tree

3 files changed

+113
-7
lines changed

3 files changed

+113
-7
lines changed

src/scribbl_py/auth/controller.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,41 @@ async def profile_page(
317317
},
318318
)
319319

320+
@get("/navbar")
321+
async def navbar_auth_status(
322+
self,
323+
request: Request,
324+
auth_service: AuthService,
325+
) -> Template:
326+
"""Return navbar auth status partial.
327+
328+
Args:
329+
request: The request object.
330+
auth_service: Auth service instance.
331+
332+
Returns:
333+
Navbar partial template.
334+
"""
335+
session_id = request.cookies.get(auth_service._config.session_cookie_name)
336+
user = None
337+
guest_name = None
338+
339+
if session_id:
340+
session = auth_service.get_session(session_id)
341+
if session:
342+
if session.user_id:
343+
user = auth_service.get_user(session.user_id)
344+
elif session.guest_name:
345+
guest_name = session.guest_name
346+
347+
return Template(
348+
template_name="auth/navbar.html",
349+
context={
350+
"user": user,
351+
"guest_name": guest_name,
352+
},
353+
)
354+
320355
@get("/leaderboard")
321356
async def leaderboard_page(
322357
self,
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
{% if user %}
2+
<!-- Logged in user -->
3+
<div class="dropdown dropdown-end">
4+
<div tabindex="0" role="button" class="btn btn-ghost btn-circle avatar">
5+
{% if user.avatar_url %}
6+
<div class="w-10 rounded-full">
7+
<img alt="{{ user.username }}" src="{{ user.avatar_url }}" />
8+
</div>
9+
{% else %}
10+
<div class="avatar placeholder">
11+
<div class="bg-primary text-primary-content rounded-full w-10">
12+
<span class="text-lg">{{ user.username[0] | upper }}</span>
13+
</div>
14+
</div>
15+
{% endif %}
16+
</div>
17+
<ul tabindex="0" class="menu menu-sm dropdown-content bg-base-100 rounded-box z-[1] mt-3 w-52 p-2 shadow">
18+
<li class="menu-title">
19+
<span>{{ user.username }}</span>
20+
</li>
21+
<li><a href="/auth/profile" hx-boost="false">
22+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
23+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
24+
</svg>
25+
Profile
26+
</a></li>
27+
<li><a href="/auth/leaderboard" hx-boost="false">
28+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
29+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
30+
</svg>
31+
Leaderboard
32+
</a></li>
33+
<div class="divider my-0"></div>
34+
<li><a href="/auth/logout" hx-boost="false" class="text-error">
35+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
36+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
37+
</svg>
38+
Logout
39+
</a></li>
40+
</ul>
41+
</div>
42+
{% elif guest_name %}
43+
<!-- Guest user -->
44+
<div class="dropdown dropdown-end">
45+
<div tabindex="0" role="button" class="btn btn-ghost btn-sm gap-2">
46+
<div class="avatar placeholder">
47+
<div class="bg-neutral text-neutral-content rounded-full w-8">
48+
<span class="text-sm">G</span>
49+
</div>
50+
</div>
51+
<span class="hidden sm:inline">{{ guest_name }}</span>
52+
</div>
53+
<ul tabindex="0" class="menu menu-sm dropdown-content bg-base-100 rounded-box z-[1] mt-3 w-52 p-2 shadow">
54+
<li class="menu-title">
55+
<span>Playing as Guest</span>
56+
</li>
57+
<li><a href="/auth/login" hx-boost="false">
58+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
59+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1"/>
60+
</svg>
61+
Sign in to save stats
62+
</a></li>
63+
</ul>
64+
</div>
65+
{% else %}
66+
<!-- Not logged in -->
67+
<a href="/auth/login" class="btn btn-primary btn-sm" hx-boost="false">
68+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
69+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1"/>
70+
</svg>
71+
Login
72+
</a>
73+
{% endif %}

src/scribbl_py/templates/base.html

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,11 @@
6363
</svg>
6464
</button>
6565

66-
<!-- Login -->
67-
<a href="/auth/login" class="btn btn-primary btn-sm ml-2" hx-boost="false">
68-
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
69-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1"/>
70-
</svg>
71-
Login
72-
</a>
66+
<!-- Auth Status (loaded via HTMX) -->
67+
<div id="auth-status" class="ml-2" hx-get="/auth/navbar" hx-trigger="load" hx-swap="innerHTML">
68+
<!-- Loading placeholder -->
69+
<span class="loading loading-spinner loading-sm"></span>
70+
</div>
7371
</div>
7472
</div>
7573

0 commit comments

Comments
 (0)