Fix hero layout: align globe with headline and update README
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
9df4444cc5
commit
63778ba761
@ -198,14 +198,59 @@ img { max-width: 100%; display: block; }
|
|||||||
.hero {
|
.hero {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-columns: 1fr 1fr;
|
flex-direction: column;
|
||||||
align-items: start;
|
justify-content: center;
|
||||||
gap: 40px;
|
padding: calc(var(--nav-height) + 52px) 24px 80px;
|
||||||
padding: calc(var(--nav-height) + 40px) 24px 80px;
|
z-index: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-bg-shapes {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-inner {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
width: 100%;
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
z-index: 1;
|
}
|
||||||
|
|
||||||
|
.hero-top {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
align-items: center;
|
||||||
|
gap: 32px 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-content {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-bottom {
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-visual {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.globe-container {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-bg-shapes .shape {
|
.hero-bg-shapes .shape {
|
||||||
@ -302,7 +347,7 @@ img { max-width: 100%; display: block; }
|
|||||||
.hero-subtitle {
|
.hero-subtitle {
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
margin-bottom: 36px;
|
margin-bottom: 0;
|
||||||
max-width: 480px;
|
max-width: 480px;
|
||||||
line-height: 1.8;
|
line-height: 1.8;
|
||||||
}
|
}
|
||||||
@ -310,7 +355,7 @@ img { max-width: 100%; display: block; }
|
|||||||
.hero-actions {
|
.hero-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
margin-bottom: 48px;
|
margin-bottom: 32px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,23 +436,6 @@ img { max-width: 100%; display: block; }
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Globe Visual */
|
/* Globe Visual */
|
||||||
.hero-visual {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: flex-start;
|
|
||||||
position: relative;
|
|
||||||
/* 与左侧 hero-badge 等高,使地球与标题「用一行代码 环游世界」顶部对齐 */
|
|
||||||
padding-top: 58px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.globe-container {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 420px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.globe-svg {
|
.globe-svg {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
@ -481,9 +509,9 @@ img { max-width: 100%; display: block; }
|
|||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-1 { top: 8%; right: -5%; animation-delay: 0s; }
|
.fc-1 { top: 5%; right: -8%; animation-delay: 0s; }
|
||||||
.fc-2 { top: 42%; left: -12%; animation-delay: -1.5s; }
|
.fc-2 { top: 38%; left: -14%; animation-delay: -1.5s; }
|
||||||
.fc-3 { bottom: 8%; right: 0; animation-delay: -3s; }
|
.fc-3 { bottom: 10%; right: -2%; animation-delay: -3s; }
|
||||||
|
|
||||||
@keyframes cardFloat {
|
@keyframes cardFloat {
|
||||||
0%, 100% { transform: translateY(0); }
|
0%, 100% { transform: translateY(0); }
|
||||||
@ -1120,17 +1148,17 @@ img { max-width: 100%; display: block; }
|
|||||||
|
|
||||||
/* ===== Responsive ===== */
|
/* ===== Responsive ===== */
|
||||||
@media (max-width: 1024px) {
|
@media (max-width: 1024px) {
|
||||||
.hero {
|
.hero-top {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-top: calc(var(--nav-height) + 20px);
|
gap: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-subtitle { margin: 0 auto 36px; }
|
.hero-subtitle { margin: 0 auto; max-width: 100%; }
|
||||||
.hero-actions { justify-content: center; }
|
.hero-actions { justify-content: center; }
|
||||||
.hero-stats { justify-content: center; }
|
.hero-stats { justify-content: center; }
|
||||||
.hero-visual { order: -1; padding-top: 0; margin-bottom: 8px; }
|
.hero-visual { order: -1; }
|
||||||
.globe-container { max-width: 300px; margin: 0 auto; }
|
.globe-container { max-width: 280px; }
|
||||||
|
|
||||||
.dest-grid { grid-template-columns: repeat(2, 1fr); }
|
.dest-grid { grid-template-columns: repeat(2, 1fr); }
|
||||||
.tools-grid { grid-template-columns: repeat(2, 1fr); }
|
.tools-grid { grid-template-columns: repeat(2, 1fr); }
|
||||||
|
|||||||
@ -63,76 +63,86 @@ export default function Hero({ stats }: Props) {
|
|||||||
<div className="hero-bg-shapes">
|
<div className="hero-bg-shapes">
|
||||||
<div className="shape shape-1" /><div className="shape shape-2" /><div className="shape shape-3" />
|
<div className="shape shape-1" /><div className="shape shape-2" /><div className="shape shape-3" />
|
||||||
</div>
|
</div>
|
||||||
<div className="hero-content">
|
|
||||||
<div className="hero-badge reveal">
|
<div className="hero-inner">
|
||||||
<span className="badge-dot" />
|
<div className="hero-top">
|
||||||
🚀 全球 {stats.total_nomads} 数字游民正在路上
|
<div className="hero-content">
|
||||||
</div>
|
<div className="hero-badge reveal">
|
||||||
<h1 className="hero-title reveal">
|
<span className="badge-dot" />
|
||||||
用一行代码<br /><span className="gradient-text">环游世界</span> 🌏
|
🚀 全球 {stats.total_nomads} 数字游民正在路上
|
||||||
</h1>
|
</div>
|
||||||
<p className="hero-subtitle reveal">
|
<h1 className="hero-title reveal">
|
||||||
<span id="typewriter" /><span className="typewriter-cursor">|</span>
|
用一行代码<br /><span className="gradient-text">环游世界</span> 🌏
|
||||||
</p>
|
</h1>
|
||||||
<div className="hero-actions reveal">
|
<p className="hero-subtitle reveal">
|
||||||
<a href="#destinations" className="btn btn-primary">
|
<span id="typewriter" /><span className="typewriter-cursor">|</span>
|
||||||
<span>探索目的地</span>
|
</p>
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M5 12h14M12 5l7 7-7 7" /></svg>
|
|
||||||
</a>
|
|
||||||
<a href="#calculator" className="btn btn-ghost"><span>🧮 费用计算</span></a>
|
|
||||||
<button className="btn btn-ghost hero-matcher-btn" onClick={() => {
|
|
||||||
window.dispatchEvent(new CustomEvent("open-matcher"));
|
|
||||||
}}><span>🎯 智能匹配</span></button>
|
|
||||||
</div>
|
|
||||||
<div className="hero-stats reveal">
|
|
||||||
<div className="stat-item">
|
|
||||||
<span className="stat-number" data-target={stats.countries}>0</span>
|
|
||||||
<span className="stat-label">🗺️ 可探索国家</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="stat-divider" />
|
|
||||||
<div className="stat-item">
|
<div className="hero-visual reveal">
|
||||||
<span className="stat-number" data-target={stats.avg_cost}>0</span>
|
<div className="globe-container">
|
||||||
<span className="stat-label">💰 平均月生活费 (千元)</span>
|
<svg className="globe-svg" viewBox="0 0 400 400">
|
||||||
|
<defs>
|
||||||
|
<radialGradient id="globeGlow" cx="50%" cy="50%" r="50%">
|
||||||
|
<stop offset="0%" stopColor="#4ECDC4" stopOpacity="0.3" />
|
||||||
|
<stop offset="100%" stopColor="#4ECDC4" stopOpacity="0" />
|
||||||
|
</radialGradient>
|
||||||
|
<linearGradient id="orbitGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||||
|
<stop offset="0%" stopColor="#FF6B6B" /><stop offset="100%" stopColor="#4ECDC4" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<circle cx="200" cy="200" r="160" fill="url(#globeGlow)" />
|
||||||
|
<circle cx="200" cy="200" r="120" fill="none" stroke="rgba(78,205,196,0.2)" strokeWidth="1" />
|
||||||
|
<ellipse cx="200" cy="200" rx="120" ry="40" fill="none" stroke="rgba(78,205,196,0.3)" strokeWidth="1.5" className="orbit-ring" />
|
||||||
|
<ellipse cx="200" cy="200" rx="40" ry="120" fill="none" stroke="rgba(255,107,107,0.3)" strokeWidth="1.5" className="orbit-ring orbit-ring-2" />
|
||||||
|
<path d="M160 140 Q180 130 200 135 Q220 128 240 140 Q250 155 245 170 Q235 185 220 190 Q200 195 185 188 Q165 180 160 165 Z" fill="rgba(78,205,196,0.4)" className="continent" />
|
||||||
|
<g className="nomad-dots">
|
||||||
|
<circle cx="180" cy="155" r="5" fill="#FF6B6B" className="pulse-dot" />
|
||||||
|
<circle cx="260" cy="215" r="5" fill="#FFE66D" className="pulse-dot" />
|
||||||
|
<circle cx="145" cy="225" r="5" fill="#4ECDC4" className="pulse-dot" />
|
||||||
|
<circle cx="220" cy="175" r="5" fill="#A78BFA" className="pulse-dot" />
|
||||||
|
</g>
|
||||||
|
<path d="M180 155 Q220 140 260 215" fill="none" stroke="url(#orbitGrad)" strokeWidth="2" strokeDasharray="6 4" className="flight-path" />
|
||||||
|
</svg>
|
||||||
|
<div className="floating-cards">
|
||||||
|
<div className="float-card fc-1">🏝️ 巴厘岛<br /><small>WiFi 98Mbps</small></div>
|
||||||
|
<div className="float-card fc-2">☕ 里斯本<br /><small>€800/月</small></div>
|
||||||
|
<div className="float-card fc-3">🏔️ 清迈<br /><small>⭐ 4.9</small></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="stat-divider" />
|
</div>
|
||||||
<div className="stat-item">
|
|
||||||
<span className="stat-number" data-target={stats.satisfaction}>0</span>
|
<div className="hero-bottom reveal">
|
||||||
<span className="stat-label">😊 生活满意度 %</span>
|
<div className="hero-actions">
|
||||||
</div>
|
<a href="#destinations" className="btn btn-primary">
|
||||||
</div>
|
<span>探索目的地</span>
|
||||||
</div>
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M5 12h14M12 5l7 7-7 7" /></svg>
|
||||||
<div className="hero-visual reveal">
|
</a>
|
||||||
<div className="globe-container">
|
<a href="#calculator" className="btn btn-ghost"><span>🧮 费用计算</span></a>
|
||||||
<svg className="globe-svg" viewBox="0 0 400 400">
|
<button className="btn btn-ghost hero-matcher-btn" onClick={() => {
|
||||||
<defs>
|
window.dispatchEvent(new CustomEvent("open-matcher"));
|
||||||
<radialGradient id="globeGlow" cx="50%" cy="50%" r="50%">
|
}}><span>🎯 智能匹配</span></button>
|
||||||
<stop offset="0%" stopColor="#4ECDC4" stopOpacity="0.3" />
|
</div>
|
||||||
<stop offset="100%" stopColor="#4ECDC4" stopOpacity="0" />
|
<div className="hero-stats">
|
||||||
</radialGradient>
|
<div className="stat-item">
|
||||||
<linearGradient id="orbitGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
<span className="stat-number" data-target={stats.countries}>0</span>
|
||||||
<stop offset="0%" stopColor="#FF6B6B" /><stop offset="100%" stopColor="#4ECDC4" />
|
<span className="stat-label">🗺️ 可探索国家</span>
|
||||||
</linearGradient>
|
</div>
|
||||||
</defs>
|
<div className="stat-divider" />
|
||||||
<circle cx="200" cy="200" r="160" fill="url(#globeGlow)" />
|
<div className="stat-item">
|
||||||
<circle cx="200" cy="200" r="120" fill="none" stroke="rgba(78,205,196,0.2)" strokeWidth="1" />
|
<span className="stat-number" data-target={stats.avg_cost}>0</span>
|
||||||
<ellipse cx="200" cy="200" rx="120" ry="40" fill="none" stroke="rgba(78,205,196,0.3)" strokeWidth="1.5" className="orbit-ring" />
|
<span className="stat-label">💰 平均月生活费 (千元)</span>
|
||||||
<ellipse cx="200" cy="200" rx="40" ry="120" fill="none" stroke="rgba(255,107,107,0.3)" strokeWidth="1.5" className="orbit-ring orbit-ring-2" />
|
</div>
|
||||||
<path d="M160 140 Q180 130 200 135 Q220 128 240 140 Q250 155 245 170 Q235 185 220 190 Q200 195 185 188 Q165 180 160 165 Z" fill="rgba(78,205,196,0.4)" className="continent" />
|
<div className="stat-divider" />
|
||||||
<g className="nomad-dots">
|
<div className="stat-item">
|
||||||
<circle cx="180" cy="155" r="5" fill="#FF6B6B" className="pulse-dot" />
|
<span className="stat-number" data-target={stats.satisfaction}>0</span>
|
||||||
<circle cx="260" cy="215" r="5" fill="#FFE66D" className="pulse-dot" />
|
<span className="stat-label">😊 生活满意度 %</span>
|
||||||
<circle cx="145" cy="225" r="5" fill="#4ECDC4" className="pulse-dot" />
|
</div>
|
||||||
<circle cx="220" cy="175" r="5" fill="#A78BFA" className="pulse-dot" />
|
|
||||||
</g>
|
|
||||||
<path d="M180 155 Q220 140 260 215" fill="none" stroke="url(#orbitGrad)" strokeWidth="2" strokeDasharray="6 4" className="flight-path" />
|
|
||||||
</svg>
|
|
||||||
<div className="floating-cards">
|
|
||||||
<div className="float-card fc-1">🏝️ 巴厘岛<br /><small>WiFi 98Mbps</small></div>
|
|
||||||
<div className="float-card fc-2">☕ 里斯本<br /><small>€800/月</small></div>
|
|
||||||
<div className="float-card fc-3">🏔️ 清迈<br /><small>⭐ 4.9</small></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="scroll-indicator">
|
<div className="scroll-indicator">
|
||||||
<span>向下滚动</span>
|
<span>向下滚动</span>
|
||||||
<div className="scroll-arrow">
|
<div className="scroll-arrow">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user