Something went wrong. Try again.
Website hub for the atmosphere community, aggregating posts, events, regional, and more
Something went wrong. Try again.
6.0 kB · 263 lines
Astro
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264---import AuthMenu from '../auth/AuthMenu.astro';
const navLinks = [ { href: '/', label: 'Home' }, { href: '/about', label: 'About' }, { href: '/community-content', label: 'Content' }, { href: '/events', label: 'Events' }, { href: '/communities', label: 'Communities' },];
const currentPath = Astro.url.pathname;const authErrorCode = Astro.locals.authproto?.errorCode;const authErrorDescription = Astro.locals.authproto?.errorDescription;const authError = authErrorDescription ?? authErrorCode;
const isActive = (href: string) => currentPath === href || (href !== '/' && currentPath.startsWith(href));---
<header class="site-header"> <nav class="site-nav container" aria-label="Main navigation"> <a href="/" class="site-logo" aria-label="atmosphere.community home"> <span class="logo-cloud" aria-hidden="true"></span> <span class="logo-text"><span class="logo-at">@</span>atmosphere community</span> </a>
<input type="checkbox" id="nav-toggle" class="nav-toggle visually-hidden" aria-hidden="true" /> <label for="nav-toggle" class="nav-toggle-label" aria-label="Toggle navigation menu"> <span class="hamburger" aria-hidden="true"></span> </label>
<ul class="nav-links" role="list"> {navLinks.map(link => ( <li> <a href={link.href} class:list={['nav-link', { 'nav-link--active': isActive(link.href) }]} aria-current={currentPath === link.href ? 'page' : undefined} > {link.label} </a> </li> ))} </ul>
<AuthMenu /> </nav> { authError && ( <div class="auth-alert-wrap"> <div class="auth-alert container" role="alert"> <strong>Sign-in failed</strong> <span>{authError}</span> {authErrorCode && authErrorCode !== authError && ( <code>{authErrorCode}</code> )} </div> </div> ) }</header>
<style> .site-header { position: sticky; top: 0; z-index: var(--z-header); background: var(--header-bg); border-bottom: 1px solid var(--header-border); }
.auth-alert-wrap { border-top: 1px solid var(--error); background: color-mix(in oklch, var(--error) 10%, var(--background)); }
.site-header:has(.auth-menu[open]) .auth-alert-wrap { display: none; }
.auth-alert { display: flex; align-items: center; gap: var(--space-sm); padding-block: var(--space-sm); color: var(--foreground); font-size: var(--text-sm); line-height: var(--leading-normal); }
.auth-alert strong { flex: 0 0 auto; color: var(--error); }
.auth-alert span { min-width: 0; overflow-wrap: anywhere; }
.auth-alert code { flex: 0 0 auto; border: 1px solid color-mix(in oklch, var(--error) 35%, transparent); border-radius: var(--radius-sm); padding: 1px var(--space-xs); color: var(--error); font-size: var(--text-xs); }
.site-nav { display: flex; align-items: center; gap: var(--space-lg); height: 56px; }
.site-logo { display: flex; align-items: center; gap: var(--space-sm); text-decoration: none; color: var(--header-link); }
.logo-cloud { display: block; width: 22px; height: 12px; position: relative; background: var(--header-link-hover-bg); border-radius: 12px; } .logo-cloud::before { content: ''; position: absolute; width: 10px; height: 10px; border-radius: 50%; background: var(--header-link-hover-bg); top: -5px; left: 4px; } .logo-cloud::after { content: ''; position: absolute; width: 7px; height: 7px; border-radius: 50%; background: var(--header-link-hover-bg); top: -3px; left: 12px; }
.logo-text { font-family: var(--font-body); font-weight: 700; font-size: var(--text-base); } .logo-at { color: var(--header-link-inactive); }
.nav-links { display: flex; gap: var(--space-lg); list-style: none; margin-left: auto; }
.nav-link { font-size: var(--text-sm); font-weight: 500; color: var(--header-fg-muted); text-decoration: none; padding-block: var(--space-xs); } .nav-link:hover { color: var(--header-fg); } .nav-link--active { color: var(--header-link); }
/* Mobile hamburger */ .nav-toggle-label { display: none; cursor: pointer; padding: var(--space-sm); margin: calc(-1 * var(--space-sm)); }
.hamburger { display: block; width: 20px; height: 2px; background: var(--header-fg); position: relative; } .hamburger::before, .hamburger::after { content: ''; position: absolute; width: 20px; height: 2px; background: var(--header-fg); left: 0; } .hamburger::before { top: -6px; } .hamburger::after { top: 6px; }
@media (max-width: 640px) { .site-nav { gap: var(--space-sm); }
.auth-alert { align-items: flex-start; flex-direction: column; gap: 2px; }
.nav-toggle-label { display: block; order: 2; }
.nav-links { position: absolute; top: 56px; left: 0; right: 0; flex-direction: column; background: var(--header-bg); border-bottom: 1px solid var(--header-border); padding: var(--space-base) var(--space-lg); gap: var(--space-base); display: none; }
.nav-toggle:checked ~ .nav-links { display: flex; }
.nav-toggle:checked ~ .nav-toggle-label .hamburger { background: transparent; } .nav-toggle:checked ~ .nav-toggle-label .hamburger::before { top: 0; transform: rotate(45deg); } .nav-toggle:checked ~ .nav-toggle-label .hamburger::after { top: 0; transform: rotate(-45deg); } }
@media (max-width: 360px) { .logo-text { display: none; } }</style>