Comprehensive visual overhaul of the Atlas Landing Site: - Dual-theme token system with light mode support via [data-theme="light"] - Glassmorphism + glow effects across all components (blur, gradient borders, glow shadows) - Theme toggle in navbar with localStorage persistence and system preference detection - Hero section: aurora glow orbs, gradient headline, floating screenshot animation - Animated gradient CTA buttons, glass card hover effects with gradient border reveal - Stagger scroll reveal animations, noise texture overlay, section gradient backgrounds - All 18 component files updated, no new files created
266 lines
7.7 KiB
Plaintext
266 lines
7.7 KiB
Plaintext
---
|
|
import CtaButton from './CtaButton.astro';
|
|
import { t, type Locale } from '../i18n/utils';
|
|
import { getRelease, getDownloadUrl } from '../data/release';
|
|
|
|
interface Props {
|
|
locale: Locale;
|
|
}
|
|
|
|
const { locale } = Astro.props;
|
|
const copy = t(locale);
|
|
const manifest = getRelease();
|
|
const downloadUrl = getDownloadUrl(manifest);
|
|
const altLocale = locale === 'zh' ? 'en' : 'zh';
|
|
const altPath = locale === 'zh' ? '/en/' : '/zh/';
|
|
const altLabel = locale === 'zh' ? 'EN' : '中文';
|
|
|
|
const navItems = [
|
|
{ label: copy.nav.whyAtlas, href: '#why' },
|
|
{ label: copy.nav.howItWorks, href: '#how' },
|
|
{ label: copy.nav.developers, href: '#developers' },
|
|
{ label: copy.nav.safety, href: '#safety' },
|
|
{ label: copy.nav.faq, href: '#faq' },
|
|
];
|
|
---
|
|
|
|
<header class="navbar" id="navbar">
|
|
<nav class="navbar__inner container" aria-label="Main navigation">
|
|
<a href={`/${locale}/`} class="navbar__brand" aria-label="Atlas for Mac">
|
|
<img src="/images/atlas-icon.png" alt="" width="32" height="32" class="navbar__logo" />
|
|
<span class="navbar__wordmark">Atlas</span>
|
|
</a>
|
|
|
|
<ul class="navbar__links" id="nav-links">
|
|
{navItems.map((item) => (
|
|
<li><a href={item.href} class="navbar__link">{item.label}</a></li>
|
|
))}
|
|
</ul>
|
|
|
|
<div class="navbar__actions">
|
|
<button class="navbar__theme-toggle" id="theme-toggle" aria-label="Toggle theme" title="Toggle theme">
|
|
<svg class="navbar__theme-icon navbar__theme-icon--sun" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<circle cx="12" cy="12" r="5"/>
|
|
<line x1="12" y1="1" x2="12" y2="3"/>
|
|
<line x1="12" y1="21" x2="12" y2="23"/>
|
|
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/>
|
|
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/>
|
|
<line x1="1" y1="12" x2="3" y2="12"/>
|
|
<line x1="21" y1="12" x2="23" y2="12"/>
|
|
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/>
|
|
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/>
|
|
</svg>
|
|
<svg class="navbar__theme-icon navbar__theme-icon--moon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
|
</svg>
|
|
</button>
|
|
<a href={altPath} class="navbar__lang" aria-label={`Switch to ${altLabel}`}>
|
|
{altLabel}
|
|
</a>
|
|
<CtaButton
|
|
label={copy.nav.download}
|
|
href={downloadUrl}
|
|
variant="primary"
|
|
class="navbar__cta"
|
|
/>
|
|
<button class="navbar__menu-btn" id="menu-btn" aria-label="Menu" aria-expanded="false">
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
|
<line x1="3" y1="6" x2="21" y2="6" />
|
|
<line x1="3" y1="12" x2="21" y2="12" />
|
|
<line x1="3" y1="18" x2="21" y2="18" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
|
|
<script>
|
|
const btn = document.getElementById('menu-btn');
|
|
const links = document.getElementById('nav-links');
|
|
if (btn && links) {
|
|
btn.addEventListener('click', () => {
|
|
const expanded = btn.getAttribute('aria-expanded') === 'true';
|
|
btn.setAttribute('aria-expanded', String(!expanded));
|
|
links.classList.toggle('is-open');
|
|
});
|
|
}
|
|
|
|
// Sticky background on scroll
|
|
let ticking = false;
|
|
const navbar = document.getElementById('navbar');
|
|
window.addEventListener('scroll', () => {
|
|
if (!ticking) {
|
|
requestAnimationFrame(() => {
|
|
if (navbar) {
|
|
navbar.classList.toggle('is-scrolled', window.scrollY > 40);
|
|
}
|
|
ticking = false;
|
|
});
|
|
ticking = true;
|
|
}
|
|
});
|
|
|
|
// Theme toggle
|
|
const themeToggle = document.getElementById('theme-toggle');
|
|
if (themeToggle) {
|
|
themeToggle.addEventListener('click', () => {
|
|
const html = document.documentElement;
|
|
const current = html.getAttribute('data-theme');
|
|
const next = current === 'dark' ? 'light' : 'dark';
|
|
html.setAttribute('data-theme', next);
|
|
localStorage.setItem('atlas-theme', next);
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.navbar {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
z-index: 100;
|
|
padding-block: var(--atlas-space-md);
|
|
transition: background-color var(--atlas-motion-standard),
|
|
backdrop-filter var(--atlas-motion-standard);
|
|
}
|
|
|
|
.navbar.is-scrolled {
|
|
background-color: var(--atlas-navbar-bg);
|
|
backdrop-filter: blur(20px);
|
|
-webkit-backdrop-filter: blur(20px);
|
|
border-bottom: 1px solid var(--atlas-color-border);
|
|
}
|
|
|
|
.navbar__inner {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--atlas-space-xxl);
|
|
}
|
|
|
|
.navbar__brand {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--atlas-space-sm);
|
|
text-decoration: none;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.navbar__logo {
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: var(--atlas-radius-sm);
|
|
}
|
|
|
|
.navbar__wordmark {
|
|
font-family: var(--atlas-font-display);
|
|
font-size: 1.125rem;
|
|
font-weight: 700;
|
|
color: var(--atlas-color-text-primary);
|
|
}
|
|
|
|
.navbar__links {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--atlas-space-xxl);
|
|
flex: 1;
|
|
}
|
|
|
|
.navbar__link {
|
|
font-size: var(--atlas-text-body-small);
|
|
color: var(--atlas-color-text-secondary);
|
|
text-decoration: none;
|
|
transition: color var(--atlas-motion-fast);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.navbar__link:hover {
|
|
color: var(--atlas-color-text-primary);
|
|
}
|
|
|
|
.navbar__actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--atlas-space-lg);
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.navbar__theme-toggle {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 36px;
|
|
height: 36px;
|
|
border-radius: var(--atlas-radius-sm);
|
|
border: 1px solid var(--atlas-color-border);
|
|
background: transparent;
|
|
color: var(--atlas-color-text-secondary);
|
|
cursor: pointer;
|
|
transition: color var(--atlas-motion-fast),
|
|
border-color var(--atlas-motion-fast);
|
|
}
|
|
|
|
.navbar__theme-toggle:hover {
|
|
color: var(--atlas-color-text-primary);
|
|
border-color: var(--atlas-color-border-emphasis);
|
|
}
|
|
|
|
/* Show sun in dark mode, moon in light mode */
|
|
.navbar__theme-icon--moon { display: none; }
|
|
.navbar__theme-icon--sun { display: block; }
|
|
|
|
[data-theme="light"] .navbar__theme-icon--sun { display: none; }
|
|
[data-theme="light"] .navbar__theme-icon--moon { display: block; }
|
|
|
|
.navbar__lang {
|
|
font-family: var(--atlas-font-mono);
|
|
font-size: var(--atlas-text-caption);
|
|
font-weight: 500;
|
|
color: var(--atlas-color-text-secondary);
|
|
text-decoration: none;
|
|
padding: var(--atlas-space-xxs) var(--atlas-space-sm);
|
|
border: 1px solid var(--atlas-color-border);
|
|
border-radius: var(--atlas-radius-sm);
|
|
transition: color var(--atlas-motion-fast),
|
|
border-color var(--atlas-motion-fast);
|
|
}
|
|
|
|
.navbar__lang:hover {
|
|
color: var(--atlas-color-text-primary);
|
|
border-color: var(--atlas-color-border-emphasis);
|
|
}
|
|
|
|
.navbar__menu-btn {
|
|
display: none;
|
|
color: var(--atlas-color-text-secondary);
|
|
}
|
|
|
|
@media (max-width: 860px) {
|
|
.navbar__links {
|
|
display: none;
|
|
position: absolute;
|
|
top: 100%;
|
|
left: 0;
|
|
right: 0;
|
|
flex-direction: column;
|
|
padding: var(--atlas-space-xl);
|
|
background-color: var(--atlas-mobile-menu-bg);
|
|
backdrop-filter: blur(12px);
|
|
border-bottom: 1px solid var(--atlas-color-border);
|
|
gap: var(--atlas-space-lg);
|
|
}
|
|
|
|
.navbar__links.is-open {
|
|
display: flex;
|
|
}
|
|
|
|
.navbar__menu-btn {
|
|
display: block;
|
|
}
|
|
|
|
:global(.navbar__cta) {
|
|
display: none;
|
|
}
|
|
}
|
|
</style>
|