Spaces:
Running
Running
| <script lang="ts"> | |
| import { onMount } from 'svelte'; | |
| import { authStore } from '../../services/auth'; | |
| import gsap from 'gsap'; | |
| let authState = { | |
| isAuthenticated: false, | |
| user: null as any, | |
| loading: true, | |
| error: null as string | null | |
| }; | |
| let loginBtn: HTMLButtonElement; | |
| authStore.subscribe(state => { | |
| authState = state; | |
| }); | |
| onMount(async () => { | |
| await authStore.init(); | |
| if (loginBtn && !authState.isAuthenticated) { | |
| gsap.to(loginBtn, { | |
| boxShadow: '0 0 20px rgba(255, 255, 255, 0.15)', | |
| duration: 2, | |
| repeat: -1, | |
| yoyo: true, | |
| ease: 'sine.inOut' | |
| }); | |
| } | |
| }); | |
| $: if (loginBtn && !authState.isAuthenticated && !authState.loading) { | |
| gsap.to(loginBtn, { | |
| boxShadow: '0 0 20px rgba(255, 255, 255, 0.15)', | |
| duration: 2, | |
| repeat: -1, | |
| yoyo: true, | |
| ease: 'sine.inOut' | |
| }); | |
| } | |
| function handleLogin() { | |
| authStore.login(); | |
| } | |
| function handleLogout() { | |
| authStore.logout(); | |
| } | |
| </script> | |
| <div class="auth-container"> | |
| {#if authState.loading} | |
| <div class="loading">Loading...</div> | |
| {:else if authState.error} | |
| <div class="error"> | |
| <span>{authState.error}</span> | |
| <button on:click={handleLogin} class="retry-btn">Try Again</button> | |
| </div> | |
| {:else if authState.isAuthenticated} | |
| <div class="user-info"> | |
| {#if authState.user?.avatarUrl} | |
| <img src={authState.user.avatarUrl} alt={authState.user.name} class="avatar" /> | |
| {/if} | |
| <span class="username">{authState.user?.name || 'User'}</span> | |
| <button on:click={handleLogout} class="logout-btn">Logout</button> | |
| </div> | |
| {:else} | |
| <button bind:this={loginBtn} on:click={handleLogin} class="login-btn"> | |
| Sign in | |
| </button> | |
| {/if} | |
| </div> | |
| <style> | |
| .auth-container { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .loading { | |
| color: #888; | |
| font-size: 0.875rem; | |
| } | |
| .error { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| color: #ff6b6b; | |
| font-size: 0.875rem; | |
| } | |
| .retry-btn { | |
| padding: 0.25rem 0.5rem; | |
| background: #ff6b6b; | |
| color: white; | |
| border: none; | |
| border-radius: 0.25rem; | |
| cursor: pointer; | |
| font-size: 0.75rem; | |
| } | |
| .retry-btn:hover { | |
| background: #ff5252; | |
| } | |
| .user-info { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .avatar { | |
| width: 24px; | |
| height: 24px; | |
| border-radius: 50%; | |
| } | |
| .username { | |
| color: #ccc; | |
| font-size: 0.875rem; | |
| } | |
| .logout-btn { | |
| padding: 0.25rem 0.5rem; | |
| background: transparent; | |
| color: #888; | |
| border: 1px solid #333; | |
| border-radius: 0.25rem; | |
| cursor: pointer; | |
| font-size: 0.75rem; | |
| transition: all 0.2s; | |
| } | |
| .logout-btn:hover { | |
| background: #333; | |
| color: #fff; | |
| } | |
| .login-btn { | |
| padding: 0.35rem 0.85rem; | |
| background: rgba(255, 255, 255, 0.03); | |
| color: rgba(255, 255, 255, 0.7); | |
| border: 1px solid rgba(255, 255, 255, 0.08); | |
| border-radius: 0.35rem; | |
| cursor: pointer; | |
| font-size: 0.75rem; | |
| font-weight: 500; | |
| transition: all 0.3s ease; | |
| backdrop-filter: blur(10px); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .login-btn:hover { | |
| background: rgba(255, 255, 255, 0.08); | |
| color: rgba(255, 255, 255, 0.95); | |
| border-color: rgba(255, 255, 255, 0.15); | |
| transform: translateY(-1px); | |
| } | |
| .login-btn:active { | |
| transform: translateY(0); | |
| } | |
| </style> |