extremely claude-assisted go game based on atproto! working on cleaning up and giving a more unique design, still has a bit of a slop vibe to it.
at list 152 lines 3.4 kB view raw
1<script lang="ts"> 2 import { onMount } from 'svelte'; 3 import { fetchUserProfile, type UserProfile } from '$lib/atproto-client'; 4 import ProfileDropdown from './ProfileDropdown.svelte'; 5 6 type Session = { did: string } | null; 7 8 let { session }: { session: Session } = $props(); 9 10 let userProfile: UserProfile | null = $state(null); 11 12 onMount(async () => { 13 if (session) { 14 userProfile = await fetchUserProfile(session.did); 15 } 16 }); 17</script> 18 19<div class="header-wrapper"> 20 <header class="header"> 21 <div class="header-content"> 22 <a href="/" class="logo">☁️ Cloud Go ☁️</a> 23 24 <div class="header-right"> 25 {#if session && userProfile} 26 <ProfileDropdown 27 avatar={userProfile.avatar || null} 28 handle={userProfile.handle} 29 did={session.did} 30 /> 31 {:else if session} 32 <!-- Loading profile --> 33 <div class="avatar-placeholder"></div> 34 {:else} 35 <a href="/" class="login-link">Login</a> 36 {/if} 37 </div> 38 </div> 39 </header> 40</div> 41 42<style> 43 .header-wrapper { 44 max-width: 1200px; 45 margin: clamp(1rem, 3vw, 2rem) auto clamp(1.5rem, 4vw, 3rem); 46 padding: 0 clamp(1rem, 3vw, 2rem); 47 } 48 49 .header { 50 background: linear-gradient( 51 135deg, 52 rgba(255, 255, 255, 0.95) 0%, 53 rgba(245, 248, 250, 0.9) 50%, 54 rgba(232, 239, 244, 0.85) 100% 55 ); 56 border: none; 57 border-radius: 2rem 2.5rem 2rem 2.2rem; 58 box-shadow: 59 0 0 20px rgba(255, 255, 255, 0.8), 60 0 0 40px rgba(255, 255, 255, 0.4), 61 0 8px 32px rgba(90, 122, 144, 0.12), 62 inset 0 1px 1px rgba(255, 255, 255, 0.9); 63 backdrop-filter: blur(8px); 64 position: relative; 65 z-index: 100; 66 } 67 68 .header::before { 69 content: ''; 70 position: absolute; 71 inset: -2px; 72 border-radius: inherit; 73 background: linear-gradient( 74 135deg, 75 rgba(255, 255, 255, 0.6) 0%, 76 rgba(212, 229, 239, 0.3) 50%, 77 rgba(255, 255, 255, 0.4) 100% 78 ); 79 filter: blur(4px); 80 z-index: -1; 81 } 82 83 .header-content { 84 display: flex; 85 align-items: center; 86 justify-content: space-between; 87 padding: clamp(1rem, 2vw, 1.5rem) clamp(1.5rem, 3vw, 2.5rem); 88 max-width: 1200px; 89 margin: 0 auto; 90 } 91 92 .logo { 93 font-size: clamp(1.5rem, 4vw, 2.75rem); 94 font-weight: 700; 95 color: var(--sky-slate-dark); 96 text-decoration: none; 97 letter-spacing: -0.02em; 98 transition: color 0.6s ease, transform 0.6s ease; 99 } 100 101 .logo:hover { 102 color: var(--sky-apricot-dark); 103 filter: drop-shadow(0 0 8px rgba(229, 168, 120, 0.6)); 104 } 105 106 107 108 .header-right { 109 display: flex; 110 align-items: center; 111 } 112 113 .login-link { 114 color: var(--sky-slate); 115 text-decoration: none; 116 font-weight: 500; 117 font-size: clamp(1rem, 2vw, 1.125rem); 118 padding: 0.75rem 1.25rem; 119 border-radius: 0.5rem; 120 transition: all 0.6s ease; 121 } 122 123 .login-link:hover { 124 background: var(--sky-apricot-light); 125 color: var(--sky-apricot-dark); 126 box-shadow: 0 0 12px rgba(229, 168, 120, 0.5); 127 } 128 129 .avatar-placeholder { 130 width: 80px; 131 height: 80px; 132 border-radius: 50%; 133 background: var(--sky-cloud); 134 animation: pulse 1.5s ease-in-out infinite; 135 } 136 137 @keyframes pulse { 138 0%, 100% { 139 opacity: 0.6; 140 } 141 50% { 142 opacity: 1; 143 } 144 } 145 146 @media (max-width: 768px) { 147 .avatar-placeholder { 148 width: 60px; 149 height: 60px; 150 } 151 } 152</style>