From 8116eee6c160abe07c8e03429223e751b9300756 Mon Sep 17 00:00:00 2001
From: zhukang <274546966@qq.com>
Date: Fri, 27 Mar 2026 23:16:34 +0800
Subject: [PATCH] feat(landing): glassmorphism visual upgrade with dark/light
theme toggle
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
---
.../src/components/ChannelBadge.astro | 8 +-
.../src/components/CtaButton.astro | 35 ++++++-
.../src/components/DeveloperSection.astro | 13 ++-
.../src/components/FaqSection.astro | 28 +++++-
.../src/components/FeatureCard.astro | 33 ++++++-
.../src/components/FooterSection.astro | 20 +++-
Apps/LandingSite/src/components/Hero.astro | 65 +++++++++++-
.../src/components/HowItWorks.astro | 41 ++++++--
Apps/LandingSite/src/components/NavBar.astro | 63 +++++++++++-
.../src/components/OpenSourceSection.astro | 12 ++-
.../src/components/ProblemOutcome.astro | 37 ++++++-
.../src/components/SafetySection.astro | 13 ++-
.../src/components/ScreenshotGallery.astro | 37 +++++--
.../src/components/TrustStrip.astro | 31 +++++-
Apps/LandingSite/src/layouts/BaseLayout.astro | 24 ++++-
Apps/LandingSite/src/styles/global.css | 31 ++++++
Apps/LandingSite/src/styles/tokens.css | 48 ++++++++-
Apps/LandingSite/src/styles/utilities.css | 98 +++++++++++++++++++
18 files changed, 581 insertions(+), 56 deletions(-)
diff --git a/Apps/LandingSite/src/components/ChannelBadge.astro b/Apps/LandingSite/src/components/ChannelBadge.astro
index 5544106..77e8264 100644
--- a/Apps/LandingSite/src/components/ChannelBadge.astro
+++ b/Apps/LandingSite/src/components/ChannelBadge.astro
@@ -29,6 +29,9 @@ const { channel, label, version, date } = Astro.props;
padding: var(--atlas-space-xxs) var(--atlas-space-sm);
border-radius: var(--atlas-radius-sm);
line-height: 1.4;
+ background: var(--atlas-glass-bg);
+ backdrop-filter: blur(12px);
+ -webkit-backdrop-filter: blur(12px);
}
.badge__dot {
@@ -47,27 +50,26 @@ const { channel, label, version, date } = Astro.props;
}
.badge--stable {
- background: rgba(20, 144, 133, 0.15);
color: var(--atlas-color-accent);
border: 1px solid rgba(20, 144, 133, 0.3);
}
.badge--stable .badge__dot {
background-color: var(--atlas-color-accent);
+ animation: pulse-dot 2s ease-in-out infinite;
}
.badge--prerelease {
- background: rgba(245, 158, 11, 0.15);
color: var(--atlas-color-warning);
border: 1px solid rgba(245, 158, 11, 0.3);
}
.badge--prerelease .badge__dot {
background-color: var(--atlas-color-warning);
+ animation: pulse-dot 2s ease-in-out infinite;
}
.badge--none {
- background: rgba(148, 163, 184, 0.1);
color: var(--atlas-color-text-secondary);
border: 1px solid rgba(148, 163, 184, 0.2);
}
diff --git a/Apps/LandingSite/src/components/CtaButton.astro b/Apps/LandingSite/src/components/CtaButton.astro
index dc4e95b..4685a20 100644
--- a/Apps/LandingSite/src/components/CtaButton.astro
+++ b/Apps/LandingSite/src/components/CtaButton.astro
@@ -49,8 +49,10 @@ const linkAttrs = external ? { target: '_blank', rel: 'noopener noreferrer' } :
.cta--primary {
color: #ffffff;
padding: var(--atlas-space-md) var(--atlas-space-xxl);
- background-color: var(--atlas-color-brand);
+ background: var(--atlas-gradient-brand);
+ background-size: 200% 100%;
box-shadow: var(--atlas-shadow-cta);
+ animation: gradient-shift 3s ease infinite;
}
.cta--primary:hover {
@@ -64,17 +66,40 @@ const linkAttrs = external ? { target: '_blank', rel: 'noopener noreferrer' } :
}
.cta--secondary {
- color: var(--atlas-color-brand);
+ color: var(--atlas-color-accent);
padding: var(--atlas-space-md) var(--atlas-space-xxl);
- background-color: rgba(20, 144, 133, 0.04);
- border: 1.5px solid rgba(20, 144, 133, 0.3);
+ background: var(--atlas-glass-bg);
+ backdrop-filter: blur(12px);
+ -webkit-backdrop-filter: blur(12px);
+ border: 1.5px solid transparent;
+ background-clip: padding-box;
+ position: relative;
+ }
+
+ .cta--secondary::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ border-radius: inherit;
+ padding: 1.5px;
+ background: var(--atlas-gradient-brand);
+ -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
+ mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
+ -webkit-mask-composite: xor;
+ mask-composite: exclude;
+ pointer-events: none;
+ opacity: 0.4;
}
.cta--secondary:hover {
- background-color: rgba(20, 144, 133, 0.08);
+ background: var(--atlas-color-bg-raised);
transform: translateY(-1px);
}
+ .cta--secondary:hover::before {
+ opacity: 0.7;
+ }
+
.cta--secondary:active {
transform: scale(0.97);
}
diff --git a/Apps/LandingSite/src/components/DeveloperSection.astro b/Apps/LandingSite/src/components/DeveloperSection.astro
index 6a57a87..2f4f6d4 100644
--- a/Apps/LandingSite/src/components/DeveloperSection.astro
+++ b/Apps/LandingSite/src/components/DeveloperSection.astro
@@ -61,9 +61,18 @@ const copy = t(locale);
.dev__card {
padding: var(--atlas-space-xl);
- background: var(--atlas-color-bg-base);
- border: 1px solid var(--atlas-color-border);
+ background: var(--atlas-glass-bg);
+ backdrop-filter: blur(20px);
+ -webkit-backdrop-filter: blur(20px);
+ border: 1px solid var(--atlas-glass-border);
border-radius: var(--atlas-radius-lg);
+ transition: box-shadow var(--atlas-motion-standard),
+ transform var(--atlas-motion-fast);
+ }
+
+ .dev__card:hover {
+ box-shadow: var(--atlas-glow-card-hover);
+ transform: translateY(-2px);
}
.dev__card-title {
diff --git a/Apps/LandingSite/src/components/FaqSection.astro b/Apps/LandingSite/src/components/FaqSection.astro
index 1f9778c..4a997c5 100644
--- a/Apps/LandingSite/src/components/FaqSection.astro
+++ b/Apps/LandingSite/src/components/FaqSection.astro
@@ -48,17 +48,38 @@ const copy = t(locale);
}
.faq__item {
- border: 1px solid var(--atlas-color-border);
+ border: 1px solid var(--atlas-glass-border);
border-radius: var(--atlas-radius-lg);
- background: var(--atlas-color-bg-base);
+ background: var(--atlas-glass-bg);
+ backdrop-filter: blur(20px);
+ -webkit-backdrop-filter: blur(20px);
overflow: hidden;
- transition: border-color var(--atlas-motion-fast);
+ transition: border-color var(--atlas-motion-fast),
+ box-shadow var(--atlas-motion-standard);
+ position: relative;
+ }
+
+ .faq__item::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ width: 3px;
+ background: var(--atlas-gradient-brand);
+ opacity: 0;
+ transition: opacity var(--atlas-motion-standard);
+ border-radius: 3px 0 0 3px;
}
.faq__item[open] {
border-color: var(--atlas-color-border-emphasis);
}
+ .faq__item[open]::before {
+ opacity: 1;
+ }
+
.faq__question {
display: flex;
justify-content: space-between;
@@ -83,6 +104,7 @@ const copy = t(locale);
.faq__item[open] .faq__chevron {
transform: rotate(180deg);
+ color: var(--atlas-color-brand);
}
.faq__answer {
diff --git a/Apps/LandingSite/src/components/FeatureCard.astro b/Apps/LandingSite/src/components/FeatureCard.astro
index f51f3e3..7a2b82e 100644
--- a/Apps/LandingSite/src/components/FeatureCard.astro
+++ b/Apps/LandingSite/src/components/FeatureCard.astro
@@ -24,17 +24,40 @@ const { title, value, example, trustCue } = Astro.props;
diff --git a/Apps/LandingSite/src/components/NavBar.astro b/Apps/LandingSite/src/components/NavBar.astro
index 4da67cb..dc3caf7 100644
--- a/Apps/LandingSite/src/components/NavBar.astro
+++ b/Apps/LandingSite/src/components/NavBar.astro
@@ -38,6 +38,22 @@ const navItems = [
+
{altLabel}
@@ -83,6 +99,18 @@ const navItems = [
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);
+ });
+ }
diff --git a/Apps/LandingSite/src/layouts/BaseLayout.astro b/Apps/LandingSite/src/layouts/BaseLayout.astro
index 3082110..563a4aa 100644
--- a/Apps/LandingSite/src/layouts/BaseLayout.astro
+++ b/Apps/LandingSite/src/layouts/BaseLayout.astro
@@ -18,7 +18,7 @@ const altUrl = new URL(altPath, Astro.site);
---
-
+
@@ -69,11 +69,21 @@ const altUrl = new URL(altPath, Astro.site);
"description": description,
"url": canonicalUrl.href
})} />
+
+
+
-
+
diff --git a/Apps/LandingSite/src/styles/global.css b/Apps/LandingSite/src/styles/global.css
index 96e4e0d..e7fd3fc 100644
--- a/Apps/LandingSite/src/styles/global.css
+++ b/Apps/LandingSite/src/styles/global.css
@@ -51,6 +51,16 @@
font-display: swap;
}
+/* ── Theme Defaults ────────────────────────────────── */
+
+html {
+ color-scheme: dark;
+}
+
+[data-theme="light"] {
+ color-scheme: light;
+}
+
/* ── Base ──────────────────────────────────────────── */
body {
@@ -59,6 +69,27 @@ body {
font-weight: var(--atlas-text-body-weight);
color: var(--atlas-color-text-primary);
background-color: var(--atlas-color-bg-base);
+ transition: background-color 0.3s, color 0.3s;
+ position: relative;
+}
+
+/* Noise texture overlay */
+body::before {
+ content: '';
+ position: fixed;
+ inset: 0;
+ z-index: 0;
+ pointer-events: none;
+ opacity: var(--atlas-noise-opacity);
+ background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
+ background-repeat: repeat;
+ background-size: 256px 256px;
+}
+
+/* Ensure content sits above noise */
+body > * {
+ position: relative;
+ z-index: 1;
}
h1, h2, h3 {
diff --git a/Apps/LandingSite/src/styles/tokens.css b/Apps/LandingSite/src/styles/tokens.css
index ecad164..1ddca0c 100644
--- a/Apps/LandingSite/src/styles/tokens.css
+++ b/Apps/LandingSite/src/styles/tokens.css
@@ -1,7 +1,7 @@
/* ══════════════════════════════════════════════════════
Atlas Landing Page — Design Tokens
Source of truth: AtlasBrand.swift + AtlasColors.xcassets
- Theme: "Precision Utility" (dark-only)
+ Theme: "Precision Utility" (dark + light)
══════════════════════════════════════════════════════ */
:root {
@@ -36,6 +36,15 @@
--atlas-color-border: rgba(241, 245, 249, 0.08);
--atlas-color-border-emphasis: rgba(241, 245, 249, 0.14);
+ /* ── Gradients & Effects ─────────────────────────── */
+ --atlas-gradient-brand: linear-gradient(135deg, #149085, #34D399);
+ --atlas-gradient-hero: radial-gradient(ellipse 80% 50% at 50% -20%, rgba(20, 144, 133, 0.15) 0%, transparent 70%);
+ --atlas-glow-brand: 0 0 60px rgba(20, 144, 133, 0.15);
+ --atlas-glow-card-hover: 0 8px 30px rgba(20, 144, 133, 0.12), 0 0 0 1px rgba(52, 211, 153, 0.1);
+ --atlas-glass-bg: rgba(255, 255, 255, 0.04);
+ --atlas-glass-border: rgba(255, 255, 255, 0.08);
+ --atlas-noise-opacity: 0.03;
+
/* ── Typography ──────────────────────────────────── */
--atlas-font-display: 'Space Grotesk', system-ui, sans-serif;
--atlas-font-body: 'Instrument Sans', system-ui, sans-serif;
@@ -96,9 +105,46 @@
--atlas-motion-standard: 220ms cubic-bezier(0.2, 0, 0, 1);
--atlas-motion-slow: 350ms cubic-bezier(0.2, 0, 0, 1);
--atlas-stagger-delay: 80ms;
+ --atlas-duration-float: 6s;
/* ── Layout ──────────────────────────────────────── */
--atlas-width-reading: 920px;
--atlas-width-content: 1080px;
--atlas-width-workspace: 1200px;
+
+ /* ── Navbar ──────────────────────────────────────── */
+ --atlas-navbar-bg: rgba(13, 15, 17, 0.85);
+ --atlas-mobile-menu-bg: rgba(13, 15, 17, 0.95);
+}
+
+/* ── Light Theme Overrides ─────────────────────────── */
+
+[data-theme="light"] {
+ --atlas-color-bg-base: #FAFBFC;
+ --atlas-color-bg-surface: #F1F5F9;
+ --atlas-color-bg-surface-hover: #E2E8F0;
+ --atlas-color-bg-raised: rgba(0, 0, 0, 0.02);
+ --atlas-color-bg-code: #F8FAFC;
+
+ --atlas-color-text-primary: #0F172A;
+ --atlas-color-text-secondary: #475569;
+ --atlas-color-text-tertiary: rgba(71, 85, 105, 0.6);
+
+ --atlas-color-border: rgba(15, 23, 42, 0.08);
+ --atlas-color-border-emphasis: rgba(15, 23, 42, 0.14);
+
+ --atlas-gradient-hero: radial-gradient(ellipse 80% 50% at 50% -20%, rgba(20, 144, 133, 0.08) 0%, transparent 70%);
+ --atlas-glow-brand: 0 0 60px rgba(20, 144, 133, 0.1);
+ --atlas-glow-card-hover: 0 8px 30px rgba(20, 144, 133, 0.08), 0 0 0 1px rgba(52, 211, 153, 0.08);
+ --atlas-glass-bg: rgba(255, 255, 255, 0.7);
+ --atlas-glass-border: rgba(0, 0, 0, 0.08);
+ --atlas-noise-opacity: 0.02;
+
+ --atlas-shadow-raised: 0 10px 18px rgba(0, 0, 0, 0.04);
+ --atlas-shadow-prominent: 0 16px 28px rgba(0, 0, 0, 0.06);
+ --atlas-shadow-cta: 0 6px 12px rgba(20, 144, 133, 0.2);
+ --atlas-shadow-cta-hover: 0 8px 20px rgba(20, 144, 133, 0.3);
+
+ --atlas-navbar-bg: rgba(250, 251, 252, 0.85);
+ --atlas-mobile-menu-bg: rgba(250, 251, 252, 0.95);
}
diff --git a/Apps/LandingSite/src/styles/utilities.css b/Apps/LandingSite/src/styles/utilities.css
index 4c1f01c..91bb89c 100644
--- a/Apps/LandingSite/src/styles/utilities.css
+++ b/Apps/LandingSite/src/styles/utilities.css
@@ -23,10 +23,20 @@
.band--dark {
background-color: var(--atlas-color-bg-base);
+ position: relative;
+}
+
+.band--dark::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: radial-gradient(ellipse 60% 40% at 50% 50%, rgba(20, 144, 133, 0.04) 0%, transparent 70%);
+ pointer-events: none;
}
.band--surface {
background-color: var(--atlas-color-bg-surface);
+ position: relative;
}
/* ── Accessibility ─────────────────────────────────── */
@@ -85,3 +95,91 @@
opacity: 1;
transform: translateY(0);
}
+
+/* ── Glass Card ──────────────────────────────────── */
+
+.glass-card {
+ background: var(--atlas-glass-bg);
+ backdrop-filter: blur(20px);
+ -webkit-backdrop-filter: blur(20px);
+ border: 1px solid var(--atlas-glass-border);
+ border-radius: var(--atlas-radius-xl);
+}
+
+/* ── Gradient Text ───────────────────────────────── */
+
+.gradient-text {
+ background: var(--atlas-gradient-brand);
+ -webkit-background-clip: text;
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+}
+
+/* ── Glow Hover ──────────────────────────────────── */
+
+.glow-hover {
+ transition: box-shadow var(--atlas-motion-standard),
+ transform var(--atlas-motion-fast);
+}
+
+.glow-hover:hover {
+ box-shadow: var(--atlas-glow-card-hover);
+}
+
+/* ── Stagger Delays ──────────────────────────────── */
+
+.stagger-1 { transition-delay: calc(var(--atlas-stagger-delay) * 0); }
+.stagger-2 { transition-delay: calc(var(--atlas-stagger-delay) * 1); }
+.stagger-3 { transition-delay: calc(var(--atlas-stagger-delay) * 2); }
+.stagger-4 { transition-delay: calc(var(--atlas-stagger-delay) * 3); }
+.stagger-5 { transition-delay: calc(var(--atlas-stagger-delay) * 4); }
+.stagger-6 { transition-delay: calc(var(--atlas-stagger-delay) * 5); }
+
+/* ── Float Animation ─────────────────────────────── */
+
+.float-animation {
+ animation: float var(--atlas-duration-float) ease-in-out infinite;
+}
+
+/* ── Gradient Border ─────────────────────────────── */
+
+.gradient-border {
+ position: relative;
+}
+
+.gradient-border::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ border-radius: inherit;
+ padding: 1px;
+ background: var(--atlas-gradient-brand);
+ -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
+ mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
+ -webkit-mask-composite: xor;
+ mask-composite: exclude;
+ pointer-events: none;
+}
+
+/* ── Keyframe Animations ─────────────────────────── */
+
+@keyframes float {
+ 0%, 100% { transform: translateY(0); }
+ 50% { transform: translateY(-8px); }
+}
+
+@keyframes gradient-shift {
+ 0% { background-position: 0% 50%; }
+ 50% { background-position: 100% 50%; }
+ 100% { background-position: 0% 50%; }
+}
+
+@keyframes pulse-glow {
+ 0%, 100% { opacity: 0.15; }
+ 50% { opacity: 0.25; }
+}
+
+@keyframes pulse-dot {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0.4; }
+}