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.
Something went wrong. Try again.
3.4 kB · 152 lines
Svelte
at list
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153<script lang="ts"> import { onMount } from 'svelte'; import { fetchUserProfile, type UserProfile } from '$lib/atproto-client'; import ProfileDropdown from './ProfileDropdown.svelte';
type Session = { did: string } | null;
let { session }: { session: Session } = $props();
let userProfile: UserProfile | null = $state(null);
onMount(async () => { if (session) { userProfile = await fetchUserProfile(session.did); } });</script>
<div class="header-wrapper"> <header class="header"> <div class="header-content"> <a href="/" class="logo">☁️ Cloud Go ☁️</a>
<div class="header-right"> {#if session && userProfile} <ProfileDropdown avatar={userProfile.avatar || null} handle={userProfile.handle} did={session.did} /> {:else if session} <!-- Loading profile --> <div class="avatar-placeholder"></div> {:else} <a href="/" class="login-link">Login</a> {/if} </div> </div> </header></div>
<style> .header-wrapper { max-width: 1200px; margin: clamp(1rem, 3vw, 2rem) auto clamp(1.5rem, 4vw, 3rem); padding: 0 clamp(1rem, 3vw, 2rem); }
.header { background: linear-gradient( 135deg, rgba(255, 255, 255, 0.95) 0%, rgba(245, 248, 250, 0.9) 50%, rgba(232, 239, 244, 0.85) 100% ); border: none; border-radius: 2rem 2.5rem 2rem 2.2rem; box-shadow: 0 0 20px rgba(255, 255, 255, 0.8), 0 0 40px rgba(255, 255, 255, 0.4), 0 8px 32px rgba(90, 122, 144, 0.12), inset 0 1px 1px rgba(255, 255, 255, 0.9); backdrop-filter: blur(8px); position: relative; z-index: 100; }
.header::before { content: ''; position: absolute; inset: -2px; border-radius: inherit; background: linear-gradient( 135deg, rgba(255, 255, 255, 0.6) 0%, rgba(212, 229, 239, 0.3) 50%, rgba(255, 255, 255, 0.4) 100% ); filter: blur(4px); z-index: -1; }
.header-content { display: flex; align-items: center; justify-content: space-between; padding: clamp(1rem, 2vw, 1.5rem) clamp(1.5rem, 3vw, 2.5rem); max-width: 1200px; margin: 0 auto; }
.logo { font-size: clamp(1.5rem, 4vw, 2.75rem); font-weight: 700; color: var(--sky-slate-dark); text-decoration: none; letter-spacing: -0.02em; transition: color 0.6s ease, transform 0.6s ease; }
.logo:hover { color: var(--sky-apricot-dark); filter: drop-shadow(0 0 8px rgba(229, 168, 120, 0.6)); }
.header-right { display: flex; align-items: center; }
.login-link { color: var(--sky-slate); text-decoration: none; font-weight: 500; font-size: clamp(1rem, 2vw, 1.125rem); padding: 0.75rem 1.25rem; border-radius: 0.5rem; transition: all 0.6s ease; }
.login-link:hover { background: var(--sky-apricot-light); color: var(--sky-apricot-dark); box-shadow: 0 0 12px rgba(229, 168, 120, 0.5); }
.avatar-placeholder { width: 80px; height: 80px; border-radius: 50%; background: var(--sky-cloud); animation: pulse 1.5s ease-in-out infinite; }
@keyframes pulse { 0%, 100% { opacity: 0.6; } 50% { opacity: 1; } }
@media (max-width: 768px) { .avatar-placeholder { width: 60px; height: 60px; } }</style>