|
59 | 59 |
|
60 | 60 | .logo { font-weight: 700; font-size: 1.25rem; color: var(--primary); } |
61 | 61 | .logo:hover { text-decoration: none; color: var(--primary-light); } |
| 62 | + .logo .teams-badge { |
| 63 | + font-size: 0.625rem; |
| 64 | + color: var(--gray-500); |
| 65 | + margin-left: 0.25rem; |
| 66 | + vertical-align: super; |
| 67 | + text-transform: uppercase; |
| 68 | + letter-spacing: 0.05em; |
| 69 | + } |
62 | 70 |
|
63 | 71 | nav { display: flex; gap: 1.5rem; flex: 1; } |
64 | 72 | nav a { color: var(--gray-300); transition: color 0.15s; } |
|
263 | 271 | /* Fade transition for HTMX swaps */ |
264 | 272 | .htmx-swapping { opacity: 0; transition: opacity 0.1s ease-out; } |
265 | 273 |
|
266 | | - /* User menu (Teams) */ |
| 274 | + /* User menu (for Teams integration) */ |
267 | 275 | .user-menu { |
268 | 276 | position: relative; |
269 | 277 | } |
|
276 | 284 | border-radius: 6px; |
277 | 285 | cursor: pointer; |
278 | 286 | color: var(--gray-300); |
| 287 | + background: none; |
| 288 | + border: none; |
279 | 289 | transition: background-color 0.15s; |
280 | 290 | } |
281 | 291 |
|
|
297 | 307 | color: white; |
298 | 308 | } |
299 | 309 |
|
| 310 | + .user-name { |
| 311 | + font-size: 0.875rem; |
| 312 | + max-width: 120px; |
| 313 | + overflow: hidden; |
| 314 | + text-overflow: ellipsis; |
| 315 | + white-space: nowrap; |
| 316 | + } |
| 317 | + |
300 | 318 | .user-menu-dropdown { |
301 | 319 | position: absolute; |
302 | 320 | top: 100%; |
|
308 | 326 | min-width: 200px; |
309 | 327 | z-index: 1000; |
310 | 328 | display: none; |
| 329 | + overflow: hidden; |
311 | 330 | } |
312 | 331 |
|
313 | 332 | .user-menu-dropdown.open { display: block; } |
314 | 333 |
|
315 | | - .user-menu-dropdown a { |
316 | | - display: block; |
| 334 | + .user-menu-dropdown .user-info { |
317 | 335 | padding: 0.75rem 1rem; |
| 336 | + border-bottom: 1px solid var(--gray-200); |
| 337 | + } |
| 338 | + |
| 339 | + .user-menu-dropdown .user-info-name { |
| 340 | + font-weight: 500; |
| 341 | + color: var(--gray-900); |
| 342 | + } |
| 343 | + |
| 344 | + .user-menu-dropdown .user-info-email { |
| 345 | + font-size: 0.8125rem; |
| 346 | + color: var(--gray-500); |
| 347 | + } |
| 348 | + |
| 349 | + .user-menu-dropdown a, |
| 350 | + .user-menu-dropdown button.menu-item { |
| 351 | + display: block; |
| 352 | + width: 100%; |
| 353 | + padding: 0.625rem 1rem; |
318 | 354 | color: var(--gray-700); |
319 | | - border-bottom: 1px solid var(--gray-100); |
| 355 | + background: none; |
| 356 | + border: none; |
| 357 | + text-align: left; |
| 358 | + font-size: 0.875rem; |
| 359 | + cursor: pointer; |
| 360 | + text-decoration: none; |
320 | 361 | } |
321 | 362 |
|
322 | | - .user-menu-dropdown a:hover { |
| 363 | + .user-menu-dropdown a:hover, |
| 364 | + .user-menu-dropdown button.menu-item:hover { |
323 | 365 | background: var(--gray-50); |
324 | 366 | text-decoration: none; |
325 | 367 | } |
326 | 368 |
|
327 | | - .user-menu-dropdown a:last-child { border-bottom: none; } |
| 369 | + .user-menu-dropdown .menu-divider { |
| 370 | + height: 1px; |
| 371 | + background: var(--gray-200); |
| 372 | + margin: 0; |
| 373 | + } |
| 374 | + |
| 375 | + .user-menu-dropdown .danger { |
| 376 | + color: var(--danger); |
| 377 | + } |
328 | 378 |
|
329 | 379 | /* Alert messages */ |
330 | 380 | .alert { |
|
345 | 395 | <header> |
346 | 396 | <div class="container"> |
347 | 397 | {% block logo %} |
348 | | - <a href="/" class="logo">⚛ devqubit</a> |
| 398 | + <a href="/" class="logo">⚛ devqubit{% if current_user %}<span class="teams-badge">teams</span>{% endif %}</a> |
349 | 399 | {% endblock %} |
350 | 400 |
|
351 | 401 | <nav> |
352 | 402 | {% block nav_start %}{% endblock %} |
353 | | - <a href="/runs" class="{% if request.url.path == '/runs' %}active{% endif %}">Runs</a> |
354 | | - <a href="/projects" class="{% if request.url.path == '/projects' %}active{% endif %}">Projects</a> |
355 | | - <a href="/groups" class="{% if request.url.path == '/groups' %}active{% endif %}">Groups</a> |
| 403 | + <a href="/runs" class="{% if request.url.path == '/runs' or request.url.path.startswith('/runs/') %}active{% endif %}">Runs</a> |
| 404 | + <a href="/projects" class="{% if request.url.path == '/projects' or request.url.path.startswith('/projects/') %}active{% endif %}">Projects</a> |
| 405 | + <a href="/groups" class="{% if request.url.path == '/groups' or request.url.path.startswith('/groups/') %}active{% endif %}">Groups</a> |
356 | 406 | <a href="/diff" class="{% if request.url.path == '/diff' %}active{% endif %}">Compare</a> |
357 | 407 | <a href="/search" class="{% if request.url.path == '/search' %}active{% endif %}">Search</a> |
358 | 408 | {% block nav_items %}{% endblock %} |
359 | 409 | </nav> |
360 | 410 |
|
361 | 411 | <div class="nav-right"> |
362 | 412 | {% block nav_right %} |
363 | | - {# Teams overrides this block to show user menu #} |
| 413 | + {# Teams user menu - shown when current_user is available #} |
| 414 | + {% if current_user %} |
| 415 | + <div class="user-menu" id="userMenu"> |
| 416 | + <button class="user-menu-toggle" onclick="document.getElementById('userMenuDropdown').classList.toggle('open')"> |
| 417 | + <div class="user-avatar">{{ (current_user.name or current_user.email)[:2] | upper }}</div> |
| 418 | + <span class="user-name">{{ current_user.name or current_user.email.split('@')[0] }}</span> |
| 419 | + </button> |
| 420 | + <div class="user-menu-dropdown" id="userMenuDropdown"> |
| 421 | + <div class="user-info"> |
| 422 | + <div class="user-info-name">{{ current_user.name or 'User' }}</div> |
| 423 | + <div class="user-info-email">{{ current_user.email }}</div> |
| 424 | + </div> |
| 425 | + <a href="/settings/tokens">API Tokens</a> |
| 426 | + <a href="/settings/profile">Profile</a> |
| 427 | + {% if current_user.is_admin %} |
| 428 | + <a href="/admin">Admin</a> |
| 429 | + {% endif %} |
| 430 | + <div class="menu-divider"></div> |
| 431 | + <form action="/auth/logout" method="post" style="margin: 0;"> |
| 432 | + <button type="submit" class="menu-item danger">Sign Out</button> |
| 433 | + </form> |
| 434 | + </div> |
| 435 | + </div> |
| 436 | + {% endif %} |
364 | 437 | {% endblock %} |
365 | 438 | </div> |
366 | 439 | </div> |
|
378 | 451 |
|
379 | 452 | {% block footer %}{% endblock %} |
380 | 453 |
|
381 | | - {% block scripts %}{% endblock %} |
| 454 | + {% block scripts %} |
| 455 | + <script> |
| 456 | + // Close user menu when clicking outside |
| 457 | + document.addEventListener('click', function(e) { |
| 458 | + var menu = document.getElementById('userMenu'); |
| 459 | + var dropdown = document.getElementById('userMenuDropdown'); |
| 460 | + if (menu && dropdown && !menu.contains(e.target)) { |
| 461 | + dropdown.classList.remove('open'); |
| 462 | + } |
| 463 | + }); |
| 464 | + </script> |
| 465 | + {% endblock %} |
382 | 466 | </body> |
383 | 467 | </html> |
0 commit comments