1511 lines
40 KiB
Vue
1511 lines
40 KiB
Vue
<script setup>
|
||
import { ref, onMounted, onUnmounted } from "vue";
|
||
import { useRouter } from "vue-router";
|
||
import { LISTENING_AUDIO_URL } from "@/config/index.js";
|
||
|
||
const router = useRouter();
|
||
|
||
// 所有功能数据
|
||
const allFeatures = ref([
|
||
{
|
||
id: 1,
|
||
title: "听力考试音频生成",
|
||
desc: "输入听力文本或上传Word,一键调用 AI 合成标准英语考试音频",
|
||
class: "card-1",
|
||
icon: "audio",
|
||
url: LISTENING_AUDIO_URL,
|
||
},
|
||
{
|
||
id: 2,
|
||
title: "口语对话练习",
|
||
desc: "五大场景 AI 外教实时对话,每条回复自动语音朗读",
|
||
class: "card-2",
|
||
icon: "mic",
|
||
route: "/speaking",
|
||
},
|
||
{
|
||
id: 3,
|
||
title: "作文原图批改",
|
||
desc: "上传手写英语作文图片,AI 自动标注语法、拼写及表达问题",
|
||
class: "card-3",
|
||
icon: "edit",
|
||
route: "/essay-correction",
|
||
},
|
||
{
|
||
id: 4,
|
||
title: "英语试题AI分析",
|
||
desc: "五维度全面拆解每道英语题目,流式输出详细解析",
|
||
class: "card-4",
|
||
icon: "analytics",
|
||
route: "/exam-analysis",
|
||
},
|
||
{
|
||
id: 5,
|
||
title: "单词听写",
|
||
desc: "自适应发音报词,智能追踪拼写薄弱点",
|
||
class: "card-5",
|
||
icon: "spell",
|
||
route: "/spell-practice",
|
||
},
|
||
{
|
||
id: 6,
|
||
title: "英语发音",
|
||
desc: "36 种音色自由选择,一键合成标准发音",
|
||
class: "card-6",
|
||
icon: "speaker",
|
||
route: "/pronunciation",
|
||
},
|
||
{
|
||
id: 7,
|
||
title: "AI引导解题",
|
||
desc: "对话式引导思考,卡片式展示解题步骤",
|
||
class: "card-7",
|
||
icon: "puzzle",
|
||
route: "/problem-solving",
|
||
},
|
||
{
|
||
id: 8,
|
||
title: "AI试题生成",
|
||
desc: "自定义难度、数量和知识点,快速创建题库",
|
||
class: "card-8",
|
||
icon: "document",
|
||
route: "/question-generator",
|
||
},
|
||
{
|
||
id: 9,
|
||
title: "题目变式生成",
|
||
desc: "AI 深度分析生成同类变式题,快速扩展题库",
|
||
class: "card-9",
|
||
icon: "variant",
|
||
route: "/question-variant",
|
||
},
|
||
{
|
||
id: 10,
|
||
title: "音频转文字",
|
||
desc: "支持中英日多语种,适用于会议记录、采访整理",
|
||
class: "card-10",
|
||
icon: "file-audio",
|
||
route: "/audio-to-text",
|
||
},
|
||
{
|
||
id: 11,
|
||
title: "听读评测",
|
||
desc: "AI智能评测发音准确度,提供错误标注和改进建议",
|
||
class: "card-12",
|
||
icon: "mic",
|
||
route: "/speaking-evaluation",
|
||
},
|
||
]);
|
||
|
||
// 统计数据
|
||
const stats = ref([
|
||
{ value: "11+", label: "AI 学习工具" },
|
||
{ value: "100万+", label: "服务学习者" },
|
||
{ value: "36", label: "发音音色" },
|
||
{ value: "24/7", label: "AI 在线" },
|
||
]);
|
||
|
||
// 垂直翻页当前页码
|
||
const currentPage = ref(0);
|
||
const totalPages = 2;
|
||
|
||
// 横向滚动当前页码
|
||
const currentHorizontalPage = ref(0);
|
||
const totalHorizontalPages = 2; // 每页6个卡片,11个功能需要2页
|
||
|
||
// 滚动到指定垂直页面
|
||
const scrollToPage = (pageIndex) => {
|
||
if (pageIndex < 0 || pageIndex >= totalPages) return;
|
||
const container = document.querySelector(".snap-container");
|
||
if (container) {
|
||
container.scrollTo({
|
||
top: pageIndex * window.innerHeight,
|
||
behavior: "smooth",
|
||
});
|
||
}
|
||
};
|
||
|
||
// 滚动到功能区域(第二页)
|
||
const scrollToFeatures = () => {
|
||
scrollToPage(1);
|
||
};
|
||
|
||
// 横向滚动到指定页
|
||
const scrollToHorizontalPage = (pageIndex) => {
|
||
if (pageIndex < 0 || pageIndex >= totalHorizontalPages) return;
|
||
const container = document.querySelector(".horizontal-scroll-container");
|
||
if (container) {
|
||
const pageWidth = container.clientWidth;
|
||
container.scrollTo({
|
||
left: pageIndex * pageWidth,
|
||
behavior: "smooth",
|
||
});
|
||
currentHorizontalPage.value = pageIndex;
|
||
}
|
||
};
|
||
|
||
// 处理功能卡片点击
|
||
const handleCardClick = (feature) => {
|
||
if (feature.url) {
|
||
window.open(feature.url, "_blank");
|
||
} else if (feature.route) {
|
||
router.push(feature.route);
|
||
}
|
||
};
|
||
|
||
// 鼠标跟随光效
|
||
const handleMouseMove = (e) => {
|
||
const cards = document.querySelectorAll(".feature-card");
|
||
for (const card of cards) {
|
||
const rect = card.getBoundingClientRect();
|
||
const x = e.clientX - rect.left;
|
||
const y = e.clientY - rect.top;
|
||
card.style.setProperty("--mouse-x", `${x}px`);
|
||
card.style.setProperty("--mouse-y", `${y}px`);
|
||
}
|
||
};
|
||
|
||
// 监听垂直滚动更新当前页码
|
||
const handleScroll = () => {
|
||
const container = document.querySelector(".snap-container");
|
||
if (container) {
|
||
const scrollTop = container.scrollTop;
|
||
const pageHeight = window.innerHeight;
|
||
currentPage.value = Math.round(scrollTop / pageHeight);
|
||
}
|
||
};
|
||
|
||
// 监听横向滚动更新当前页码
|
||
const handleHorizontalScroll = () => {
|
||
const container = document.querySelector(".horizontal-scroll-container");
|
||
if (container) {
|
||
const scrollLeft = container.scrollLeft;
|
||
const pageWidth = container.clientWidth;
|
||
currentHorizontalPage.value = Math.round(scrollLeft / pageWidth);
|
||
}
|
||
};
|
||
|
||
// 键盘导航
|
||
const handleKeyDown = (e) => {
|
||
if (currentPage.value === 1) {
|
||
// 在第二页时,左右键控制横向滚动
|
||
if (e.key === "ArrowRight") {
|
||
e.preventDefault();
|
||
scrollToHorizontalPage(currentHorizontalPage.value + 1);
|
||
return;
|
||
} else if (e.key === "ArrowLeft") {
|
||
e.preventDefault();
|
||
scrollToHorizontalPage(currentHorizontalPage.value - 1);
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (e.key === "ArrowDown" || e.key === "PageDown") {
|
||
e.preventDefault();
|
||
scrollToPage(currentPage.value + 1);
|
||
} else if (e.key === "ArrowUp" || e.key === "PageUp") {
|
||
e.preventDefault();
|
||
scrollToPage(currentPage.value - 1);
|
||
}
|
||
};
|
||
|
||
// 垂直滚轮翻页控制
|
||
let wheelTimeout = null;
|
||
const handleWheel = (e) => {
|
||
// 如果在第二页且横向滚动容器存在,检查是否在容器内
|
||
if (currentPage.value === 1) {
|
||
const horizontalContainer = document.querySelector(".horizontal-scroll-container");
|
||
if (horizontalContainer) {
|
||
// 让横向滚动容器自己处理滚轮事件
|
||
return;
|
||
}
|
||
}
|
||
|
||
e.preventDefault();
|
||
if (wheelTimeout) return;
|
||
|
||
wheelTimeout = setTimeout(() => {
|
||
wheelTimeout = null;
|
||
}, 800);
|
||
|
||
if (e.deltaY > 0) {
|
||
scrollToPage(currentPage.value + 1);
|
||
} else if (e.deltaY < 0) {
|
||
scrollToPage(currentPage.value - 1);
|
||
}
|
||
};
|
||
|
||
// 横向滚轮处理
|
||
const handleHorizontalWheel = (e) => {
|
||
e.preventDefault();
|
||
if (e.deltaY > 0 || e.deltaX > 0) {
|
||
scrollToHorizontalPage(currentHorizontalPage.value + 1);
|
||
} else if (e.deltaY < 0 || e.deltaX < 0) {
|
||
scrollToHorizontalPage(currentHorizontalPage.value - 1);
|
||
}
|
||
};
|
||
|
||
// 触摸滑动支持
|
||
let touchStartX = 0;
|
||
let touchStartY = 0;
|
||
let touchStartTime = 0;
|
||
let isTouching = false;
|
||
|
||
const handleTouchStart = (e) => {
|
||
touchStartX = e.touches[0].clientX;
|
||
touchStartY = e.touches[0].clientY;
|
||
touchStartTime = Date.now();
|
||
isTouching = true;
|
||
};
|
||
|
||
const handleTouchMove = (e) => {
|
||
if (!isTouching) return;
|
||
// 阻止默认行为防止页面滚动冲突
|
||
const touchX = e.touches[0].clientX;
|
||
const touchY = e.touches[0].clientY;
|
||
const deltaX = Math.abs(touchX - touchStartX);
|
||
const deltaY = Math.abs(touchY - touchStartY);
|
||
|
||
// 在功能区域(第2页)优先处理水平滑动
|
||
if (currentPage.value === 1 && deltaX > deltaY && deltaX > 10) {
|
||
e.preventDefault();
|
||
}
|
||
};
|
||
|
||
const handleTouchEnd = (e) => {
|
||
if (!isTouching) return;
|
||
isTouching = false;
|
||
|
||
const touchEndX = e.changedTouches[0].clientX;
|
||
const touchEndY = e.changedTouches[0].clientY;
|
||
const touchEndTime = Date.now();
|
||
|
||
const deltaX = touchStartX - touchEndX;
|
||
const deltaY = touchStartY - touchEndY;
|
||
const deltaTime = touchEndTime - touchStartTime;
|
||
|
||
// 快速滑动检测(250ms内)
|
||
const isQuickSwipe = deltaTime < 250;
|
||
const threshold = isQuickSwipe ? 25 : 60;
|
||
|
||
// 判断是水平滑动还是垂直滑动
|
||
if (Math.abs(deltaX) > Math.abs(deltaY)) {
|
||
// 水平滑动 - 控制横向滚动
|
||
if (Math.abs(deltaX) > threshold) {
|
||
if (deltaX > 0) {
|
||
scrollToHorizontalPage(currentHorizontalPage.value + 1);
|
||
} else {
|
||
scrollToHorizontalPage(currentHorizontalPage.value - 1);
|
||
}
|
||
}
|
||
} else {
|
||
// 垂直滑动 - 控制页面翻页(仅在非横向滚动区域)
|
||
if (Math.abs(deltaY) > threshold && currentPage.value !== 1) {
|
||
if (deltaY > 0) {
|
||
scrollToPage(currentPage.value + 1);
|
||
} else {
|
||
scrollToPage(currentPage.value - 1);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
// 横向滚动容器触摸处理
|
||
const handleHorizontalTouchStart = (e) => {
|
||
touchStartX = e.touches[0].clientX;
|
||
touchStartTime = Date.now();
|
||
};
|
||
|
||
const handleHorizontalTouchEnd = (e) => {
|
||
const touchEndX = e.changedTouches[0].clientX;
|
||
const deltaTime = Date.now() - touchStartTime;
|
||
const deltaX = touchStartX - touchEndX;
|
||
|
||
const isQuickSwipe = deltaTime < 300;
|
||
const threshold = isQuickSwipe ? 30 : 60;
|
||
|
||
if (Math.abs(deltaX) > threshold) {
|
||
if (deltaX > 0) {
|
||
scrollToHorizontalPage(currentHorizontalPage.value + 1);
|
||
} else {
|
||
scrollToHorizontalPage(currentHorizontalPage.value - 1);
|
||
}
|
||
}
|
||
};
|
||
|
||
onMounted(() => {
|
||
const container = document.querySelector(".snap-container");
|
||
if (container) {
|
||
container.addEventListener("scroll", handleScroll);
|
||
container.addEventListener("wheel", handleWheel, { passive: false });
|
||
container.addEventListener("touchstart", handleTouchStart, { passive: true });
|
||
container.addEventListener("touchmove", handleTouchMove, { passive: false });
|
||
container.addEventListener("touchend", handleTouchEnd, { passive: true });
|
||
}
|
||
window.addEventListener("keydown", handleKeyDown);
|
||
|
||
const page2 = document.querySelector(".page-2");
|
||
if (page2) {
|
||
page2.addEventListener("mousemove", handleMouseMove);
|
||
}
|
||
|
||
const horizontalContainer = document.querySelector(".horizontal-scroll-container");
|
||
if (horizontalContainer) {
|
||
horizontalContainer.addEventListener("scroll", handleHorizontalScroll);
|
||
horizontalContainer.addEventListener("touchstart", handleHorizontalTouchStart, { passive: true });
|
||
horizontalContainer.addEventListener("touchend", handleHorizontalTouchEnd, { passive: true });
|
||
}
|
||
});
|
||
|
||
onUnmounted(() => {
|
||
const container = document.querySelector(".snap-container");
|
||
if (container) {
|
||
container.removeEventListener("scroll", handleScroll);
|
||
container.removeEventListener("wheel", handleWheel);
|
||
container.removeEventListener("touchstart", handleTouchStart);
|
||
container.removeEventListener("touchmove", handleTouchMove);
|
||
container.removeEventListener("touchend", handleTouchEnd);
|
||
}
|
||
window.removeEventListener("keydown", handleKeyDown);
|
||
|
||
const page2 = document.querySelector(".page-2");
|
||
if (page2) {
|
||
page2.removeEventListener("mousemove", handleMouseMove);
|
||
}
|
||
|
||
const horizontalContainer = document.querySelector(".horizontal-scroll-container");
|
||
if (horizontalContainer) {
|
||
horizontalContainer.removeEventListener("scroll", handleHorizontalScroll);
|
||
horizontalContainer.removeEventListener("touchstart", handleHorizontalTouchStart);
|
||
horizontalContainer.removeEventListener("touchend", handleHorizontalTouchEnd);
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<div class="landing-wrapper">
|
||
<!-- 背景 -->
|
||
<div class="landing-bg">
|
||
<div class="bg-gradient"></div>
|
||
<div class="bg-grid"></div>
|
||
</div>
|
||
|
||
<!-- 导航栏 -->
|
||
<nav class="landing-nav">
|
||
<div class="nav-brand">
|
||
<div class="brand-icon">
|
||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M9.813 15.904L9 18.75l-.813-2.846a4.5 4.5 0 00-3.09-3.09L2.25 12l2.846-.813a4.5 4.5 0 003.09-3.09L9 5.25l.813 2.846a4.5 4.5 0 003.09 3.09L15.75 12l-2.846.813a4.5 4.5 0 00-3.09 3.09zM18.259 8.715L18 9.75l-.259-1.035a3.375 3.375 0 00-2.455-2.456L14.25 6l1.036-.259a3.375 3.375 0 002.455-2.456L18 2.25l.259 1.035a3.375 3.375 0 002.456 2.456L21.75 6l-1.035.259a3.375 3.375 0 00-2.456 2.456zM16.894 20.567L16.5 21.75l-.394-1.183a2.25 2.25 0 00-1.423-1.423L13.5 18.75l1.183-.394a2.25 2.25 0 001.423-1.423l.394-1.183.394 1.183a2.25 2.25 0 001.423 1.423l1.183.394-1.183.394a2.25 2.25 0 00-1.423 1.423z" />
|
||
</svg>
|
||
</div>
|
||
<span class="brand-text">AI English</span>
|
||
</div>
|
||
</nav>
|
||
|
||
<!-- 翻页指示器 -->
|
||
<div class="page-indicator">
|
||
<div
|
||
v-for="page in totalPages"
|
||
:key="page"
|
||
class="indicator-dot"
|
||
:class="{ active: currentPage === page - 1 }"
|
||
@click="scrollToPage(page - 1)"
|
||
></div>
|
||
</div>
|
||
|
||
<!-- 翻页滚动容器 -->
|
||
<div class="snap-container">
|
||
<!-- 第一页:Hero Section -->
|
||
<section class="snap-page page-1">
|
||
<div class="page-content">
|
||
<div class="hero-badge">
|
||
<span class="badge-dot"></span>
|
||
全新 AI 驱动的英语学习平台
|
||
</div>
|
||
<h1 class="hero-title">
|
||
让 AI 成为你的
|
||
<span class="gradient-text">专属英语教练</span>
|
||
</h1>
|
||
<p class="hero-subtitle">
|
||
11+ 智能学习工具,覆盖听说读写全场景。从口语对话到作文批改,<br>
|
||
从试题分析到智能评测,全方位提升你的英语能力。
|
||
</p>
|
||
<div class="hero-cta">
|
||
<button class="cta-button primary" @click="scrollToFeatures">
|
||
开始探索
|
||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- 统计数据 -->
|
||
<div class="hero-stats">
|
||
<div v-for="stat in stats" :key="stat.label" class="stat-item">
|
||
<div class="stat-value">{{ stat.value }}</div>
|
||
<div class="stat-label">{{ stat.label }}</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 向下滚动提示 -->
|
||
<div class="scroll-hint" @click="scrollToFeatures">
|
||
<span>向下滚动</span>
|
||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
|
||
</svg>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 第二页:功能区域 -->
|
||
<section class="snap-page page-2">
|
||
<div class="page-content">
|
||
<div class="section-header">
|
||
<h2 class="section-title">全部功能</h2>
|
||
<p class="section-subtitle">11+ AI 驱动的英语学习工具</p>
|
||
</div>
|
||
|
||
<!-- 横向滚动容器 -->
|
||
<div class="horizontal-scroll-wrapper">
|
||
<div
|
||
class="horizontal-scroll-container"
|
||
@wheel="handleHorizontalWheel"
|
||
>
|
||
<div class="horizontal-page">
|
||
<div class="features-grid">
|
||
<div
|
||
v-for="feature in allFeatures.slice(0, 6)"
|
||
:key="feature.id"
|
||
@click="handleCardClick(feature)"
|
||
class="feature-card"
|
||
:class="feature.class"
|
||
>
|
||
<div class="card-content">
|
||
<div class="icon-wrapper">
|
||
<svg v-if="feature.icon === 'audio'" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 21a9.004 9.004 0 0 0 8.716-6.747M12 21a9.004 9.004 0 0 1-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 0 1 7.843 4.582M12 3a8.997 8.997 0 0 0-7.843 4.582m15.686 0A11.953 11.953 0 0 1 12 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0 1 21 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0 1 12 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 0 1 3 12c0-1.605.42-3.113 1.157-4.418" />
|
||
</svg>
|
||
<svg v-else-if="feature.icon === 'mic'" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 18.75a6 6 0 0 0 6-6v-1.5m-6 7.5a6 6 0 0 1-6-6v-1.5m6 7.5v3.75m-3.75 0h7.5M12 15.75a3 3 0 0 1-3-3V4.5a3 3 0 1 1 6 0v8.25a3 3 0 0 1-3 3Z" />
|
||
</svg>
|
||
<svg v-else-if="feature.icon === 'edit'" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" />
|
||
</svg>
|
||
<svg v-else-if="feature.icon === 'analytics'" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z" />
|
||
</svg>
|
||
<svg v-else-if="feature.icon === 'spell'" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6.042A8.967 8.967 0 0 0 6 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 0 1 6 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 0 1 6-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0 0 18 18a8.967 8.967 0 0 0-6 2.292m0-14.25v14.25" />
|
||
</svg>
|
||
<svg v-else-if="feature.icon === 'speaker'" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M19.114 5.636a9 9 0 0 1 0 12.728M16.463 8.288a5.25 5.25 0 0 1 0 7.424M6.75 8.25l4.72-4.72a.75.75 0 0 1 1.28.53v15.88a.75.75 0 0 1-1.28.53l-4.72-4.72H4.51c-.88 0-1.704-.507-1.938-1.354A9.009 9.009 0 0 1 2.25 12c0-.83.112-1.633.322-2.396C2.806 8.756 3.63 8.25 4.51 8.25H6.75Z" />
|
||
</svg>
|
||
</div>
|
||
<h3 class="card-title">{{ feature.title }}</h3>
|
||
<p class="card-desc">{{ feature.desc }}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="horizontal-page">
|
||
<div class="features-grid">
|
||
<div
|
||
v-for="feature in allFeatures.slice(6, 11)"
|
||
:key="feature.id"
|
||
@click="handleCardClick(feature)"
|
||
class="feature-card"
|
||
:class="feature.class"
|
||
>
|
||
<div class="card-content">
|
||
<div class="icon-wrapper">
|
||
<svg v-if="feature.icon === 'puzzle'" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||
</svg>
|
||
<svg v-else-if="feature.icon === 'document'" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z" />
|
||
</svg>
|
||
<svg v-else-if="feature.icon === 'variant'" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 0 1-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 0 1 1.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876v9.004c0 .621-.504 1.125-1.125 1.125h-3.75c-.621 0-1.125.504-1.125 1.125v3.876c0 .621.504 1.125 1.125 1.125h3.75c.621 0 1.125-.504 1.125-1.125Z" />
|
||
</svg>
|
||
<svg v-else-if="feature.icon === 'file-audio'" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" />
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M11.25 12.75l2.25-1.5v4.5l-2.25-1.5v-1.5z" />
|
||
</svg>
|
||
<svg v-else-if="feature.icon === 'mic'" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 18.75a6 6 0 0 0 6-6v-1.5m-6 7.5a6 6 0 0 1-6-6v-1.5m6 7.5v3.75m-3.75 0h7.5M12 15.75a3 3 0 0 1-3-3V4.5a3 3 0 1 1 6 0v8.25a3 3 0 0 1-3 3Z" />
|
||
</svg>
|
||
</div>
|
||
<h3 class="card-title">{{ feature.title }}</h3>
|
||
<p class="card-desc">{{ feature.desc }}</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 横向滚动指示器 -->
|
||
<div class="horizontal-indicator">
|
||
<div
|
||
v-for="page in totalHorizontalPages"
|
||
:key="page"
|
||
class="h-indicator-dot"
|
||
:class="{ active: currentHorizontalPage === page - 1 }"
|
||
@click="scrollToHorizontalPage(page - 1)"
|
||
></div>
|
||
</div>
|
||
|
||
<!-- 横向滚动箭头 -->
|
||
<button
|
||
v-if="currentHorizontalPage > 0"
|
||
class="scroll-arrow scroll-arrow-left"
|
||
@click="scrollToHorizontalPage(currentHorizontalPage - 1)"
|
||
>
|
||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
|
||
</svg>
|
||
</button>
|
||
<button
|
||
v-if="currentHorizontalPage < totalHorizontalPages - 1"
|
||
class="scroll-arrow scroll-arrow-right"
|
||
@click="scrollToHorizontalPage(currentHorizontalPage + 1)"
|
||
>
|
||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
|
||
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Footer -->
|
||
<footer class="landing-footer">
|
||
<p>AI 英语学习辅助平台 · 让学习更智能</p>
|
||
</footer>
|
||
</section>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
/* ========== 基础布局 ========== */
|
||
.landing-wrapper {
|
||
height: 100vh;
|
||
width: 100vw;
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
color: #f8fafc;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* ========== 翻页滚动容器 ========== */
|
||
.snap-container {
|
||
height: 100vh;
|
||
width: 100vw;
|
||
overflow-y: scroll;
|
||
scroll-snap-type: y mandatory;
|
||
scroll-behavior: smooth;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
.snap-container::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
.snap-page {
|
||
height: 100vh;
|
||
width: 100vw;
|
||
scroll-snap-align: start;
|
||
scroll-snap-stop: always;
|
||
display: flex;
|
||
flex-direction: column;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.page-content {
|
||
width: 100%;
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
padding: 0 2rem;
|
||
box-sizing: border-box;
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* ========== 翻页指示器 ========== */
|
||
.page-indicator {
|
||
position: fixed;
|
||
right: 2rem;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
z-index: 100;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.indicator-dot {
|
||
width: 10px;
|
||
height: 10px;
|
||
border-radius: 50%;
|
||
background: rgba(255, 255, 255, 0.2);
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
border: 2px solid transparent;
|
||
}
|
||
|
||
.indicator-dot:hover {
|
||
background: rgba(255, 255, 255, 0.4);
|
||
}
|
||
|
||
.indicator-dot.active {
|
||
background: linear-gradient(135deg, #6366f1, #8b5cf6);
|
||
border-color: rgba(255, 255, 255, 0.3);
|
||
transform: scale(1.2);
|
||
}
|
||
|
||
/* ========== 向下滚动提示 ========== */
|
||
.scroll-hint {
|
||
position: absolute;
|
||
bottom: 2rem;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
color: #64748b;
|
||
font-size: 0.875rem;
|
||
cursor: pointer;
|
||
animation: bounce 2s infinite;
|
||
z-index: 10;
|
||
}
|
||
|
||
.scroll-hint svg {
|
||
width: 24px;
|
||
height: 24px;
|
||
}
|
||
|
||
@keyframes bounce {
|
||
0%, 20%, 50%, 80%, 100% {
|
||
transform: translateX(-50%) translateY(0);
|
||
}
|
||
40% {
|
||
transform: translateX(-50%) translateY(-10px);
|
||
}
|
||
60% {
|
||
transform: translateX(-50%) translateY(-5px);
|
||
}
|
||
}
|
||
|
||
/* ========== 背景 ========== */
|
||
.landing-bg {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100vw;
|
||
height: 100vh;
|
||
z-index: 0;
|
||
overflow: hidden;
|
||
background: #0f172a;
|
||
}
|
||
|
||
.bg-gradient {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background:
|
||
radial-gradient(ellipse 80% 50% at 50% -20%, rgba(99, 102, 241, 0.15), transparent),
|
||
radial-gradient(ellipse 60% 40% at 80% 50%, rgba(139, 92, 246, 0.1), transparent),
|
||
radial-gradient(ellipse 50% 30% at 20% 80%, rgba(236, 72, 153, 0.08), transparent);
|
||
}
|
||
|
||
.bg-grid {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background-image:
|
||
linear-gradient(rgba(255, 255, 255, 0.02) 1px, transparent 1px),
|
||
linear-gradient(90deg, rgba(255, 255, 255, 0.02) 1px, transparent 1px);
|
||
background-size: 60px 60px;
|
||
mask-image: linear-gradient(to bottom, transparent 0%, black 20%, black 80%, transparent 100%);
|
||
}
|
||
|
||
/* ========== 导航栏 ========== */
|
||
.landing-nav {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 100;
|
||
padding: 1rem 2rem;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
background: rgba(15, 23, 42, 0.8);
|
||
backdrop-filter: blur(12px);
|
||
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
||
}
|
||
|
||
.nav-brand {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.brand-icon {
|
||
width: 36px;
|
||
height: 36px;
|
||
background: linear-gradient(135deg, #6366f1, #8b5cf6);
|
||
border-radius: 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: white;
|
||
}
|
||
|
||
.brand-icon svg {
|
||
width: 22px;
|
||
height: 22px;
|
||
}
|
||
|
||
.brand-text {
|
||
font-size: 1.25rem;
|
||
font-weight: 700;
|
||
background: linear-gradient(135deg, #fff 0%, #a5b4fc 100%);
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
}
|
||
|
||
/* ========== Hero Section ========== */
|
||
.page-1 .page-content {
|
||
justify-content: center;
|
||
align-items: center;
|
||
text-align: center;
|
||
padding-top: 5rem;
|
||
padding-bottom: 6rem;
|
||
}
|
||
|
||
/* Hero 区域移动端优化 */
|
||
@media (max-width: 640px) {
|
||
.page-1 .page-content {
|
||
padding-top: 4rem;
|
||
padding-bottom: 4rem;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.hero-badge {
|
||
font-size: 0.75rem;
|
||
padding: 0.375rem 0.75rem;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.hero-title {
|
||
font-size: clamp(1.75rem, 8vw, 2.5rem);
|
||
line-height: 1.2;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.hero-subtitle {
|
||
font-size: 0.875rem;
|
||
line-height: 1.6;
|
||
margin-bottom: 1.5rem;
|
||
padding: 0 0.5rem;
|
||
}
|
||
|
||
.hero-subtitle br {
|
||
display: none;
|
||
}
|
||
|
||
.hero-cta {
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.cta-button {
|
||
padding: 0.875rem 1.5rem;
|
||
font-size: 0.9375rem;
|
||
}
|
||
|
||
.hero-stats {
|
||
gap: 1rem;
|
||
padding: 1rem 1.25rem;
|
||
border-radius: 16px;
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 1.25rem;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 0.75rem;
|
||
}
|
||
}
|
||
|
||
.hero-badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
padding: 0.5rem 1rem;
|
||
background: rgba(99, 102, 241, 0.1);
|
||
border: 1px solid rgba(99, 102, 241, 0.2);
|
||
border-radius: 9999px;
|
||
font-size: 0.875rem;
|
||
color: #a5b4fc;
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.badge-dot {
|
||
width: 8px;
|
||
height: 8px;
|
||
background: #10b981;
|
||
border-radius: 50%;
|
||
animation: pulse 2s infinite;
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0%, 100% { opacity: 1; }
|
||
50% { opacity: 0.5; }
|
||
}
|
||
|
||
.hero-title {
|
||
font-size: clamp(2.5rem, 6vw, 4.5rem);
|
||
font-weight: 800;
|
||
letter-spacing: -0.03em;
|
||
line-height: 1.1;
|
||
margin: 0 0 1.5rem;
|
||
color: #fff;
|
||
}
|
||
|
||
.gradient-text {
|
||
background: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #ec4899 100%);
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
}
|
||
|
||
.hero-subtitle {
|
||
font-size: 1.125rem;
|
||
color: #94a3b8;
|
||
line-height: 1.8;
|
||
max-width: 600px;
|
||
margin: 0 0 2.5rem;
|
||
}
|
||
|
||
.hero-cta {
|
||
display: flex;
|
||
gap: 1rem;
|
||
margin-bottom: 4rem;
|
||
}
|
||
|
||
.cta-button {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
padding: 1rem 2rem;
|
||
font-size: 1rem;
|
||
font-weight: 600;
|
||
border-radius: 12px;
|
||
border: none;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.cta-button.primary {
|
||
background: linear-gradient(135deg, #6366f1, #8b5cf6);
|
||
color: white;
|
||
box-shadow: 0 10px 30px -10px rgba(99, 102, 241, 0.5);
|
||
}
|
||
|
||
.cta-button.primary:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 15px 40px -10px rgba(99, 102, 241, 0.6);
|
||
}
|
||
|
||
.cta-button svg {
|
||
width: 20px;
|
||
height: 20px;
|
||
transition: transform 0.3s ease;
|
||
}
|
||
|
||
.cta-button:hover svg {
|
||
transform: translateY(2px);
|
||
}
|
||
|
||
/* ========== Hero Stats ========== */
|
||
.hero-stats {
|
||
display: flex;
|
||
gap: 3rem;
|
||
padding: 2rem 3rem;
|
||
background: rgba(255, 255, 255, 0.02);
|
||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||
border-radius: 20px;
|
||
backdrop-filter: blur(10px);
|
||
}
|
||
|
||
.stat-item {
|
||
text-align: center;
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 2rem;
|
||
font-weight: 800;
|
||
background: linear-gradient(135deg, #fff 0%, #a5b4fc 100%);
|
||
-webkit-background-clip: text;
|
||
background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
}
|
||
|
||
.stat-label {
|
||
font-size: 0.875rem;
|
||
color: #64748b;
|
||
margin-top: 0.25rem;
|
||
}
|
||
|
||
/* ========== Section Header ========== */
|
||
.section-header {
|
||
text-align: center;
|
||
margin-bottom: 3rem;
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.section-header {
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 1.5rem;
|
||
}
|
||
|
||
.section-subtitle {
|
||
font-size: 0.875rem;
|
||
}
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 2rem;
|
||
font-weight: 700;
|
||
color: #fff;
|
||
margin: 0 0 0.75rem;
|
||
}
|
||
|
||
.section-subtitle {
|
||
font-size: 1rem;
|
||
color: #64748b;
|
||
margin: 0;
|
||
}
|
||
|
||
/* ========== Features Section ========== */
|
||
.page-2 .page-content {
|
||
padding-top: 5rem;
|
||
padding-bottom: 0;
|
||
justify-content: flex-start;
|
||
overflow: hidden;
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.page-2 .page-content {
|
||
padding-top: 4rem;
|
||
}
|
||
}
|
||
|
||
/* ========== 横向滚动区域 ========== */
|
||
.horizontal-scroll-wrapper {
|
||
flex: 1;
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.horizontal-scroll-container {
|
||
flex: 1;
|
||
display: flex;
|
||
overflow-x: auto;
|
||
scroll-snap-type: x mandatory;
|
||
scroll-behavior: smooth;
|
||
scrollbar-width: none;
|
||
-ms-overflow-style: none;
|
||
}
|
||
|
||
.horizontal-scroll-container::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
.horizontal-page {
|
||
flex: 0 0 100%;
|
||
width: 100%;
|
||
height: 100%;
|
||
scroll-snap-align: start;
|
||
scroll-snap-stop: always;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 1rem 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.features-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
grid-template-rows: repeat(2, auto);
|
||
gap: 1.5rem;
|
||
width: 100%;
|
||
max-width: 1000px;
|
||
padding: 2rem;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
/* ========== 横向滚动指示器 ========== */
|
||
.horizontal-indicator {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 0.5rem;
|
||
padding: 1rem 0;
|
||
}
|
||
|
||
.h-indicator-dot {
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
background: rgba(255, 255, 255, 0.2);
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.h-indicator-dot:hover {
|
||
background: rgba(255, 255, 255, 0.4);
|
||
}
|
||
|
||
.h-indicator-dot.active {
|
||
background: linear-gradient(135deg, #6366f1, #8b5cf6);
|
||
transform: scale(1.2);
|
||
}
|
||
|
||
/* ========== 横向滚动箭头 ========== */
|
||
.scroll-arrow {
|
||
position: absolute;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
width: 48px;
|
||
height: 48px;
|
||
border-radius: 50%;
|
||
background: rgba(255, 255, 255, 0.1);
|
||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||
color: #fff;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.3s ease;
|
||
backdrop-filter: blur(10px);
|
||
z-index: 10;
|
||
}
|
||
|
||
.scroll-arrow:hover {
|
||
background: rgba(255, 255, 255, 0.2);
|
||
transform: translateY(-50%) scale(1.1);
|
||
}
|
||
|
||
.scroll-arrow svg {
|
||
width: 24px;
|
||
height: 24px;
|
||
}
|
||
|
||
.scroll-arrow-left {
|
||
left: 1rem;
|
||
}
|
||
|
||
.scroll-arrow-right {
|
||
right: 1rem;
|
||
}
|
||
|
||
.all-features-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||
gap: 1.5rem;
|
||
}
|
||
|
||
/* 横向滚动中的卡片样式 */
|
||
.features-grid .feature-card {
|
||
min-height: 200px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding: 2rem;
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.features-grid .feature-card {
|
||
min-height: auto;
|
||
padding: 1.25rem;
|
||
}
|
||
|
||
.features-grid .feature-card .icon-wrapper {
|
||
width: 44px;
|
||
height: 44px;
|
||
border-radius: 12px;
|
||
}
|
||
|
||
.features-grid .feature-card .icon-wrapper svg {
|
||
width: 22px;
|
||
height: 22px;
|
||
}
|
||
|
||
.features-grid .feature-card .card-title {
|
||
font-size: 0.9375rem;
|
||
margin: 0.5rem 0 0.25rem;
|
||
}
|
||
|
||
.features-grid .feature-card .card-desc {
|
||
font-size: 0.75rem;
|
||
line-height: 1.5;
|
||
}
|
||
}
|
||
|
||
/* ========== Feature Cards ========== */
|
||
.feature-card {
|
||
background: rgba(255, 255, 255, 0.02);
|
||
border: 1px solid rgba(255, 255, 255, 0.06);
|
||
border-radius: 20px;
|
||
padding: 1.5rem;
|
||
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||
position: relative;
|
||
overflow: hidden;
|
||
cursor: pointer;
|
||
backdrop-filter: blur(10px);
|
||
}
|
||
|
||
.feature-card::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: radial-gradient(
|
||
600px circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
|
||
rgba(255, 255, 255, 0.06),
|
||
transparent 40%
|
||
);
|
||
opacity: 0;
|
||
transition: opacity 0.4s;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.feature-card:hover::before {
|
||
opacity: 1;
|
||
}
|
||
|
||
.feature-card:hover {
|
||
transform: translateY(-4px);
|
||
background: rgba(255, 255, 255, 0.04);
|
||
border-color: rgba(255, 255, 255, 0.1);
|
||
}
|
||
|
||
.feature-card {
|
||
padding: 1.5rem;
|
||
}
|
||
|
||
.feature-card:hover {
|
||
transform: translateY(-4px);
|
||
}
|
||
|
||
.card-content {
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
|
||
|
||
.icon-wrapper {
|
||
width: 56px;
|
||
height: 56px;
|
||
border-radius: 14px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: #fff;
|
||
transition: transform 0.3s ease;
|
||
}
|
||
|
||
.icon-wrapper.small {
|
||
width: 44px;
|
||
height: 44px;
|
||
border-radius: 12px;
|
||
}
|
||
|
||
.icon-wrapper svg {
|
||
width: 28px;
|
||
height: 28px;
|
||
}
|
||
|
||
.icon-wrapper.small svg {
|
||
width: 22px;
|
||
height: 22px;
|
||
}
|
||
|
||
.feature-card:hover .icon-wrapper {
|
||
transform: scale(1.05);
|
||
}
|
||
|
||
/* Card Colors */
|
||
.card-1 .icon-wrapper {
|
||
background: linear-gradient(135deg, #6366f1, #4f46e5);
|
||
box-shadow: 0 8px 20px -6px rgba(99, 102, 241, 0.5);
|
||
}
|
||
|
||
.card-2 .icon-wrapper {
|
||
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
|
||
box-shadow: 0 8px 20px -6px rgba(139, 92, 246, 0.5);
|
||
}
|
||
|
||
.card-3 .icon-wrapper {
|
||
background: linear-gradient(135deg, #ec4899, #db2777);
|
||
box-shadow: 0 8px 20px -6px rgba(236, 72, 153, 0.5);
|
||
}
|
||
|
||
.card-4 .icon-wrapper {
|
||
background: linear-gradient(135deg, #14b8a6, #0d9488);
|
||
box-shadow: 0 8px 20px -6px rgba(20, 184, 166, 0.5);
|
||
}
|
||
|
||
.card-5 .icon-wrapper {
|
||
background: linear-gradient(135deg, #f59e0b, #d97706);
|
||
box-shadow: 0 8px 20px -6px rgba(245, 158, 11, 0.5);
|
||
}
|
||
|
||
.card-6 .icon-wrapper {
|
||
background: linear-gradient(135deg, #ef4444, #dc2626);
|
||
box-shadow: 0 8px 20px -6px rgba(239, 68, 68, 0.5);
|
||
}
|
||
|
||
.card-7 .icon-wrapper {
|
||
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
|
||
box-shadow: 0 8px 20px -6px rgba(139, 92, 246, 0.5);
|
||
}
|
||
|
||
.card-8 .icon-wrapper {
|
||
background: linear-gradient(135deg, #10b981, #059669);
|
||
box-shadow: 0 8px 20px -6px rgba(16, 185, 129, 0.5);
|
||
}
|
||
|
||
.card-9 .icon-wrapper {
|
||
background: linear-gradient(135deg, #6366f1, #8b5cf6);
|
||
box-shadow: 0 8px 20px -6px rgba(99, 102, 241, 0.5);
|
||
}
|
||
|
||
.card-10 .icon-wrapper {
|
||
background: linear-gradient(135deg, #06b6d4, #0891b2);
|
||
box-shadow: 0 8px 20px -6px rgba(6, 182, 212, 0.5);
|
||
}
|
||
|
||
.card-12 .icon-wrapper {
|
||
background: linear-gradient(135deg, #ec4899, #f472b6);
|
||
box-shadow: 0 8px 20px -6px rgba(236, 72, 153, 0.5);
|
||
}
|
||
|
||
.card-title {
|
||
font-size: 1.125rem;
|
||
font-weight: 600;
|
||
margin: 0.75rem 0 0.375rem;
|
||
color: #f8fafc;
|
||
}
|
||
|
||
.card-desc {
|
||
font-size: 0.875rem;
|
||
color: #94a3b8;
|
||
line-height: 1.6;
|
||
margin: 0;
|
||
}
|
||
|
||
|
||
|
||
/* ========== Footer ========== */
|
||
.landing-footer {
|
||
padding: 3rem 0;
|
||
text-align: center;
|
||
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.landing-footer {
|
||
padding: 1.5rem 0;
|
||
}
|
||
|
||
.landing-footer p {
|
||
font-size: 0.75rem;
|
||
}
|
||
}
|
||
|
||
.landing-footer p {
|
||
color: #64748b;
|
||
font-size: 0.875rem;
|
||
margin: 0;
|
||
}
|
||
|
||
/* ========== Responsive ========== */
|
||
@media (max-width: 968px) {
|
||
.all-features-grid {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
}
|
||
|
||
.hero-stats {
|
||
gap: 2rem;
|
||
padding: 1.5rem 2rem;
|
||
}
|
||
|
||
.page-indicator {
|
||
right: 1rem;
|
||
}
|
||
|
||
/* 平板端横向滚动优化 */
|
||
.horizontal-scroll-wrapper {
|
||
padding: 0 0.5rem;
|
||
}
|
||
|
||
.features-grid {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
grid-template-rows: repeat(3, auto);
|
||
gap: 1rem;
|
||
padding: 1rem;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.page-content {
|
||
padding: 0 1rem;
|
||
}
|
||
|
||
.landing-nav {
|
||
padding: 0.75rem 1rem;
|
||
}
|
||
|
||
.nav-brand {
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.brand-icon {
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.brand-icon svg {
|
||
width: 18px;
|
||
height: 18px;
|
||
}
|
||
|
||
.brand-text {
|
||
font-size: 1.125rem;
|
||
}
|
||
|
||
.page-1 .page-content {
|
||
padding-top: 3.5rem;
|
||
padding-bottom: 4rem;
|
||
}
|
||
|
||
.hero-stats {
|
||
flex-wrap: wrap;
|
||
gap: 1rem;
|
||
padding: 1rem 1.25rem;
|
||
}
|
||
|
||
.stat-item {
|
||
flex: 1 1 45%;
|
||
}
|
||
|
||
.page-2 .page-content {
|
||
padding-top: 3.5rem;
|
||
}
|
||
|
||
.features-grid {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
grid-template-rows: repeat(3, auto);
|
||
gap: 0.625rem;
|
||
padding: 0.5rem;
|
||
}
|
||
|
||
.features-grid .feature-card {
|
||
min-height: auto;
|
||
padding: 0.875rem;
|
||
}
|
||
|
||
.features-grid .feature-card .icon-wrapper {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 10px;
|
||
}
|
||
|
||
.features-grid .feature-card .icon-wrapper svg {
|
||
width: 18px;
|
||
height: 18px;
|
||
}
|
||
|
||
.features-grid .feature-card .card-title {
|
||
font-size: 0.8125rem;
|
||
margin: 0.375rem 0 0.125rem;
|
||
}
|
||
|
||
.features-grid .feature-card .card-desc {
|
||
font-size: 0.6875rem;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.all-features-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.scroll-arrow {
|
||
width: 36px;
|
||
height: 36px;
|
||
}
|
||
|
||
.scroll-arrow svg {
|
||
width: 18px;
|
||
height: 18px;
|
||
}
|
||
|
||
.scroll-arrow-left {
|
||
left: 0.25rem;
|
||
}
|
||
|
||
.scroll-arrow-right {
|
||
right: 0.25rem;
|
||
}
|
||
|
||
.page-indicator {
|
||
right: 0.5rem;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.indicator-dot {
|
||
width: 6px;
|
||
height: 6px;
|
||
}
|
||
|
||
.horizontal-indicator {
|
||
padding: 0.75rem 0;
|
||
}
|
||
|
||
.h-indicator-dot {
|
||
width: 6px;
|
||
height: 6px;
|
||
}
|
||
|
||
.scroll-hint {
|
||
bottom: 1rem;
|
||
font-size: 0.75rem;
|
||
}
|
||
|
||
.scroll-hint svg {
|
||
width: 20px;
|
||
height: 20px;
|
||
}
|
||
}
|
||
</style> |