Files
dreamweaver/frontend/public/landing.html
zhangtuo e9d7f8832a Initial commit: clean project structure
- Backend: FastAPI + SQLAlchemy + Celery (Python 3.11+)
- Frontend: Vue 3 + TypeScript + Pinia + Tailwind
- Admin Frontend: separate Vue 3 app for management
- Docker Compose: 9 services orchestration
- Specs: design prototypes, memory system PRD, product roadmap

Cleanup performed:
- Removed temporary debug scripts from backend root
- Removed deprecated admin_app.py (embedded UI)
- Removed duplicate docs from admin-frontend
- Updated .gitignore for Vite cache and egg-info
2026-01-20 18:20:03 +08:00

399 lines
29 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>梦语织机 - AI 儿童故事创作</title>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-deep: #0D0F1A;
--bg-card: #151829;
--bg-elevated: #1C2035;
--accent: #FFD369;
--accent-soft: #FFF0C9;
--text: #EAEAEA;
--text-secondary: #9CA3AF;
--text-muted: #6B7280;
--border: rgba(255,255,255,0.08);
--glow: rgba(255, 211, 105, 0.15);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Noto Sans SC', -apple-system, sans-serif;
background: var(--bg-deep);
color: var(--text);
line-height: 1.6;
overflow-x: hidden;
}
/* 动画背景 */
.animated-bg { position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
.glow { position: absolute; border-radius: 50%; filter: blur(80px); opacity: 0.5; will-change: transform; }
.glow-1 { width: 600px; height: 600px; background: radial-gradient(circle, rgba(99, 102, 241, 0.4) 0%, transparent 70%); top: -200px; left: -100px; animation: float1 20s ease-in-out infinite; }
.glow-2 { width: 500px; height: 500px; background: radial-gradient(circle, rgba(255, 211, 105, 0.3) 0%, transparent 70%); top: 30%; right: -150px; animation: float2 25s ease-in-out infinite; }
.glow-3 { width: 400px; height: 400px; background: radial-gradient(circle, rgba(168, 85, 247, 0.35) 0%, transparent 70%); bottom: -100px; left: 20%; animation: float3 22s ease-in-out infinite; }
@keyframes float1 { 0%, 100% { transform: translate(0, 0) scale(1); } 33% { transform: translate(100px, 50px) scale(1.1); } 66% { transform: translate(50px, 100px) scale(0.9); } }
@keyframes float2 { 0%, 100% { transform: translate(0, 0) scale(1); } 33% { transform: translate(-80px, 60px) scale(1.15); } 66% { transform: translate(-40px, -40px) scale(0.95); } }
@keyframes float3 { 0%, 100% { transform: translate(0, 0) scale(1); } 33% { transform: translate(60px, -50px) scale(1.05); } 66% { transform: translate(-30px, 30px) scale(1.1); } }
.grid-bg { position: absolute; inset: 0; background-image: linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px); background-size: 60px 60px; mask-image: radial-gradient(ellipse 80% 50% at 50% 50%, black 40%, transparent 100%); }
.star { position: absolute; width: 2px; height: 2px; background: white; border-radius: 50%; animation: twinkle 3s ease-in-out infinite; }
@keyframes twinkle { 0%, 100% { opacity: 0.3; transform: scale(1); } 50% { opacity: 1; transform: scale(1.5); } }
/* 导航 */
nav { position: fixed; top: 0; left: 0; right: 0; padding: 16px 48px; display: flex; justify-content: space-between; align-items: center; background: rgba(13, 15, 26, 0.8); backdrop-filter: blur(12px); border-bottom: 1px solid var(--border); z-index: 100; }
.logo { font-size: 1.2rem; font-weight: 600; color: var(--accent); letter-spacing: 1px; }
.nav-links { display: flex; gap: 36px; list-style: none; }
.nav-links a { color: var(--text-secondary); text-decoration: none; font-size: 0.9rem; transition: color 0.2s; }
.nav-links a:hover { color: var(--text); }
.nav-cta { padding: 10px 22px; background: var(--accent); color: var(--bg-deep); border: none; border-radius: 8px; font-size: 0.9rem; font-weight: 600; cursor: pointer; transition: all 0.2s; }
.nav-cta:hover { box-shadow: 0 0 20px var(--glow); }
/* 滚动动画 */
.fade-in { opacity: 0; transform: translateY(40px); transition: opacity 0.8s ease-out, transform 0.8s ease-out; }
.fade-in.visible { opacity: 1; transform: translateY(0); }
.fade-in-left { opacity: 0; transform: translateX(-60px); transition: opacity 0.8s ease-out, transform 0.8s ease-out; }
.fade-in-left.visible { opacity: 1; transform: translateX(0); }
.fade-in-right { opacity: 0; transform: translateX(60px); transition: opacity 0.8s ease-out, transform 0.8s ease-out; }
.fade-in-right.visible { opacity: 1; transform: translateX(0); }
.fade-in-scale { opacity: 0; transform: scale(0.9); transition: opacity 0.8s ease-out, transform 0.8s ease-out; }
.fade-in-scale.visible { opacity: 1; transform: scale(1); }
.delay-1 { transition-delay: 0.1s; }
.delay-2 { transition-delay: 0.2s; }
.delay-3 { transition-delay: 0.3s; }
.delay-4 { transition-delay: 0.4s; }
.delay-5 { transition-delay: 0.5s; }
/* 按钮 */
.btn-primary { padding: 16px 32px; background: var(--accent); color: var(--bg-deep); border: none; border-radius: 10px; font-size: 1rem; font-weight: 600; cursor: pointer; transition: all 0.2s; }
.btn-primary:hover { box-shadow: 0 0 30px var(--glow); transform: translateY(-2px); }
.btn-ghost { padding: 16px 32px; background: transparent; color: var(--text); border: 1px solid var(--border); border-radius: 10px; font-size: 1rem; cursor: pointer; transition: all 0.2s; }
.btn-ghost:hover { background: var(--bg-elevated); border-color: var(--text-muted); }
/* Hero */
.hero { min-height: 100vh; display: flex; align-items: center; padding: 120px 48px 80px; max-width: 1400px; margin: 0 auto; position: relative; z-index: 1; }
.hero-content { flex: 1; max-width: 580px; }
.hero-badge { display: inline-flex; align-items: center; gap: 8px; padding: 8px 16px; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 24px; font-size: 0.85rem; color: var(--text-secondary); margin-bottom: 28px; }
.hero-badge span { color: var(--accent); }
.hero-title { font-size: 3.5rem; font-weight: 700; line-height: 1.2; margin-bottom: 24px; }
.hero-title .highlight { color: var(--accent); }
.hero-desc { font-size: 1.15rem; color: var(--text-secondary); line-height: 1.8; margin-bottom: 40px; }
.hero-buttons { display: flex; gap: 16px; margin-bottom: 56px; }
.hero-visual { flex: 1; display: flex; justify-content: flex-end; padding-left: 60px; }
.visual-container { position: relative; width: 440px; }
/* 故事卡片 */
.main-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 20px; padding: 24px; backdrop-filter: blur(10px); }
.card-cover { aspect-ratio: 16/10; background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%); border-radius: 14px; margin-bottom: 20px; position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center; }
.card-cover::before { content: ''; position: absolute; width: 100px; height: 100px; background: radial-gradient(circle, var(--accent) 0%, transparent 70%); opacity: 0.3; top: 20%; left: 30%; filter: blur(20px); }
.card-cover-text { font-size: 3rem; opacity: 0.8; animation: bounce 2s ease-in-out infinite; }
@keyframes bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
.card-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 12px; }
.card-title { font-size: 1.15rem; font-weight: 600; }
.card-badge { padding: 4px 10px; background: var(--glow); color: var(--accent); border-radius: 6px; font-size: 0.75rem; font-weight: 500; }
.card-excerpt { font-size: 0.9rem; color: var(--text-secondary); line-height: 1.7; margin-bottom: 16px; }
.card-tags { display: flex; gap: 8px; margin-bottom: 20px; }
.tag { padding: 6px 12px; background: var(--bg-elevated); color: var(--text-muted); border-radius: 6px; font-size: 0.8rem; border: 1px solid var(--border); }
.card-actions { display: flex; gap: 10px; }
.action-btn { flex: 1; padding: 12px; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 10px; font-size: 0.85rem; color: var(--text-secondary); cursor: pointer; transition: all 0.2s; display: flex; align-items: center; justify-content: center; gap: 8px; }
.action-btn:hover { border-color: var(--accent); color: var(--accent); }
/* 浮动卡片 */
.float-card { position: absolute; background: var(--bg-card); border: 1px solid var(--border); padding: 12px 18px; border-radius: 12px; backdrop-filter: blur(10px); display: flex; align-items: center; gap: 12px; animation: floatCard 6s ease-in-out infinite; }
.float-card-1 { top: 20px; left: -60px; }
.float-card-2 { bottom: 80px; right: -40px; animation-delay: 1s; }
@keyframes floatCard { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-15px); } }
.float-icon { width: 36px; height: 36px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 18px; background: var(--bg-elevated); }
.float-text { font-size: 0.85rem; color: var(--text-secondary); }
/* Trust Bar */
.trust-bar { padding: 60px 48px; background: rgba(255,255,255,0.02); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); position: relative; z-index: 1; }
.trust-container { max-width: 900px; margin: 0 auto; display: flex; justify-content: center; gap: 60px; flex-wrap: wrap; }
.stat-item { text-align: center; min-width: 140px; }
.stat-number { font-size: 2.5rem; font-weight: 700; color: var(--text); line-height: 1; margin-bottom: 8px; }
.stat-number .accent { color: var(--accent); }
.stat-label { font-size: 0.9rem; color: var(--text-muted); }
/* Section通用 */
.section { padding: 120px 48px; position: relative; z-index: 1; }
.section-header { text-align: center; margin-bottom: 72px; }
.section-label { font-size: 0.85rem; color: var(--accent); text-transform: uppercase; letter-spacing: 2px; margin-bottom: 16px; }
.section-title { font-size: 2.5rem; font-weight: 600; }
/* Features */
.features-container { max-width: 1200px; margin: 0 auto; }
.features-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.feature-card { background: var(--bg-card); border: 1px solid var(--border); padding: 36px 28px; border-radius: 16px; transition: all 0.3s; }
.feature-card:hover { border-color: rgba(255, 211, 105, 0.3); transform: translateY(-4px); }
.feature-icon { width: 52px; height: 52px; border-radius: 14px; display: flex; align-items: center; justify-content: center; font-size: 24px; margin-bottom: 24px; background: var(--bg-elevated); border: 1px solid var(--border); }
.feature-title { font-size: 1.1rem; font-weight: 600; margin-bottom: 12px; }
.feature-desc { font-size: 0.95rem; color: var(--text-secondary); line-height: 1.7; }
/* How It Works */
.steps-container { max-width: 800px; margin: 0 auto; }
.steps { display: flex; flex-direction: column; gap: 24px; }
.step { display: flex; align-items: flex-start; gap: 24px; background: rgba(255,255,255,0.03); border: 1px solid var(--border); border-radius: 16px; padding: 28px; transition: all 0.3s; }
.step:hover { border-color: rgba(255, 211, 105, 0.3); }
.step-number { width: 56px; height: 56px; background: linear-gradient(135deg, var(--accent), #FF9F43); border-radius: 14px; display: flex; align-items: center; justify-content: center; font-size: 1.5rem; font-weight: 700; color: var(--bg-deep); flex-shrink: 0; }
.step-content h3 { font-size: 1.15rem; font-weight: 600; margin-bottom: 8px; }
.step-content p { font-size: 0.95rem; color: var(--text-secondary); line-height: 1.7; }
/* FAQ */
.faq-container { max-width: 700px; margin: 0 auto; }
.faq-list { display: flex; flex-direction: column; gap: 12px; }
.faq-item { background: rgba(255,255,255,0.03); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; transition: border-color 0.3s; }
.faq-item:hover { border-color: rgba(255,255,255,0.15); }
.faq-item.active { border-color: rgba(255, 211, 105, 0.3); }
.faq-question { width: 100%; padding: 20px 24px; background: none; border: none; color: var(--text); font-size: 1rem; font-weight: 500; text-align: left; cursor: pointer; display: flex; justify-content: space-between; align-items: center; gap: 16px; transition: color 0.2s; }
.faq-question:hover { color: var(--accent); }
.faq-item.active .faq-question { color: var(--accent); }
.faq-icon { width: 24px; height: 24px; flex-shrink: 0; position: relative; }
.faq-icon::before, .faq-icon::after { content: ''; position: absolute; background: currentColor; border-radius: 2px; transition: transform 0.3s ease; }
.faq-icon::before { width: 14px; height: 2px; top: 50%; left: 50%; transform: translate(-50%, -50%); }
.faq-icon::after { width: 2px; height: 14px; top: 50%; left: 50%; transform: translate(-50%, -50%); }
.faq-item.active .faq-icon::after { transform: translate(-50%, -50%) rotate(90deg); opacity: 0; }
.faq-answer-wrapper { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.3s ease; }
.faq-item.active .faq-answer-wrapper { grid-template-rows: 1fr; }
.faq-answer { overflow: hidden; }
.faq-answer-content { padding: 0 24px 20px; color: var(--text-secondary); line-height: 1.7; }
/* CTA */
.cta { text-align: center; }
.cta-container { max-width: 650px; margin: 0 auto; padding: 60px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 24px; }
.cta-title { font-size: 2rem; font-weight: 600; margin-bottom: 16px; }
.cta-desc { font-size: 1rem; color: var(--text-secondary); margin-bottom: 32px; }
/* 模态框 */
.modal-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.7); backdrop-filter: blur(4px); z-index: 1000; display: flex; align-items: center; justify-content: center; padding: 24px; opacity: 0; visibility: hidden; transition: opacity 0.3s ease, visibility 0.3s ease; }
.modal-overlay.active { opacity: 1; visibility: visible; }
.modal { background: var(--bg-card); border: 1px solid var(--border); border-radius: 20px; width: 100%; max-width: 500px; max-height: 90vh; overflow-y: auto; transform: scale(0.9) translateY(20px); opacity: 0; transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.3s ease; }
.modal-overlay.active .modal { transform: scale(1) translateY(0); opacity: 1; }
.modal-header { display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; border-bottom: 1px solid var(--border); }
.modal-title { font-size: 1.25rem; font-weight: 600; }
.modal-close { width: 36px; height: 36px; border: none; background: rgba(255,255,255,0.05); border-radius: 10px; color: var(--text-secondary); font-size: 1.25rem; cursor: pointer; transition: all 0.2s; display: flex; align-items: center; justify-content: center; }
.modal-close:hover { background: rgba(255,255,255,0.1); color: var(--text); }
.modal-body { padding: 24px; }
.form-group { margin-bottom: 20px; }
.form-label { display: block; font-size: 0.9rem; color: var(--text-secondary); margin-bottom: 8px; }
.form-input { width: 100%; padding: 14px 16px; background: rgba(255,255,255,0.05); border: 1px solid var(--border); border-radius: 10px; color: var(--text); font-size: 1rem; transition: border-color 0.2s, box-shadow 0.2s; }
.form-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(255, 211, 105, 0.1); }
.form-input::placeholder { color: var(--text-muted); }
textarea.form-input { min-height: 100px; resize: vertical; }
.tags-select { display: flex; flex-wrap: wrap; gap: 8px; }
.tag-option { padding: 8px 16px; background: rgba(255,255,255,0.05); border: 1px solid var(--border); border-radius: 20px; font-size: 0.9rem; color: var(--text-secondary); cursor: pointer; transition: all 0.2s; }
.tag-option:hover { border-color: rgba(255, 211, 105, 0.3); color: var(--text); }
.tag-option.selected { background: rgba(255, 211, 105, 0.15); border-color: var(--accent); color: var(--accent); }
.modal-footer { padding: 20px 24px; border-top: 1px solid var(--border); display: flex; gap: 12px; justify-content: flex-end; }
/* Footer */
.footer { padding: 40px 48px; background: var(--bg-elevated); border-top: 1px solid var(--border); text-align: center; position: relative; z-index: 1; }
.footer p { color: var(--text-muted); font-size: 0.9rem; }
/* 响应式 */
@media (max-width: 1100px) {
.hero { flex-direction: column; padding: 100px 24px 60px; }
.hero-content { max-width: 100%; text-align: center; }
.hero-title { font-size: 2.5rem; }
.hero-buttons { justify-content: center; }
.hero-visual { padding: 50px 0 0; }
.visual-container { width: 100%; max-width: 400px; }
.float-card { display: none; }
.features-grid { grid-template-columns: 1fr; }
nav { padding: 14px 20px; }
.nav-links { display: none; }
.section { padding: 80px 24px; }
.trust-bar { padding: 40px 24px; }
.trust-container { gap: 40px; }
.step { flex-direction: column; text-align: center; }
.cta-container { padding: 40px 24px; }
}
</style>
</head>
<body>
<div class="animated-bg">
<div class="glow glow-1"></div>
<div class="glow glow-2"></div>
<div class="glow glow-3"></div>
<div class="grid-bg"></div>
<div class="stars" id="stars"></div>
</div>
<nav>
<div class="logo">梦语织机</div>
<ul class="nav-links">
<li><a href="#features">功能</a></li>
<li><a href="#how-it-works">使用方法</a></li>
<li><a href="#faq">常见问题</a></li>
</ul>
<button class="nav-cta" onclick="openModal()">开始创作</button>
</nav>
<!-- Hero Section -->
<section class="hero">
<div class="hero-content">
<div class="hero-badge fade-in"><span></span> 专为 3-8 岁儿童设计</div>
<h1 class="hero-title fade-in delay-1">为孩子编织<br><span class="highlight">专属的童话梦境</span></h1>
<p class="hero-desc fade-in delay-2">输入几个关键词AI 即刻为孩子创作独一无二的睡前故事。温暖的声音,精美的插画,让每个夜晚都充满想象。</p>
<div class="hero-buttons fade-in delay-3">
<button class="btn-primary" onclick="openModal()">免费开始创作</button>
<button class="btn-ghost" onclick="document.getElementById('features').scrollIntoView({behavior:'smooth'})">了解更多</button>
</div>
</div>
<div class="hero-visual fade-in-right delay-2">
<div class="visual-container">
<div class="float-card float-card-1"><div class="float-icon">🎨</div><span class="float-text">AI 生成插画</span></div>
<div class="main-card">
<div class="card-cover"><span class="card-cover-text">🐰</span></div>
<div class="card-header"><h3 class="card-title">小兔子的勇气冒险</h3><span class="card-badge">刚刚生成</span></div>
<p class="card-excerpt">在一片被晨露打湿的森林里,住着一只名叫棉花的小白兔。今天,她决定独自去森林深处...</p>
<div class="card-tags"><span class="tag">勇气</span><span class="tag">冒险</span><span class="tag">友谊</span></div>
<div class="card-actions"><button class="action-btn">🔊 播放朗读</button><button class="action-btn">🖼 生成插画</button></div>
</div>
<div class="float-card float-card-2"><div class="float-icon">🔊</div><span class="float-text">温暖语音朗读</span></div>
</div>
</div>
</section>
<!-- Trust Bar -->
<section class="trust-bar" id="trust-bar">
<div class="trust-container">
<div class="stat-item fade-in"><div class="stat-number"><span class="counter" data-target="10000">0</span><span class="accent">+</span></div><div class="stat-label">故事已创作</div></div>
<div class="stat-item fade-in delay-1"><div class="stat-number"><span class="counter" data-target="5000">0</span><span class="accent">+</span></div><div class="stat-label">家庭信赖</div></div>
<div class="stat-item fade-in delay-2"><div class="stat-number"><span class="counter" data-target="98">0</span><span class="accent">%</span></div><div class="stat-label">满意度</div></div>
</div>
</section>
<!-- Features -->
<section class="section" id="features">
<div class="features-container">
<div class="section-header"><p class="section-label fade-in">核心功能</p><h2 class="section-title fade-in delay-1">为什么选择梦语织机</h2></div>
<div class="features-grid">
<div class="feature-card fade-in-scale delay-1"><div class="feature-icon">✍️</div><h3 class="feature-title">智能创作</h3><p class="feature-desc">输入关键词或简单想法AI 即刻创作充满想象力的原创故事</p></div>
<div class="feature-card fade-in-scale delay-2"><div class="feature-icon">🧒</div><h3 class="feature-title">个性化记忆</h3><p class="feature-desc">系统记住孩子的喜好,故事越来越懂 TA</p></div>
<div class="feature-card fade-in-scale delay-3"><div class="feature-icon">🎨</div><h3 class="feature-title">精美插画</h3><p class="feature-desc">为每个故事自动生成独特的封面插画</p></div>
<div class="feature-card fade-in-scale delay-1"><div class="feature-icon">🔊</div><h3 class="feature-title">温暖朗读</h3><p class="feature-desc">专业配音,陪伴孩子进入甜美梦乡</p></div>
<div class="feature-card fade-in-scale delay-2"><div class="feature-icon">📚</div><h3 class="feature-title">教育主题</h3><p class="feature-desc">勇气、友谊、分享...自然传递正向价值观</p></div>
<div class="feature-card fade-in-scale delay-3"><div class="feature-icon">🌍</div><h3 class="feature-title">故事宇宙</h3><p class="feature-desc">创建专属世界观,角色可在不同故事中复用</p></div>
</div>
</div>
</section>
<!-- How It Works -->
<section class="section" id="how-it-works">
<div class="steps-container">
<div class="section-header"><p class="section-label fade-in">使用方法</p><h2 class="section-title fade-in delay-1">简单三步,创造专属故事</h2></div>
<div class="steps">
<div class="step fade-in-left delay-1"><div class="step-number">1</div><div class="step-content"><h3>输入灵感</h3><p>几个关键词或简单想法,比如"勇敢的小兔子在森林里冒险"</p></div></div>
<div class="step fade-in-right delay-2"><div class="step-number">2</div><div class="step-content"><h3>AI 创作</h3><p>AI 即刻理解并创作充满想象力的原创故事,还能生成精美插画</p></div></div>
<div class="step fade-in-left delay-3"><div class="step-number">3</div><div class="step-content"><h3>温暖朗读</h3><p>选择喜欢的声音,让温暖的朗读陪伴孩子进入甜美梦乡</p></div></div>
</div>
</div>
</section>
<!-- FAQ -->
<section class="section" id="faq">
<div class="faq-container">
<div class="section-header"><p class="section-label fade-in">常见问题</p><h2 class="section-title fade-in delay-1">你可能想知道</h2></div>
<div class="faq-list">
<div class="faq-item fade-in delay-1"><button class="faq-question" onclick="toggleFaq(this)"><span>梦语织机适合多大的孩子?</span><span class="faq-icon"></span></button><div class="faq-answer-wrapper"><div class="faq-answer"><div class="faq-answer-content">梦语织机专为 3-8 岁儿童设计。我们的故事内容、语言难度和主题都经过精心调整,确保适合这个年龄段孩子的认知发展水平。</div></div></div></div>
<div class="faq-item fade-in delay-2"><button class="faq-question" onclick="toggleFaq(this)"><span>生成的故事内容安全吗?</span><span class="faq-icon"></span></button><div class="faq-answer-wrapper"><div class="faq-answer"><div class="faq-answer-content">绝对安全。所有生成的故事都经过多层内容审核,确保不包含任何不适合儿童的内容。我们的 AI 模型经过专门训练,只会生成积极、正向、富有教育意义的故事内容。</div></div></div></div>
<div class="faq-item fade-in delay-3"><button class="faq-question" onclick="toggleFaq(this)"><span>可以自定义故事的主角吗?</span><span class="faq-icon"></span></button><div class="faq-answer-wrapper"><div class="faq-answer"><div class="faq-answer-content">当然可以您可以输入孩子喜欢的角色名称、特征甚至可以把孩子自己设定为故事主角。AI 会根据您的输入创作独一无二的个性化故事。</div></div></div></div>
<div class="faq-item fade-in delay-4"><button class="faq-question" onclick="toggleFaq(this)"><span>免费版和付费版有什么区别?</span><span class="faq-icon"></span></button><div class="faq-answer-wrapper"><div class="faq-answer"><div class="faq-answer-content">免费版每月可生成 5 个故事包含基础的语音朗读功能。付费版提供无限故事生成、高级语音选择、AI 插画生成、故事导出等更多功能。</div></div></div></div>
</div>
</div>
</section>
<!-- CTA -->
<section class="section cta">
<div class="cta-container fade-in-scale">
<h2 class="cta-title">准备好为孩子创造魔法了吗?</h2>
<p class="cta-desc">免费开始,无需信用卡</p>
<button class="btn-primary" onclick="openModal()">立即开始创作</button>
</div>
</section>
<!-- Footer -->
<footer class="footer">
<p>© 2024 梦语织机 DreamWeaver. All rights reserved.</p>
</footer>
<!-- 创作模态框 -->
<div class="modal-overlay" id="createModal" onclick="closeModalOnOverlay(event)">
<div class="modal">
<div class="modal-header"><h2 class="modal-title">创作新故事</h2><button class="modal-close" onclick="closeModal()">×</button></div>
<div class="modal-body">
<div class="form-group"><label class="form-label">故事主角</label><input type="text" class="form-input" placeholder="例如:小兔子、勇敢的公主..."></div>
<div class="form-group"><label class="form-label">故事场景</label><input type="text" class="form-input" placeholder="例如:魔法森林、星空下..."></div>
<div class="form-group"><label class="form-label">选择主题</label><div class="tags-select"><span class="tag-option" onclick="toggleTag(this)">勇气</span><span class="tag-option" onclick="toggleTag(this)">友谊</span><span class="tag-option" onclick="toggleTag(this)">冒险</span><span class="tag-option" onclick="toggleTag(this)">分享</span><span class="tag-option" onclick="toggleTag(this)">成长</span></div></div>
<div class="form-group"><label class="form-label">额外要求(可选)</label><textarea class="form-input" placeholder="任何特殊要求..."></textarea></div>
</div>
<div class="modal-footer"><button class="btn-ghost" onclick="closeModal()">取消</button><button class="btn-primary">开始创作 ✨</button></div>
</div>
</div>
<script>
// 生成星星
const starsContainer = document.getElementById('stars');
for (let i = 0; i < 50; i++) {
const star = document.createElement('div');
star.className = 'star';
star.style.left = Math.random() * 100 + '%';
star.style.top = Math.random() * 100 + '%';
star.style.animationDelay = Math.random() * 3 + 's';
star.style.animationDuration = (2 + Math.random() * 2) + 's';
starsContainer.appendChild(star);
}
// 滚动动画
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) entry.target.classList.add('visible');
});
}, { threshold: 0.15 });
document.querySelectorAll('.fade-in, .fade-in-left, .fade-in-right, .fade-in-scale').forEach(el => observer.observe(el));
// 数字计数动画
function easeOutQuart(t) { return 1 - Math.pow(1 - t, 4); }
function animateCounter(el, target, duration = 2000) {
const start = performance.now();
function update(now) {
const progress = Math.min((now - start) / duration, 1);
el.textContent = Math.floor(target * easeOutQuart(progress)).toLocaleString();
if (progress < 1) requestAnimationFrame(update);
}
requestAnimationFrame(update);
}
const counterObserver = new IntersectionObserver((entries, obs) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.querySelectorAll('.counter').forEach((c, i) => {
setTimeout(() => animateCounter(c, parseInt(c.dataset.target)), i * 200);
});
obs.unobserve(entry.target);
}
});
}, { threshold: 0.3 });
document.querySelectorAll('#trust-bar').forEach(el => counterObserver.observe(el));
// FAQ 手风琴
function toggleFaq(btn) { btn.closest('.faq-item').classList.toggle('active'); }
// 模态框
let lastFocus = null;
function openModal() {
lastFocus = document.activeElement;
document.getElementById('createModal').classList.add('active');
document.body.style.overflow = 'hidden';
setTimeout(() => document.querySelector('.modal .form-input')?.focus(), 100);
}
function closeModal() {
document.getElementById('createModal').classList.remove('active');
document.body.style.overflow = '';
lastFocus?.focus();
}
function closeModalOnOverlay(e) { if (e.target.classList.contains('modal-overlay')) closeModal(); }
function toggleTag(el) { el.classList.toggle('selected'); }
document.addEventListener('keydown', e => { if (e.key === 'Escape') closeModal(); });
</script>
</body>
</html>