practice_code/web/graduation/src/pages/travel/[slug].astro

249 lines
10 KiB
Plaintext
Raw Normal View History

2025-03-23 01:42:26 +08:00
---
import { getCollection, getEntry, type CollectionEntry } from "astro:content";
import MainLayout from "../../layouts/MainLayout.astro";
import ScrollReveal from "../../components/aceternity/ScrollReveal.astro";
// 定义Props类型
export interface Props {
entry: CollectionEntry<"travel">;
}
// 生成静态路径
export async function getStaticPaths() {
const travels = await getCollection("travel");
return travels.map((entry) => ({
params: { slug: entry.slug },
props: { entry },
}));
}
// 获取当前旅行攻略数据
const { entry } = Astro.props;
const { Content } = await entry.render();
// 获取相关旅行攻略
const allTravels = await getCollection("travel");
const relatedTravels = allTravels
.filter(
(item) =>
item.slug !== entry.slug &&
(item.data.season === entry.data.season ||
item.data.type === entry.data.type ||
item.data.tags.some((tag) => entry.data.tags.includes(tag)))
)
.slice(0, 3);
---
<MainLayout title={`${entry.data.title} - 河北游礼`}>
<!-- 页面标题区域 -->
<div class="relative py-16 bg-gradient-to-br from-color-primary-700 via-color-primary-600 to-color-primary-800 text-white dark:from-color-dark-primary-900 dark:via-color-dark-primary-800 dark:to-color-dark-primary-950">
<div class="absolute inset-0 bg-black/30"></div>
<div class="container mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<div class="max-w-4xl mx-auto">
<ScrollReveal animation="fade">
<div class="flex flex-wrap items-center gap-2 mb-4">
<a href="/" class="text-white/80 hover:text-white transition-colors">首页</a>
<span class="text-white/60">/</span>
<a href="/travel" class="text-white/80 hover:text-white transition-colors">旅行攻略</a>
<span class="text-white/60">/</span>
<span class="text-white/60">{entry.data.title}</span>
</div>
<h1 class="text-4xl md:text-5xl font-bold mb-4">{entry.data.title}</h1>
<div class="flex flex-wrap items-center gap-4 mb-4">
{entry.data.season && (
<div class="flex items-center text-white/90">
<span class="mr-1">🌤️</span> {entry.data.season}
</div>
)}
{entry.data.type && (
<div class="flex items-center text-white/90">
<span class="mr-1">📋</span> {entry.data.type}
</div>
)}
{entry.data.days && (
<div class="flex items-center text-white/90">
<span class="mr-1">⏱️</span> {entry.data.days}天行程
</div>
)}
{entry.data.difficulty && (
<div class="flex items-center text-white/90">
<span class="mr-1">🏔️</span> 难度:{entry.data.difficulty}
</div>
)}
</div>
<div class="flex flex-wrap gap-2 mb-6">
{entry.data.tags.map((tag) => (
<span class="px-3 py-1 bg-white/20 backdrop-blur-sm text-white text-sm rounded-full">
{tag}
</span>
))}
</div>
<p class="text-xl text-white/90 max-w-3xl">{entry.data.description}</p>
</ScrollReveal>
</div>
</div>
</div>
<!-- 主要内容区域 -->
<div class="py-12 bg-white dark:bg-color-dark-bg">
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-12">
<!-- 左侧内容 -->
<div class="lg:col-span-2">
<ScrollReveal animation="fade">
<div class="prose prose-lg dark:prose-invert max-w-none">
<Content />
</div>
</ScrollReveal>
</div>
<!-- 右侧边栏 -->
<div class="space-y-8">
<!-- 旅行图片 -->
<ScrollReveal animation="slide-up">
<div class="rounded-lg overflow-hidden shadow-md">
<div class="h-64 bg-gray-300 dark:bg-gray-700 flex items-center justify-center">
<span class="text-gray-500 dark:text-gray-400">{entry.data.title} 图片</span>
</div>
</div>
</ScrollReveal>
<!-- 攻略信息卡片 -->
<ScrollReveal animation="slide-up" delay={100}>
<div class="bg-gray-50 dark:bg-color-dark-card rounded-lg shadow-md p-6">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">攻略信息</h3>
<div class="space-y-3">
{entry.data.season && (
<div class="flex">
<span class="w-24 flex-shrink-0 text-gray-600 dark:text-gray-400">适宜季节:</span>
<span class="text-gray-900 dark:text-white">{entry.data.season}</span>
</div>
)}
{entry.data.type && (
<div class="flex">
<span class="w-24 flex-shrink-0 text-gray-600 dark:text-gray-400">攻略类型:</span>
<span class="text-gray-900 dark:text-white">{entry.data.type}</span>
</div>
)}
{entry.data.days && (
<div class="flex">
<span class="w-24 flex-shrink-0 text-gray-600 dark:text-gray-400">行程天数:</span>
<span class="text-gray-900 dark:text-white">{entry.data.days}天</span>
</div>
)}
{entry.data.difficulty && (
<div class="flex">
<span class="w-24 flex-shrink-0 text-gray-600 dark:text-gray-400">难度级别:</span>
<span class="text-gray-900 dark:text-white">{entry.data.difficulty}</span>
</div>
)}
<div class="flex">
<span class="w-24 flex-shrink-0 text-gray-600 dark:text-gray-400">旅行主题:</span>
<div class="flex flex-wrap gap-1">
{entry.data.tags.map((tag) => (
<span class="px-2 py-0.5 bg-color-primary-100 text-color-primary-800 text-xs rounded-full dark:bg-color-dark-primary-900/70 dark:text-color-primary-300">
{tag}
</span>
))}
</div>
</div>
{entry.data.pubDate && (
<div class="flex">
<span class="w-24 flex-shrink-0 text-gray-600 dark:text-gray-400">发布时间:</span>
<span class="text-gray-900 dark:text-white">{new Date(entry.data.pubDate).toLocaleDateString('zh-CN')}</span>
</div>
)}
</div>
</div>
</ScrollReveal>
<!-- 旅行小贴士 -->
<ScrollReveal animation="slide-up" delay={200}>
<div class="bg-color-primary-50 dark:bg-color-dark-primary-900/30 rounded-lg shadow-md p-6 border border-color-primary-100 dark:border-color-dark-primary-800">
<h3 class="text-xl font-semibold text-color-primary-800 dark:text-color-primary-300 mb-4">旅行小贴士</h3>
<div class="space-y-3 text-color-primary-700 dark:text-color-primary-300/90">
<div class="flex">
<span class="mr-2">✓</span>
<p>出行前查看天气预报,准备合适的衣物</p>
</div>
<div class="flex">
<span class="mr-2">✓</span>
<p>提前规划路线,预订住宿和交通</p>
</div>
<div class="flex">
<span class="mr-2">✓</span>
<p>携带必要的药品和紧急联系方式</p>
</div>
<div class="flex">
<span class="mr-2">✓</span>
<p>尊重当地风俗习惯,做文明旅行者</p>
</div>
</div>
</div>
</ScrollReveal>
<!-- 相关攻略 -->
{relatedTravels.length > 0 && (
<ScrollReveal animation="slide-up" delay={300}>
<div class="bg-gray-50 dark:bg-color-dark-card rounded-lg shadow-md p-6">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">相关攻略</h3>
<div class="space-y-4">
{relatedTravels.map((travel) => (
<a
href={`/travel/${travel.slug}`}
class="block group"
>
<div class="flex items-start space-x-3">
<div class="w-16 h-16 flex-shrink-0 bg-gray-300 dark:bg-gray-700 rounded flex items-center justify-center">
<span class="text-xs text-gray-500 dark:text-gray-400">图片</span>
</div>
<div>
<h4 class="text-base font-medium text-gray-900 dark:text-white group-hover:text-color-primary-600 dark:group-hover:text-color-primary-400 transition-colors">
{travel.data.title}
</h4>
<div class="flex items-center text-xs text-gray-500 dark:text-gray-400 mt-1 space-x-2">
{travel.data.season && <span>{travel.data.season}</span>}
{travel.data.days && <span>• {travel.data.days}天行程</span>}
</div>
<p class="text-sm text-gray-600 dark:text-gray-400 line-clamp-2 mt-1">
{travel.data.description.substring(0, 60)}...
</p>
</div>
</div>
</a>
))}
</div>
</div>
</ScrollReveal>
)}
<!-- 返回按钮 -->
<ScrollReveal animation="slide-up" delay={400}>
<a
href="/travel"
class="block w-full py-3 text-center bg-color-primary-600 text-white rounded-md hover:bg-color-primary-700 transition-colors dark:bg-color-dark-primary-600 dark:hover:bg-color-dark-primary-500"
>
返回所有攻略
</a>
</ScrollReveal>
</div>
</div>
</div>
</div>
</MainLayout>