修复所有样式

This commit is contained in:
lsy 2025-04-10 21:08:37 +08:00
parent d36c639ca4
commit 3a93ac41b7
11 changed files with 814 additions and 1068 deletions

View File

@ -1,183 +0,0 @@
---
interface Props {
animation?: 'fade' | 'slide-up' | 'slide-down' | 'slide-left' | 'slide-right' | 'scale' | 'rotate';
duration?: number; // 动画持续时间,毫秒
delay?: number; // 延迟时间,毫秒
threshold?: number; // 触发阈值0-1之间
once?: boolean; // 是否只触发一次
className?: string;
}
const {
animation = 'fade',
duration = 800,
delay = 0,
threshold = 0.3,
once = true,
className = ""
} = Astro.props;
// 生成唯一ID
const id = `scroll-reveal-${Math.random().toString(36).substring(2, 11)}`;
// 设定初始隐藏样式
const getInitialStyles = () => {
switch(animation) {
case 'fade':
return 'opacity: 0;';
case 'slide-up':
return 'opacity: 0; transform: translateY(40px);';
case 'slide-down':
return 'opacity: 0; transform: translateY(-40px);';
case 'slide-left':
return 'opacity: 0; transform: translateX(40px);';
case 'slide-right':
return 'opacity: 0; transform: translateX(-40px);';
case 'scale':
return 'opacity: 0; transform: scale(0.9);';
case 'rotate':
return 'opacity: 0; transform: rotate(-5deg);';
default:
return 'opacity: 0;';
}
};
const initialStyles = getInitialStyles();
---
<div
id={id}
class={`scroll-reveal ${className}`}
data-scroll-animation={animation}
data-scroll-once={once.toString()}
style={`${initialStyles} transition: all ${duration}ms ease ${delay}ms;`}
>
<slot />
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const revealElements = document.querySelectorAll('.scroll-reveal');
// 检查是否为移动端设备
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
// 如果是移动端,直接显示所有元素,不使用动画
if (isMobile) {
revealElements.forEach((element) => {
const el = element as HTMLElement;
el.style.opacity = '1';
el.style.transform = 'none';
});
return;
}
// 检查是否支持 IntersectionObserver
if (!('IntersectionObserver' in window)) {
// 如果不支持,也直接显示所有元素
revealElements.forEach((element) => {
const el = element as HTMLElement;
el.style.opacity = '1';
el.style.transform = 'none';
});
return;
}
const observerOptions = {
root: null, // 使用视口作为根元素
rootMargin: '0px',
threshold: 0.3 // 默认阈值
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
const element = entry.target as HTMLElement;
const isOnce = element.getAttribute('data-scroll-once') === 'true';
if (entry.isIntersecting) {
// 元素进入视口,添加显示样式
element.style.opacity = '1';
element.style.transform = 'none';
// 如果设置为只触发一次,取消观察
if (isOnce) {
observer.unobserve(element);
}
} else if (!isOnce) {
// 如果不是一次性的,元素离开视口时恢复初始状态
const animation = element.getAttribute('data-scroll-animation') || 'fade';
switch(animation) {
case 'fade':
element.style.opacity = '0';
break;
case 'slide-up':
element.style.opacity = '0';
element.style.transform = 'translateY(40px)';
break;
case 'slide-down':
element.style.opacity = '0';
element.style.transform = 'translateY(-40px)';
break;
case 'slide-left':
element.style.opacity = '0';
element.style.transform = 'translateX(40px)';
break;
case 'slide-right':
element.style.opacity = '0';
element.style.transform = 'translateX(-40px)';
break;
case 'scale':
element.style.opacity = '0';
element.style.transform = 'scale(0.9)';
break;
case 'rotate':
element.style.opacity = '0';
element.style.transform = 'rotate(-5deg)';
break;
}
}
});
}, observerOptions);
// 为每个元素添加超时保障,确保元素最终会显示
revealElements.forEach((element) => {
const el = element as HTMLElement;
// 设置一个3秒的超时确保即使IntersectionObserver失效元素也会显示
setTimeout(() => {
el.style.opacity = '1';
el.style.transform = 'none';
}, 3000);
});
// 开始观察所有滚动显示元素
revealElements.forEach(element => {
// 设置自定义阈值
const elementThreshold = parseFloat(element.getAttribute('data-scroll-threshold') || '0.3');
if (!isNaN(elementThreshold) && elementThreshold >= 0 && elementThreshold <= 1) {
const newObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
const element = entry.target as HTMLElement;
const isOnce = element.getAttribute('data-scroll-once') === 'true';
if (entry.isIntersecting) {
element.style.opacity = '1';
element.style.transform = 'none';
if (isOnce) {
newObserver.unobserve(element);
}
} else if (!isOnce) {
// 恢复初始状态的逻辑与上面相同
// 为简化代码,这里不重复实现
}
});
}, { ...observerOptions, threshold: elementThreshold });
newObserver.observe(element);
} else {
observer.observe(element);
}
});
});
</script>

View File

@ -0,0 +1,64 @@
---
title: "正宗安徽板面 - 河北地区传承的皖系面食"
description: "安徽板面是河北地区流传的一种源自安徽的特色面食,以独特的手工拉制技法和浓郁的汤底著称,口感劲道爽滑,风味独特。"
category: "传统面食"
featured: true
image: "/images/cuisine/anhui-bannoodles.jpg"
city: ["邯郸", "石家庄", "保定"]
ingredients: ["高筋面粉", "鸡蛋", "肉汤", "牛肉", "羊肉", "香菜", "葱", "姜", "蒜", "辣椒油"]
taste: "鲜香麻辣"
cookTime: "2小时"
difficulty: "中等"
tags: ["面食", "传统美食", "地方特色", "河北小吃", "安徽风味"]
pubDate: 2023-10-15
---
# 正宗安徽板面
安徽板面,是一道源自安徽但在河北地区有着独特发展的传统面食,因其制作时将面团拍打成薄板状而得名。这种面食以其独特的制作工艺、劲道的口感和浓郁的汤底在河北地区广受欢迎,成为连接豫皖和冀地饮食文化的重要纽带。
## 历史渊源
安徽板面起源于安徽省北部地区,后随着人口流动和商贸往来传入河北。据传,早在明清时期,安徽商帮便将这一面食带到了河北南部,并逐渐在当地扎根发展。经过数百年的传承与融合,河北地区的安徽板面已经形成了独具地方特色的风味,成为河北与安徽两地饮食文化交流的见证。
在河北的邯郸、石家庄等地,安徽板面被赋予了新的地方特色,既保留了原汁原味的制作技艺,又融入了河北人对面食的独特理解,形成了一种独特的"河北式安徽板面"。
## 制作特点
正宗的安徽板面制作工艺独特,主要分为面条制作和汤底熬制两大部分。
**面条制作**选用优质高筋面粉和新鲜鸡蛋按照特定比例和面经过反复揉搓使面团富有弹性。然后将面团反复摔打在案板上拉伸成薄板状再切成宽约2-3厘米的条状。这种特殊的制作工艺使得面条内部形成独特的层次结构煮熟后劲道有嚼劲不易煮烂。
**汤底制作**河北地区的安徽板面汤底通常选用牛骨、羊骨和各种香料熬制8小时以上汤色乳白香气四溢。不同的城市又有不同的变化
- **邯郸版本**:偏重使用羊肉和羊骨熬制,汤底清澈微黄,突出原汁原味。
- **石家庄版本**:加入更多香料和少量番茄,汤底略带酸甜。
- **保定版本**:汤底中加入豆瓣酱提味,口感更为浓郁。
## 品尝方法
正宗的安徽板面上桌时,通常先端上一碗热气腾腾的面条,上面铺着切片的牛肉或羊肉,再单独附上一小碗浓香的卤汁。食用时,可根据个人口味加入适量的卤汁、辣椒油、蒜泥、香菜等调料,搅拌均匀后食用。
特别值得一提的是,河北地区的安徽板面常常会提供几种不同的辣椒油和醋供食客自行调配,以满足不同人的口味需求。当地人常说:"十个人吃板面,十种调味法",体现了这道美食的包容性。
## 地方特色
虽然源自安徽,但河北各地的安徽板面已经发展出了鲜明的地方特色:
- **邯郸安徽板面**:面条略宽,以羊肉为主料,汤底清爽,讲究"原汁原味"。
- **石家庄安徽板面**:面条韧性更强,常配以牛肉和牛杂,味道浓郁,有"一碗面,满嘴香"之说。
- **保定安徽板面**:面条韧滑均匀,汤料讲究层次感,常加入豆腐皮、木耳等辅料,丰富口感。
## 营养价值
安徽板面营养丰富,面条富含碳水化合物和蛋白质,汤底中的肉类提供优质蛋白质和多种氨基酸,各种蔬菜和调料则提供维生素和矿物质。冬季食用一碗热气腾腾的安徽板面,不仅能够温暖身体,还能提供充足的能量。
## 品尝地点
- **邯郸**:老街安徽板面、邯郸大食堂安徽板面馆
- **石家庄**:石门老街安徽板面、槐安路板面王
- **保定**:满庭芳安徽板面、老城根板面馆
- **价格范围**15-30元/碗,根据配料不同而有所变化
- **最佳品尝季节**:秋冬季节尤为适宜,寒冷天气中一碗热腾腾的板面格外满足
品尝一碗正宗的安徽板面,感受两地饮食文化的交融与创新,体验传统手工面食的魅力与河北地方特色的完美结合。无论是当地居民还是外地游客,都能在这碗面中找到属于自己的味道记忆。

View File

@ -1,7 +1,6 @@
---
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 {
@ -50,44 +49,42 @@ const relatedAttractions = allAttractions
<!-- 页面标题区域 -->
<div class="relative py-16 bg-gradient-to-br from-primary-700 via-primary-600 to-primary-800 text-white dark:from-primary-900 dark:via-primary-800 dark:to-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-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8 lg:gap-12">
<div class="lg:col-span-2">
<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="/attractions" 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>
<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="/attractions" 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.city && (
<div class="flex items-center text-white/90">
<span class="mr-1">📍</span> {entry.data.city}
</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.city && (
<div class="flex items-center text-white/90">
<span class="mr-1">📍</span> {entry.data.city}
</div>
)}
{entry.data.pubDate && (
<div class="flex items-center text-white/90">
<span class="mr-1">📅</span> {new Date(entry.data.pubDate).toLocaleDateString('zh-CN')}
</div>
)}
</div>
<div class="flex flex-wrap gap-2 mb-6">
{entry.data.tags.map((tag: string) => (
<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">{entry.data.description}</p>
</ScrollReveal>
{entry.data.pubDate && (
<div class="flex items-center text-white/90">
<span class="mr-1">📅</span> {new Date(entry.data.pubDate).toLocaleDateString('zh-CN')}
</div>
)}
</div>
<div class="flex flex-wrap gap-2 mb-6">
{entry.data.tags.map((tag: string) => (
<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">{entry.data.description}</p>
</div>
<div class="hidden lg:block lg:col-span-1">
<!-- 与底部边栏对齐的空白区域 -->
@ -98,97 +95,89 @@ const relatedAttractions = allAttractions
<!-- 主要内容区域 -->
<div class="py-8 lg:py-12 bg-white dark:bg-dark-bg">
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8 lg: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 class="prose prose-lg dark:prose-invert max-w-none">
<Content />
</div>
</div>
<!-- 右侧边栏 -->
<div class="space-y-6 md:space-y-8">
<!-- 景点图片 -->
<ScrollReveal animation="slide-up">
<div class="rounded-lg overflow-hidden shadow-md">
<div class="h-48 md: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 class="rounded-lg overflow-hidden shadow-md">
<div class="h-48 md: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>
</ScrollReveal>
</div>
<!-- 移动端快速信息栏 -->
<div class="block md:hidden">
<ScrollReveal animation="fade">
<div class="grid grid-cols-2 gap-3 mb-4">
{entry.data.city && (
<div class="bg-gray-50 dark:bg-gray-800 p-3 rounded-lg flex flex-col items-center text-center">
<span class="text-primary-500 dark:text-primary-400 text-xl mb-1">📍</span>
<span class="text-sm font-medium text-gray-600 dark:text-gray-400">位置</span>
<span class="text-sm text-gray-900 dark:text-white">{entry.data.city}</span>
</div>
)}
{entry.data.pubDate && (
<div class="bg-gray-50 dark:bg-gray-800 p-3 rounded-lg flex flex-col items-center text-center">
<span class="text-primary-500 dark:text-primary-400 text-xl mb-1">📅</span>
<span class="text-sm font-medium text-gray-600 dark:text-gray-400">发布日期</span>
<span class="text-sm text-gray-900 dark:text-white">{new Date(entry.data.pubDate).toLocaleDateString('zh-CN')}</span>
</div>
)}
<div class="grid grid-cols-2 gap-3 mb-4">
{entry.data.city && (
<div class="bg-gray-50 dark:bg-gray-800 p-3 rounded-lg flex flex-col items-center text-center">
<span class="text-primary-500 dark:text-primary-400 text-xl mb-1"></span>
<span class="text-sm font-medium text-gray-600 dark:text-gray-400">开放时间</span>
<span class="text-sm text-gray-900 dark:text-white">09:00-17:00</span>
<span class="text-primary-500 dark:text-primary-400 text-xl mb-1">📍</span>
<span class="text-sm font-medium text-gray-600 dark:text-gray-400">位置</span>
<span class="text-sm text-gray-900 dark:text-white">{entry.data.city}</span>
</div>
)}
{entry.data.pubDate && (
<div class="bg-gray-50 dark:bg-gray-800 p-3 rounded-lg flex flex-col items-center text-center">
<span class="text-primary-500 dark:text-primary-400 text-xl mb-1">🎫</span>
<span class="text-sm font-medium text-gray-600 dark:text-gray-400">门票</span>
<span class="text-sm text-gray-900 dark:text-white">50元</span>
<span class="text-primary-500 dark:text-primary-400 text-xl mb-1">📅</span>
<span class="text-sm font-medium text-gray-600 dark:text-gray-400">发布日期</span>
<span class="text-sm text-gray-900 dark:text-white">{new Date(entry.data.pubDate).toLocaleDateString('zh-CN')}</span>
</div>
)}
<div class="bg-gray-50 dark:bg-gray-800 p-3 rounded-lg flex flex-col items-center text-center">
<span class="text-primary-500 dark:text-primary-400 text-xl mb-1">⏰</span>
<span class="text-sm font-medium text-gray-600 dark:text-gray-400">开放时间</span>
<span class="text-sm text-gray-900 dark:text-white">09:00-17:00</span>
</div>
</ScrollReveal>
<div class="bg-gray-50 dark:bg-gray-800 p-3 rounded-lg flex flex-col items-center text-center">
<span class="text-primary-500 dark:text-primary-400 text-xl mb-1">🎫</span>
<span class="text-sm font-medium text-gray-600 dark:text-gray-400">门票</span>
<span class="text-sm text-gray-900 dark:text-white">50元</span>
</div>
</div>
</div>
<!-- 景点信息卡片 -->
<ScrollReveal animation="slide-up" delay={100}>
<div class="bg-gray-50 dark:bg-color-dark-card rounded-lg shadow-md p-5">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">景点信息</h3>
<div class="space-y-3">
{entry.data.city && (
<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.city}</span>
</div>
)}
<div class="flex flex-wrap">
<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: string) => (
<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 class="bg-gray-50 dark:bg-color-dark-card rounded-lg shadow-md p-5">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">景点信息</h3>
<div class="space-y-3">
{entry.data.city && (
<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.city}</span>
</div>
)}
<div class="flex flex-wrap">
<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: string) => (
<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>
{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>
{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>
</ScrollReveal>
</div>
<!-- 信息卡片组 -->
<div class="grid grid-cols-1 md:grid-cols-1 gap-4">
@ -293,14 +282,12 @@ const relatedAttractions = allAttractions
<!-- 返回按钮 - 仅在非移动端显示 -->
<div class="hidden md:block">
<ScrollReveal animation="slide-up" delay={300}>
<a
href="/attractions"
class="block w-full py-4 mt-8 mb-4 text-center bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors dark:bg-color-dark-primary-600 dark:hover:bg-color-dark-primary-500 font-bold shadow-lg border-2 border-blue-500 text-lg"
>
返回所有景点
</a>
</ScrollReveal>
<a
href="/attractions"
class="block w-full py-4 mt-8 mb-4 text-center bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors dark:bg-color-dark-primary-600 dark:hover:bg-color-dark-primary-500 font-bold shadow-lg border-2 border-blue-500 text-lg"
>
返回所有景点
</a>
</div>
</div>
</div>

View File

@ -137,7 +137,7 @@ const getCategory = (attraction: CollectionEntry<"attractions">) => {
<!-- 主内容区 - 摄影展览风格 -->
<div class="bg-white dark:bg-black text-gray-900 dark:text-white py-6 sm:py-10">
<div class="container mx-auto px-4">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<!-- 移动端筛选按钮 -->
<div class="lg:hidden mb-4 flex justify-between items-center">
<button id="mobile-filter-toggle" class="bg-primary-500 text-white px-4 py-2 rounded-full inline-flex items-center space-x-2 shadow-md active:shadow-sm transition-shadow">

View File

@ -1,7 +1,6 @@
---
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 {
@ -47,139 +46,127 @@ const relatedCuisines = allCuisines
</div>
<!-- 内容 -->
<div class="absolute inset-0 flex items-end">
<div class="container mx-auto px-4 pb-12">
<ScrollReveal animation="slide-up">
<div class="max-w-4xl">
<!-- 面包屑导航 -->
<div class="flex items-center gap-2 text-white/80 mb-4">
<a href="/" class="hover:text-white transition-colors">首页</a>
<span>/</span>
<a href="/cuisine" class="hover:text-white transition-colors">美食</a>
<span>/</span>
<span class="text-white">{entry.data.title}</span>
</div>
<div class="absolute inset-0">
<div class="max-w-7xl h-full flex flex-col justify-end px-4 sm:px-6 lg:px-8 pb-12 mx-auto">
<!-- 面包屑导航 -->
<div class="flex items-center gap-2 text-white/80 mb-4">
<a href="/" class="hover:text-white transition-colors">首页</a>
<span>/</span>
<a href="/cuisine" class="hover:text-white transition-colors">美食</a>
<span>/</span>
<span class="text-white">{entry.data.title}</span>
</div>
<h1 class="text-4xl md:text-5xl font-bold text-white mb-4">{entry.data.title}</h1>
<!-- 标签 -->
<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>
</div>
</ScrollReveal>
<h1 class="text-4xl md:text-5xl font-bold text-white mb-4">{entry.data.title}</h1>
<!-- 标签 -->
<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>
</div>
</div>
</div>
<!-- 主要内容区域 -->
<div class="py-12 bg-gray-50 dark:bg-gray-900">
<div class="container mx-auto px-4">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="grid grid-cols-1 lg:grid-cols-12 gap-12">
<!-- 左侧内容 -->
<div class="lg:col-span-8">
<ScrollReveal animation="fade">
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-8">
<!-- 添加城市信息展示 -->
{entry.data.city && entry.data.city.length > 0 && (
<div class="mb-6 flex flex-wrap gap-2">
<span class="text-gray-600 dark:text-gray-400">地域:</span>
{entry.data.city.map((cityName: string) => (
<span class="px-3 py-1 bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-300 text-sm rounded-full">
{cityName}
</span>
))}
</div>
)}
<div class="prose prose-lg dark:prose-invert max-w-none">
<Content />
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-8">
<!-- 添加城市信息展示 -->
{entry.data.city && entry.data.city.length > 0 && (
<div class="mb-6 flex flex-wrap gap-2">
<span class="text-gray-600 dark:text-gray-400">地域:</span>
{entry.data.city.map((cityName: string) => (
<span class="px-3 py-1 bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-300 text-sm rounded-full">
{cityName}
</span>
))}
</div>
)}
<div class="prose prose-lg dark:prose-invert max-w-none">
<Content />
</div>
</ScrollReveal>
</div>
</div>
<!-- 右侧边栏 -->
<div class="lg:col-span-4 space-y-8">
<!-- 食材信息卡片 -->
{entry.data.ingredients && entry.data.ingredients.length > 0 && (
<ScrollReveal animation="slide-up">
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6">
<h3 class="text-xl font-bold mb-6 flex items-center">
<span class="text-2xl mr-2">🥘</span>
主要食材
</h3>
<div class="grid grid-cols-2 gap-4">
{entry.data.ingredients.map((ingredient) => (
<div class="flex items-center bg-gray-50 dark:bg-gray-700 rounded-lg p-3">
<span class="text-amber-600 dark:text-amber-400 mr-2">•</span>
<span>{ingredient}</span>
</div>
))}
</div>
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6">
<h3 class="text-xl font-bold mb-6 flex items-center">
<span class="text-2xl mr-2">🥘</span>
主要食材
</h3>
<div class="grid grid-cols-2 gap-4">
{entry.data.ingredients.map((ingredient) => (
<div class="flex items-center bg-gray-50 dark:bg-gray-700 rounded-lg p-3">
<span class="text-amber-600 dark:text-amber-400 mr-2">•</span>
<span>{ingredient}</span>
</div>
))}
</div>
</ScrollReveal>
</div>
)}
<!-- 烹饪信息卡片 -->
<ScrollReveal animation="slide-up" delay={100}>
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6">
<h3 class="text-xl font-bold mb-6 flex items-center">
<span class="text-2xl mr-2">⏱️</span>
烹饪信息
</h3>
<div class="space-y-4">
<div class="flex justify-between items-center p-3 bg-gray-50 dark:bg-gray-700 rounded-lg">
<span class="text-gray-600 dark:text-gray-300">烹饪时间</span>
<span class="font-medium">{entry.data.cookTime || '45分钟'}</span>
</div>
<div class="flex justify-between items-center p-3 bg-gray-50 dark:bg-gray-700 rounded-lg">
<span class="text-gray-600 dark:text-gray-300">难度等级</span>
<span class="font-medium">{entry.data.difficulty || '中等'}</span>
</div>
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6">
<h3 class="text-xl font-bold mb-6 flex items-center">
<span class="text-2xl mr-2">⏱️</span>
烹饪信息
</h3>
<div class="space-y-4">
<div class="flex justify-between items-center p-3 bg-gray-50 dark:bg-gray-700 rounded-lg">
<span class="text-gray-600 dark:text-gray-300">烹饪时间</span>
<span class="font-medium">{entry.data.cookTime || '45分钟'}</span>
</div>
<div class="flex justify-between items-center p-3 bg-gray-50 dark:bg-gray-700 rounded-lg">
<span class="text-gray-600 dark:text-gray-300">难度等级</span>
<span class="font-medium">{entry.data.difficulty || '中等'}</span>
</div>
</div>
</ScrollReveal>
</div>
<!-- 相关美食推荐 -->
{relatedCuisines.length > 0 && (
<ScrollReveal animation="slide-up" delay={200}>
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6">
<h3 class="text-xl font-bold mb-6 flex items-center">
<span class="text-2xl mr-2">🍽️</span>
相关美食
</h3>
<div class="space-y-4">
{relatedCuisines.map((cuisine) => (
<a
href={`/cuisine/${cuisine.slug}`}
class="block group"
>
<div class="flex items-center gap-4 p-3 bg-gray-50 dark:bg-gray-700 rounded-lg transition-colors hover:bg-gray-100 dark:hover:bg-gray-600">
<img
src={cuisine.data.image}
alt={cuisine.data.title}
class="w-16 h-16 rounded-lg object-cover"
/>
<div>
<h4 class="font-medium group-hover:text-amber-600 dark:group-hover:text-amber-400 transition-colors">
{cuisine.data.title}
</h4>
<p class="text-sm text-gray-600 dark:text-gray-400">
{cuisine.data.category}
</p>
</div>
<div class="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6">
<h3 class="text-xl font-bold mb-6 flex items-center">
<span class="text-2xl mr-2">🍽️</span>
相关美食
</h3>
<div class="space-y-4">
{relatedCuisines.map((cuisine) => (
<a
href={`/cuisine/${cuisine.slug}`}
class="block group"
>
<div class="flex items-center gap-4 p-3 bg-gray-50 dark:bg-gray-700 rounded-lg transition-colors hover:bg-gray-100 dark:hover:bg-gray-600">
<img
src={cuisine.data.image}
alt={cuisine.data.title}
class="w-16 h-16 rounded-lg object-cover"
/>
<div>
<h4 class="font-medium group-hover:text-amber-600 dark:group-hover:text-amber-400 transition-colors">
{cuisine.data.title}
</h4>
<p class="text-sm text-gray-600 dark:text-gray-400">
{cuisine.data.category}
</p>
</div>
</a>
))}
</div>
</div>
</a>
))}
</div>
</ScrollReveal>
</div>
)}
</div>
</div>

View File

@ -1,7 +1,6 @@
---
import MainLayout from "../../layouts/MainLayout.astro";
import { getCollection, type CollectionEntry } from "astro:content";
import ScrollReveal from "../../components/aceternity/ScrollReveal.astro";
// 获取美食内容集合
const cuisines = await getCollection("cuisine");
@ -243,7 +242,7 @@ if (queryParams) queryParams = '?' + queryParams.substring(1);
<!-- 主内容区域 - 食谱风格 -->
<div class="bg-recipe-paper dark:bg-recipe-paper-dark py-12">
<div class="container mx-auto px-4">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<!-- 移动端筛选按钮和搜索框 -->
<div class="lg:hidden mb-6 flex justify-between items-center">
<button id="mobile-filter-toggle" class="bg-amber-500 text-white px-4 py-2 rounded-full inline-flex items-center space-x-2 shadow-md active:shadow-sm transition-shadow h-[38px]">
@ -369,10 +368,10 @@ if (queryParams) queryParams = '?' + queryParams.substring(1);
// 为标签生成不同的颜色
const colors = ['amber', 'red', 'green', 'orange', 'amber', 'red'];
const colorClasses = {
'amber': 'border-amber-200 dark:border-amber-800 text-amber-700 dark:text-amber-300 bg-amber-50/50 dark:bg-amber-900/20',
'red': 'border-red-200 dark:border-red-800 text-red-700 dark:text-red-300 bg-red-50/50 dark:bg-red-900/20',
'green': 'border-green-200 dark:border-green-800 text-green-700 dark:text-green-300 bg-green-50/50 dark:bg-green-900/20',
'orange': 'border-orange-200 dark:border-orange-800 text-orange-700 dark:text-orange-300 bg-orange-50/50 dark:bg-orange-900/20'
'amber': 'border-amber-200 dark:border-amber-800 text-amber-700 dark:text-amber-50 hover:text-amber-900 dark:hover:text-amber-50 hover:border-amber-400 dark:hover:border-amber-700 bg-amber-50/50 dark:bg-amber-900/80',
'red': 'border-red-200 dark:border-red-800 text-red-700 dark:text-red-50 hover:text-red-900 dark:hover:text-red-50 hover:border-red-400 dark:hover:border-red-700 bg-red-50/50 dark:bg-red-900/80',
'green': 'border-green-200 dark:border-green-800 text-green-700 dark:text-green-50 hover:text-green-900 dark:hover:text-green-50 hover:border-green-400 dark:hover:border-green-700 bg-green-50/50 dark:bg-green-900/80',
'orange': 'border-orange-200 dark:border-orange-800 text-orange-700 dark:text-orange-50 hover:text-orange-900 dark:hover:text-orange-50 hover:border-orange-400 dark:hover:border-orange-700 bg-orange-50/50 dark:bg-orange-900/80'
};
const color = colors[i % colors.length] as keyof typeof colorClasses;
const selectedClass = isSelected ? 'ring-2 ring-amber-500 dark:ring-amber-400 shadow-md' : '';
@ -500,7 +499,7 @@ if (queryParams) queryParams = '?' + queryParams.substring(1);
return (
<a href={isSelected ? `/cuisine${queryParams.replace(new RegExp(`[&?]city=${encodeURIComponent(cityParam)}`, 'i'), '')}` : `/cuisine?city=${encodeURIComponent(city.name)}${queryParams.replace(/^\?/, '&')}`}
class="flex items-center group cursor-pointer font-recipe-body">
<div class={`w-4 h-4 mr-2 transition-colors ${isSelected ? 'bg-green-500 dark:bg-green-500' : 'border border-brown-400 dark:border-brown-600'}`}></div>
<div class={`w-4 h-4 mr-2 transition-colors ${isSelected ? 'bg-green-500 dark:bg-green-500' : 'border border-green-400 dark:border-green-600'}`}></div>
<div class="font-light text-brown-700 dark:text-brown-300 text-sm truncate">
<span>{city.name}</span> <span class="text-green-600/70 dark:text-green-500/50 text-xs">({city.count})</span>
</div>
@ -523,10 +522,10 @@ if (queryParams) queryParams = '?' + queryParams.substring(1);
const isSelected = tasteParam && tasteParam.toLowerCase() === taste.name.toLowerCase();
return (
<a href={isSelected ? `/cuisine${queryParams.replace(new RegExp(`[&?]taste=${encodeURIComponent(tasteParam)}`, 'i'), '')}` : `/cuisine?taste=${encodeURIComponent(taste.name)}${queryParams.replace(/^\?/, '&')}`}
class="inline-flex items-center group cursor-pointer px-3 py-1 bg-orange-50/70 dark:bg-orange-900/30 border border-orange-200 dark:border-orange-800 rounded-full font-recipe-body">
class="inline-flex items-center group cursor-pointer px-3 py-1 bg-orange-50/50 dark:bg-orange-900/50 border border-orange-200 dark:border-orange-800 rounded-full font-recipe-body">
<div class={`w-3 h-3 mr-2 rounded-full transition-colors ${isSelected ? 'bg-orange-400 dark:bg-orange-500' : 'border border-orange-400 dark:border-orange-500'}`}></div>
<div class="font-light text-orange-800 dark:text-orange-300 text-xs">
{taste.name} <span class="text-orange-600/70 dark:text-orange-500/50">({taste.count})</span>
<div class="font-light text-orange-800 dark:text-orange-100 text-xs">
{taste.name} <span class="text-orange-600/70 dark:text-orange-300/90">({taste.count})</span>
</div>
</a>
);
@ -547,10 +546,10 @@ if (queryParams) queryParams = '?' + queryParams.substring(1);
// 为标签生成不同的颜色
const colors = ['amber', 'red', 'green', 'orange', 'amber', 'red'];
const colorClasses = {
'amber': 'border-amber-200 dark:border-amber-800 text-amber-700 dark:text-amber-300 hover:text-amber-900 dark:hover:text-amber-200 hover:border-amber-400 dark:hover:border-amber-700 bg-amber-50/50 dark:bg-amber-900/20',
'red': 'border-red-200 dark:border-red-800 text-red-700 dark:text-red-300 hover:text-red-900 dark:hover:text-red-200 hover:border-red-400 dark:hover:border-red-700 bg-red-50/50 dark:bg-red-900/20',
'green': 'border-green-200 dark:border-green-800 text-green-700 dark:text-green-300 hover:text-green-900 dark:hover:text-green-200 hover:border-green-400 dark:hover:border-green-700 bg-green-50/50 dark:bg-green-900/20',
'orange': 'border-orange-200 dark:border-orange-800 text-orange-700 dark:text-orange-300 hover:text-orange-900 dark:hover:text-orange-200 hover:border-orange-400 dark:hover:border-orange-700 bg-orange-50/50 dark:bg-orange-900/20'
'amber': 'border-amber-200 dark:border-amber-800 text-amber-700 dark:text-amber-50 hover:text-amber-900 dark:hover:text-amber-50 hover:border-amber-400 dark:hover:border-amber-700 bg-amber-50/50 dark:bg-amber-900/80',
'red': 'border-red-200 dark:border-red-800 text-red-700 dark:text-red-50 hover:text-red-900 dark:hover:text-red-50 hover:border-red-400 dark:hover:border-red-700 bg-red-50/50 dark:bg-red-900/80',
'green': 'border-green-200 dark:border-green-800 text-green-700 dark:text-green-50 hover:text-green-900 dark:hover:text-green-50 hover:border-green-400 dark:hover:border-green-700 bg-green-50/50 dark:bg-green-900/80',
'orange': 'border-orange-200 dark:border-orange-800 text-orange-700 dark:text-orange-50 hover:text-orange-900 dark:hover:text-orange-50 hover:border-orange-400 dark:hover:border-orange-700 bg-orange-50/50 dark:bg-orange-900/80'
};
const color = colors[i % colors.length] as keyof typeof colorClasses;
// 判断当前标签是否被选中
@ -581,10 +580,10 @@ if (queryParams) queryParams = '?' + queryParams.substring(1);
<a href={isSelected
? `/cuisine${queryParams.replace(new RegExp(`[&?]ingredient=${encodeURIComponent(ingredientParam)}`, 'i'), '')}`
: `/cuisine?ingredient=${encodeURIComponent(ingredient.name)}${queryParams.replace(/^\?/, '&')}`}
class="inline-flex items-center group cursor-pointer px-3 py-1 bg-green-50/70 dark:bg-green-900/30 border border-green-200 dark:border-green-800 rounded-full font-recipe-body">
class="inline-flex items-center group cursor-pointer px-3 py-1 bg-green-50/50 dark:bg-green-900/50 border border-green-200 dark:border-green-800 rounded-full font-recipe-body">
<div class={`w-3 h-3 mr-2 rounded-full transition-colors ${isSelected ? 'bg-green-400 dark:bg-green-500' : 'border border-green-400 dark:border-green-500 group-hover:bg-green-400 dark:group-hover:bg-green-500'}`}></div>
<div class="font-light text-green-800 dark:text-green-300 text-xs">
{ingredient.name} <span class="text-green-600/70 dark:text-green-500/50">({ingredient.count})</span>
<div class="font-light text-green-800 dark:text-green-100 text-xs">
{ingredient.name} <span class="text-green-600/70 dark:text-green-300/90">({ingredient.count})</span>
</div>
</a>
);
@ -699,7 +698,7 @@ if (queryParams) queryParams = '?' + queryParams.substring(1);
const paperColor = paperColors[index % paperColors.length];
return (
<ScrollReveal animation="fade">
<div class="transition-all duration-300">
<a href={`/cuisine/${cuisine.slug}`} class="block group">
<div class={`recipe-card-item border transition-all duration-300 ${paperColor}`}
data-ingredients={cuisine.data.ingredients && cuisine.data.ingredients.length > 0 ?
@ -774,7 +773,7 @@ if (queryParams) queryParams = '?' + queryParams.substring(1);
</div>
</div>
</a>
</ScrollReveal>
</div>
);
})}
</div>
@ -1662,7 +1661,7 @@ if (queryParams) queryParams = '?' + queryParams.substring(1);
if (isSelected) {
checkboxDiv.className = 'w-4 h-4 mr-2 transition-colors bg-green-500 dark:bg-green-500';
} else {
checkboxDiv.className = 'w-4 h-4 mr-2 transition-colors border border-brown-400 dark:border-brown-600';
checkboxDiv.className = 'w-4 h-4 mr-2 transition-colors border border-green-400 dark:border-green-600';
}
}
});

View File

@ -1,7 +1,6 @@
---
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 {
@ -51,184 +50,170 @@ const relatedCultures = allCultures
<div class="relative py-16 bg-ancient-paper dark:bg-ancient-paper-dark overflow-hidden">
<div class="absolute inset-0 bg-opacity-20 bg-amber-100 dark:bg-opacity-20 dark:bg-amber-900"></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-ancient-black/80 dark:text-ancient-white/80 hover:text-ancient-accent dark:hover:text-ancient-accent-dark transition-colors font-ancient-small">首页</a>
<span class="text-ancient-black/60 dark:text-ancient-white/60 font-ancient-small">/</span>
<a href="/culture" class="text-ancient-black/80 dark:text-ancient-white/80 hover:text-ancient-accent dark:hover:text-ancient-accent-dark transition-colors font-ancient-small">文化</a>
<span class="text-ancient-black/60 dark:text-ancient-white/60 font-ancient-small">/</span>
<span class="text-ancient-black/60 dark:text-ancient-white/60 font-ancient-small">{entry.data.title}</span>
</div>
<!-- 典籍风格标题 -->
<div class="official-title">
<h1 class="text-4xl md:text-5xl font-ancient text-ancient-black dark:text-ancient-white mb-4 leading-snug">{entry.data.title}</h1>
<div class="w-40 h-0.5 my-6 bg-ancient-accent dark:bg-ancient-accent-dark"></div>
</div>
<div class="flex flex-wrap items-center gap-4 mb-4">
{entry.data.city && entry.data.city.length > 0 && (
<div class="flex items-center text-ancient-black/90 dark:text-ancient-white/90 font-ancient-body">
<span class="mr-1">📍</span>
{entry.data.city.map((cityName, index) => (
<>
<span>{cityName}</span>
{index < entry.data.city.length - 1 && <span>, </span>}
</>
))}
</div>
)}
{entry.data.pubDate && (
<div class="flex items-center text-ancient-black/90 dark:text-ancient-white/90 font-ancient-body">
<span class="mr-1">📅</span> {new Date(entry.data.pubDate).toLocaleDateString('zh-CN')}
</div>
)}
<div class="flex items-center text-ancient-black/90 dark:text-ancient-white/90 font-ancient-body">
<span class="mr-1">🏷️</span> {entry.data.category}
</div>
</div>
<div class="flex flex-wrap gap-2 mb-6">
{entry.data.tags.map((tag) => (
<span class="px-3 py-1 bg-ancient-paper/70 dark:bg-ancient-paper-dark/70 text-ancient-black dark:text-ancient-white text-sm font-ancient-small border border-ancient-accent/30 dark:border-ancient-accent-dark/30 hover:border-ancient-accent/50 dark:hover:border-ancient-accent-dark/50 rounded-full">
{tag}
</span>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<div class="flex flex-wrap items-center gap-2 mb-4">
<a href="/" class="text-ancient-black/80 dark:text-ancient-white/80 hover:text-ancient-accent dark:hover:text-ancient-accent-dark transition-colors font-ancient-small">首页</a>
<span class="text-ancient-black/60 dark:text-ancient-white/60 font-ancient-small">/</span>
<a href="/culture" class="text-ancient-black/80 dark:text-ancient-white/80 hover:text-ancient-accent dark:hover:text-ancient-accent-dark transition-colors font-ancient-small">文化</a>
<span class="text-ancient-black/60 dark:text-ancient-white/60 font-ancient-small">/</span>
<span class="text-ancient-black/60 dark:text-ancient-white/60 font-ancient-small">{entry.data.title}</span>
</div>
<!-- 典籍风格标题 -->
<div class="official-title">
<h1 class="text-4xl md:text-5xl font-ancient text-ancient-black dark:text-ancient-white mb-4 leading-snug">{entry.data.title}</h1>
<div class="w-40 h-0.5 my-6 bg-ancient-accent dark:bg-ancient-accent-dark"></div>
</div>
<div class="flex flex-wrap items-center gap-4 mb-4">
{entry.data.city && entry.data.city.length > 0 && (
<div class="flex items-center text-ancient-black/90 dark:text-ancient-white/90 font-ancient-body">
<span class="mr-1">📍</span>
{entry.data.city.map((cityName, index) => (
<>
<span>{cityName}</span>
{index < entry.data.city.length - 1 && <span>, </span>}
</>
))}
</div>
<p class="text-xl text-ancient-black/90 dark:text-ancient-white/90 max-w-3xl font-ancient-body">{entry.data.description}</p>
</ScrollReveal>
)}
{entry.data.pubDate && (
<div class="flex items-center text-ancient-black/90 dark:text-ancient-white/90 font-ancient-body">
<span class="mr-1">📅</span> {new Date(entry.data.pubDate).toLocaleDateString('zh-CN')}
</div>
)}
<div class="flex items-center text-ancient-black/90 dark:text-ancient-white/90 font-ancient-body">
<span class="mr-1">🏷️</span> {entry.data.category}
</div>
</div>
<div class="flex flex-wrap gap-2 mb-6">
{entry.data.tags.map((tag) => (
<span class="px-3 py-1 bg-ancient-paper/70 dark:bg-ancient-paper-dark/70 text-ancient-black dark:text-ancient-white text-sm font-ancient-small border border-ancient-accent/30 dark:border-ancient-accent-dark/30 hover:border-ancient-accent/50 dark:hover:border-ancient-accent-dark/50 rounded-full">
{tag}
</span>
))}
</div>
<p class="text-xl text-ancient-black/90 dark:text-ancient-white/90 max-w-3xl font-ancient-body">{entry.data.description}</p>
</div>
</div>
<!-- 主要内容区域 - 古籍风格 -->
<div class="py-12 bg-ancient-paper dark:bg-ancient-paper-dark">
<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="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="grid grid-cols-1 lg:grid-cols-12 gap-6">
<!-- 左侧内容 - 古籍风格 -->
<div class="lg:col-span-2">
<ScrollReveal animation="fade">
<div class="prose prose-lg dark:prose-invert max-w-none font-ancient-body bg-ancient-paper-light/50 dark:bg-ancient-paper-dark/50 p-8 border-ancient-accent/30 dark:border-ancient-accent-dark/30 relative">
<Content />
</div>
</ScrollReveal>
<div class="lg:col-span-8">
<div class="prose prose-lg dark:prose-invert max-w-none font-ancient-body bg-ancient-paper-light/30 dark:bg-ancient-paper-dark/30 p-0 relative">
<Content />
</div>
</div>
<!-- 右侧边栏 - 古籍风格 -->
<div class="space-y-8">
<div class="lg:col-span-4 space-y-6">
<!-- 文化图片 - 古籍风格 -->
<ScrollReveal animation="slide-up">
<div class="border border-ancient-accent/40 dark:border-ancient-accent-dark/40 overflow-hidden shadow-md">
<div class="h-64 bg-ancient-paper-light/70 dark:bg-ancient-paper-dark/70 flex items-center justify-center relative">
<span class="text-ancient-black/40 dark:text-ancient-white/40 font-ancient">{entry.data.title} 图片</span>
</div>
<div class="border border-ancient-accent/40 dark:border-ancient-accent-dark/40 overflow-hidden shadow-md">
<div class="h-64 bg-ancient-paper-light/70 dark:bg-ancient-paper-dark/70 flex items-center justify-center relative">
<span class="text-ancient-black/40 dark:text-ancient-white/40 font-ancient">{entry.data.title} 图片</span>
</div>
</ScrollReveal>
</div>
<!-- 文化信息卡片 - 古籍风格 -->
<ScrollReveal animation="slide-up" delay={100}>
<div class="bg-ancient-paper-light dark:bg-ancient-paper-dark-light p-6 border-2 border-ancient-accent/30 dark:border-ancient-accent-dark/30 shadow-md">
<h3 class="text-xl font-ancient-heading text-ancient-black dark:text-ancient-white mb-4 flex items-center">
<svg class="w-5 h-5 mr-2 text-ancient-accent dark:text-ancient-accent-dark" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
文化信息
</h3>
<div class="space-y-3 font-ancient-body">
{entry.data.city && entry.data.city.length > 0 && (
<div class="flex">
<span class="w-24 flex-shrink-0 text-ancient-black/60 dark:text-ancient-white/60">分布地区:</span>
<div class="text-ancient-black dark:text-ancient-white">
{entry.data.city.map((cityName, index) => (
<>
<span>{cityName}</span>
{index < entry.data.city.length - 1 && <span>, </span>}
</>
))}
</div>
</div>
)}
<div class="bg-ancient-paper-light dark:bg-ancient-paper-dark-light p-5 border border-ancient-accent/30 dark:border-ancient-accent-dark/30 shadow-md">
<h3 class="text-xl font-ancient-heading text-ancient-black dark:text-ancient-white mb-4 flex items-center">
<svg class="w-5 h-5 mr-2 text-ancient-accent dark:text-ancient-accent-dark" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
文化信息
</h3>
<div class="space-y-3 font-ancient-body">
{entry.data.city && entry.data.city.length > 0 && (
<div class="flex">
<span class="w-24 flex-shrink-0 text-ancient-black/60 dark:text-ancient-white/60">文化类型:</span>
<span class="text-ancient-black dark:text-ancient-white">{entry.data.category}</span>
</div>
<div class="flex">
<span class="w-24 flex-shrink-0 text-ancient-black/60 dark:text-ancient-white/60">特色标签:</span>
<div class="flex flex-wrap gap-1">
{entry.data.tags.map((tag) => (
<span class="px-2 py-0.5 bg-ancient-paper/70 dark:bg-ancient-paper-dark/70 text-sm font-ancient-small border border-ancient-accent/30 dark:border-ancient-accent-dark/30 text-ancient-black dark:text-ancient-white text-xs rounded-full">
{tag}
</span>
<span class="w-24 flex-shrink-0 text-ancient-black/60 dark:text-ancient-white/60">分布地区:</span>
<div class="text-ancient-black dark:text-ancient-white">
{entry.data.city.map((cityName, index) => (
<>
<span>{cityName}</span>
{index < entry.data.city.length - 1 && <span>, </span>}
</>
))}
</div>
</div>
{entry.data.pubDate && (
<div class="flex">
<span class="w-24 flex-shrink-0 text-ancient-black/60 dark:text-ancient-white/60">发布时间:</span>
<span class="text-ancient-black dark:text-ancient-white">{new Date(entry.data.pubDate).toLocaleDateString('zh-CN')}</span>
</div>
)}
)}
<div class="flex">
<span class="w-24 flex-shrink-0 text-ancient-black/60 dark:text-ancient-white/60">文化类型:</span>
<span class="text-ancient-black dark:text-ancient-white">{entry.data.category}</span>
</div>
</div>
</ScrollReveal>
<!-- 相关文化 - 古籍风格 -->
{relatedCultures.length > 0 && (
<ScrollReveal animation="slide-up" delay={200}>
<div class="bg-ancient-paper-light dark:bg-ancient-paper-dark-light p-6 border-2 border-ancient-accent/30 dark:border-ancient-accent-dark/30 shadow-md">
<h3 class="text-xl font-ancient-heading text-ancient-black dark:text-ancient-white mb-4 flex items-center">
<svg class="w-5 h-5 mr-2 text-ancient-accent dark:text-ancient-accent-dark" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
相关文化
</h3>
<div class="space-y-4">
{relatedCultures.map((culture) => (
<a
href={`/culture/${culture.slug}`}
class="block group"
>
<div class="flex items-start space-x-3">
<div class="w-16 h-16 flex-shrink-0 bg-ancient-paper/70 dark:bg-ancient-paper-dark/70 border border-ancient-accent/20 dark:border-ancient-accent-dark/20 rounded flex items-center justify-center">
<span class="text-xs text-ancient-black/40 dark:text-ancient-white/40">图片</span>
</div>
<div>
<h4 class="text-base font-ancient-heading text-ancient-black dark:text-ancient-white group-hover:text-ancient-accent dark:group-hover:text-ancient-accent-dark transition-colors">
{culture.data.title}
</h4>
<p class="text-sm text-ancient-black/70 dark:text-ancient-white/70 line-clamp-2 font-ancient-body">
{culture.data.description.substring(0, 60)}...
</p>
</div>
</div>
</a>
<div class="flex">
<span class="w-24 flex-shrink-0 text-ancient-black/60 dark:text-ancient-white/60">特色标签:</span>
<div class="flex flex-wrap gap-1">
{entry.data.tags.map((tag) => (
<span class="px-2 py-0.5 bg-ancient-paper/70 dark:bg-ancient-paper-dark/70 text-sm font-ancient-small border border-ancient-accent/30 dark:border-ancient-accent-dark/30 text-ancient-black dark:text-ancient-white text-xs rounded-full">
{tag}
</span>
))}
</div>
</div>
</ScrollReveal>
{entry.data.pubDate && (
<div class="flex">
<span class="w-24 flex-shrink-0 text-ancient-black/60 dark:text-ancient-white/60">发布时间:</span>
<span class="text-ancient-black dark:text-ancient-white">{new Date(entry.data.pubDate).toLocaleDateString('zh-CN')}</span>
</div>
)}
</div>
</div>
<!-- 相关文化 - 古籍风格 -->
{relatedCultures.length > 0 && (
<div class="bg-ancient-paper-light dark:bg-ancient-paper-dark-light p-5 border border-ancient-accent/30 dark:border-ancient-accent-dark/30 shadow-md">
<h3 class="text-xl font-ancient-heading text-ancient-black dark:text-ancient-white mb-4 flex items-center">
<svg class="w-5 h-5 mr-2 text-ancient-accent dark:text-ancient-accent-dark" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
</svg>
相关文化
</h3>
<div class="space-y-4">
{relatedCultures.map((culture) => (
<a
href={`/culture/${culture.slug}`}
class="block group"
>
<div class="flex items-start space-x-3">
<div class="w-16 h-16 flex-shrink-0 bg-ancient-paper/70 dark:bg-ancient-paper-dark/70 border border-ancient-accent/20 dark:border-ancient-accent-dark/20 rounded flex items-center justify-center">
<span class="text-xs text-ancient-black/40 dark:text-ancient-white/40">图片</span>
</div>
<div>
<h4 class="text-base font-ancient-heading text-ancient-black dark:text-ancient-white group-hover:text-ancient-accent dark:group-hover:text-ancient-accent-dark transition-colors">
{culture.data.title}
</h4>
<p class="text-sm text-ancient-black/70 dark:text-ancient-white/70 line-clamp-2 font-ancient-body">
{culture.data.description.substring(0, 60)}...
</p>
</div>
</div>
</a>
))}
</div>
</div>
)}
<!-- 返回按钮 - 仅在非移动端显示 - 古籍风格 -->
<div class="hidden md:block">
<ScrollReveal animation="slide-up" delay={300}>
<a
href="/culture"
class="block w-full py-4 mt-8 mb-4 text-center bg-ancient-accent dark:bg-ancient-accent-dark text-ancient-white rounded-md hover:bg-ancient-accent/90 dark:hover:bg-ancient-accent-dark/90 transition-colors font-ancient shadow-md border border-ancient-accent/50 dark:border-ancient-accent-dark/50 text-lg"
>
返回所有文化
</a>
</ScrollReveal>
<a
href="/culture"
class="block w-full py-4 mt-8 mb-4 text-center bg-ancient-accent dark:bg-ancient-accent-dark text-ancient-white rounded-md hover:bg-ancient-accent/90 dark:hover:bg-ancient-accent-dark/90 transition-colors font-ancient shadow-md border border-ancient-accent/50 dark:border-ancient-accent-dark/50 text-lg"
>
返回所有文化
</a>
</div>
</div>
</div>

View File

@ -1,7 +1,6 @@
---
import MainLayout from "../../layouts/MainLayout.astro";
import { getCollection, type CollectionEntry } from "astro:content";
import ScrollReveal from "../../components/aceternity/ScrollReveal.astro";
import MainLayout from "../../layouts/MainLayout.astro";
// 获取URL参数
const { searchParams } = Astro.url;
@ -167,7 +166,7 @@ const buildUrl = (params: Record<string, string | null>) => {
<div class="absolute inset-0 bg-opacity-20 bg-amber-100 dark:bg-opacity-20 dark:bg-amber-900"></div>
<!-- 古籍书卷式标题区域 -->
<div class="container mx-auto px-4 relative z-10">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<div class="max-w-4xl mx-auto text-center">
<!-- 书卷式内容区 -->
<div class="relative py-12">
@ -192,7 +191,7 @@ const buildUrl = (params: Record<string, string | null>) => {
<!-- 主内容区域 - 古籍风格 -->
<div class="bg-ancient-paper dark:bg-ancient-paper-dark py-12">
<div class="container mx-auto px-4">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<!-- 文化介绍语 - 书卷风格 -->
<div class="mb-16 max-w-4xl mx-auto">
<div class="px-8 py-10 text-center border-l-2 border-r-2 border-ancient-accent/30 dark:border-ancient-accent-dark/30 bg-ancient-paper-light/50 dark:bg-ancient-paper-dark/50 relative">
@ -303,7 +302,7 @@ const buildUrl = (params: Record<string, string | null>) => {
</div>
<!-- 移动端筛选抽屉 - 默认隐藏 -->
<div id="mobile-filter-drawer" class="lg:hidden fixed inset-0 z-50 transform translate-x-full transition-transform duration-300 ease-in-out">
<div id="mobile-filter-drawer" class="lg:hidden fixed inset-0 z-50 transform translate-x-full ">
<div class="absolute inset-0 bg-black/50 backdrop-blur-sm" id="mobile-filter-backdrop"></div>
<div class="absolute right-0 top-0 bottom-0 w-4/5 max-w-sm bg-ancient-paper-light dark:bg-ancient-paper-dark shadow-xl overflow-y-auto">
<div class="p-4 border-b border-ancient-accent/20 dark:border-ancient-accent-dark/20 flex justify-between items-center">
@ -329,7 +328,7 @@ const buildUrl = (params: Record<string, string | null>) => {
<a
href={buildUrl({ category: category.name === activeCategory ? null : category.name })}
class:list={[
"px-3 py-1.5 bg-ancient-paper/70 dark:bg-ancient-paper-dark/70 text-sm font-ancient-small border transition-all rounded-md",
"px-3 py-1.5 bg-ancient-paper/70 dark:bg-ancient-paper-dark/70 text-sm font-ancient-small border rounded-md",
category.name === activeCategory
? "border-ancient-accent dark:border-ancient-accent-dark text-ancient-accent dark:text-ancient-accent-dark font-medium"
: "border-ancient-accent/30 dark:border-ancient-accent-dark/30 text-ancient-black dark:text-ancient-white hover:border-ancient-accent/50 dark:hover:border-ancient-accent-dark/50"
@ -356,10 +355,10 @@ const buildUrl = (params: Record<string, string | null>) => {
<a
href={buildUrl({ city: city.name === activeCity ? null : city.name })}
class:list={[
"px-3 py-1.5 text-sm font-ancient-small border rounded-md transition-all",
"px-3 py-1.5 bg-ancient-paper/70 dark:bg-ancient-paper-dark/70 text-sm font-ancient-small border rounded-md",
city.name === activeCity
? "bg-amber-100 dark:bg-amber-800/50 border-amber-300 dark:border-amber-600 text-amber-800 dark:text-amber-200 font-medium"
: "bg-amber-100/50 dark:bg-amber-800/30 border-amber-200/50 dark:border-amber-700/30 text-ancient-black/70 dark:text-ancient-white/70 hover:border-amber-300/50 dark:hover:border-amber-600/50"
? "border-ancient-accent dark:border-ancient-accent-dark text-ancient-accent dark:text-ancient-accent-dark font-medium"
: "border-ancient-accent/30 dark:border-ancient-accent-dark/30 text-ancient-black dark:text-ancient-white hover:border-ancient-accent/50 dark:hover:border-ancient-accent-dark/50"
]}
>
{city.name}
@ -382,7 +381,7 @@ const buildUrl = (params: Record<string, string | null>) => {
<a
href={buildUrl({ tag: tag.name === activeTag ? null : tag.name })}
class:list={[
"px-3 py-1.5 bg-ancient-paper/70 dark:bg-ancient-paper-dark/70 text-sm font-ancient-small border rounded-md transition-all",
"px-3 py-1.5 bg-ancient-paper/70 dark:bg-ancient-paper-dark/70 text-sm font-ancient-small border rounded-md",
tag.name === activeTag
? "border-ancient-accent dark:border-ancient-accent-dark text-ancient-accent dark:text-ancient-accent-dark font-medium"
: "border-ancient-accent/30 dark:border-ancient-accent-dark/30 text-ancient-black dark:text-ancient-white hover:border-ancient-accent/50 dark:hover:border-ancient-accent-dark/50"
@ -457,12 +456,14 @@ const buildUrl = (params: Record<string, string | null>) => {
{ "bg-ancient-accent/20 dark:bg-ancient-accent-dark/20": category.name === activeCategory }
]}
>
<div class="w-4 h-4 border border-ancient-accent/50 dark:border-ancient-accent-dark/50 mr-2 flex-shrink-0 group-hover:bg-ancient-accent/20 dark:group-hover:bg-ancient-accent-dark/20 transition-colors">
<div class="w-4 h-4 border border-ancient-accent/50 dark:border-ancient-accent-dark/50 mr-2 flex-shrink-0 group-hover:bg-ancient-accent/20 dark:group-hover:bg-ancient-accent-dark/20 relative">
{category.name === activeCategory && (
<div class="w-full h-full bg-ancient-accent/60 dark:bg-ancient-accent-dark/60"></div>
<div class="absolute inset-0 flex items-center justify-center">
<div class="w-2 h-3 border-r-2 border-b-2 border-ancient-accent dark:border-ancient-accent-dark transform rotate-45 -translate-y-1/4"></div>
</div>
)}
</div>
<div class="text-ancient-black dark:text-ancient-white group-hover:text-ancient-accent dark:group-hover:text-ancient-accent-dark transition-colors">
<div class="text-ancient-black dark:text-ancient-white group-hover:text-ancient-accent dark:group-hover:text-ancient-accent-dark">
<span>{category.name}</span>
<span class="text-ancient-black/60 dark:text-ancient-white/60 text-sm">({category.count})</span>
</div>
@ -490,12 +491,14 @@ const buildUrl = (params: Record<string, string | null>) => {
{ "bg-amber-100/80 dark:bg-amber-800/30": city.name === activeCity }
]}
>
<div class="w-4 h-4 border border-amber-300/50 dark:border-amber-700/50 mr-2 flex-shrink-0 group-hover:bg-amber-200/40 dark:group-hover:bg-amber-700/30 transition-colors">
<div class="w-4 h-4 border border-amber-300/50 dark:border-amber-700/50 mr-2 flex-shrink-0 group-hover:bg-amber-200/40 dark:group-hover:bg-amber-700/30 relative">
{city.name === activeCity && (
<div class="w-full h-full bg-amber-400/60 dark:bg-amber-600/60"></div>
<div class="absolute inset-0 flex items-center justify-center">
<div class="w-2 h-3 border-r-2 border-b-2 border-amber-400 dark:border-amber-600 transform rotate-45 -translate-y-1/4"></div>
</div>
)}
</div>
<div class="text-ancient-black dark:text-ancient-white group-hover:text-amber-700 dark:group-hover:text-amber-300 transition-colors">
<div class="text-ancient-black dark:text-ancient-white group-hover:text-amber-700 dark:group-hover:text-amber-300">
<span>{city.name}</span>
<span class="text-ancient-black/60 dark:text-ancient-white/60 text-sm">({city.count})</span>
</div>
@ -518,7 +521,7 @@ const buildUrl = (params: Record<string, string | null>) => {
<a
href={buildUrl({ tag: tag.name === activeTag ? null : tag.name })}
class:list={[
"px-3 py-1.5 bg-ancient-paper/70 dark:bg-ancient-paper-dark/70 text-sm font-ancient-small border rounded-md transition-all",
"px-3 py-1.5 bg-ancient-paper/70 dark:bg-ancient-paper-dark/70 text-sm font-ancient-small border rounded-md",
tag.name === activeTag
? "border-ancient-accent dark:border-ancient-accent-dark text-ancient-accent dark:text-ancient-accent-dark font-medium"
: "border-ancient-accent/30 dark:border-ancient-accent-dark/30 text-ancient-black dark:text-ancient-white hover:border-ancient-accent/50 dark:hover:border-ancient-accent-dark/50"
@ -543,93 +546,91 @@ const buildUrl = (params: Record<string, string | null>) => {
<!-- 文化内容列表 - 卷轴风格网格 -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 auto-rows-fr">
{currentPageCultures.map((culture, index) => (
<ScrollReveal animation="fade" delay={index * 100}>
<a href={`/culture/${culture.slug}`} class="block group h-full">
<div class="ancient-card relative h-full bg-ancient-paper dark:bg-ancient-paper-dark flex flex-col shadow-lg transition-transform duration-300 group-hover:shadow-xl overflow-hidden"
<a href={`/culture/${culture.slug}`} class="block group h-full">
<div class="ancient-card relative h-full bg-ancient-paper dark:bg-ancient-paper-dark flex flex-col shadow-lg group-hover:shadow-xl overflow-hidden"
data-tags={JSON.stringify(culture.data.tags.map((tag: string) => tag.toLowerCase()))}
data-category={culture.data.category?.toLowerCase() || ''}
data-cities={JSON.stringify(culture.data.city?.map((city: string) => city.toLowerCase()) || [])}
>
<div class="relative h-48 overflow-hidden border-b-2 border-ancient-accent/30 dark:border-ancient-accent-dark/30">
<!-- 装饰元素 -->
<div class="absolute top-2 left-2 w-8 h-8 bg-ink-decoration opacity-10 dark:opacity-15"></div>
<div class="absolute bottom-2 right-2 w-8 h-8 bg-ink-decoration opacity-10 dark:opacity-15 rotate-180"></div>
>
<div class="relative h-48 overflow-hidden border-b-2 border-ancient-accent/30 dark:border-ancient-accent-dark/30">
<!-- 装饰元素 -->
<div class="absolute top-2 left-2 w-8 h-8 bg-ink-decoration opacity-10 dark:opacity-15"></div>
<div class="absolute bottom-2 right-2 w-8 h-8 bg-ink-decoration opacity-10 dark:opacity-15 rotate-180"></div>
<!-- 默认内容显示 -->
<div class="absolute inset-0 flex items-center justify-center">
<span class="text-ancient-black/40 dark:text-amber-100/60 font-ancient">{culture.data.title}</span>
<!-- 默认内容显示 -->
<div class="absolute inset-0 flex items-center justify-center">
<span class="text-ancient-black/40 dark:text-amber-100/60 font-ancient">{culture.data.title}</span>
</div>
<!-- 印章效果 -->
{index % 4 === 0 && (
<div class="absolute top-4 right-4 w-16 h-16 bg-seal-mark opacity-40 rotate-12"></div>
)}
{/* 文化类别标签 */}
{culture.data.category && (
<div class="absolute top-3 right-3 px-2 py-1 bg-ancient-paper/90 dark:bg-dark-surface text-ancient-black dark:text-amber-100 text-xs font-ancient-small border border-ancient-accent/30 dark:border-amber-700/50 category-tag" data-category-value={culture.data.category.toLowerCase()}>
{culture.data.category}
</div>
)}
</div>
<!-- 印章效果 -->
{index % 4 === 0 && (
<div class="absolute top-4 right-4 w-16 h-16 bg-seal-mark opacity-40 rotate-12"></div>
)}
{/* 文化类别标签 */}
{culture.data.category && (
<div class="absolute top-3 right-3 px-2 py-1 bg-ancient-paper/90 dark:bg-dark-surface text-ancient-black dark:text-amber-100 text-xs font-ancient-small border border-ancient-accent/30 dark:border-amber-700/50 category-tag" data-category-value={culture.data.category.toLowerCase()}>
{culture.data.category}
<div class="p-5 flex flex-col flex-grow dark:bg-dark-card">
<div class="mb-3">
<h3 class="text-xl font-ancient text-ancient-black dark:text-amber-100 group-hover:text-ancient-red dark:group-hover:text-amber-300 ">
{culture.data.title}
</h3>
{(culture.data as any).period && (
<div class="text-sm text-ancient-black/70 dark:text-amber-200/80 mt-1 font-ancient-small period-tag" data-period-value={(culture.data as any).period.toLowerCase()}>
{(culture.data as any).period} 时期
</div>
)}
</div>
<div class="p-5 flex flex-col flex-grow dark:bg-dark-card">
<div class="mb-3">
<h3 class="text-xl font-ancient text-ancient-black dark:text-amber-100 group-hover:text-ancient-red dark:group-hover:text-amber-300 transition-colors">
{culture.data.title}
</h3>
{(culture.data as any).period && (
<div class="text-sm text-ancient-black/70 dark:text-amber-200/80 mt-1 font-ancient-small period-tag" data-period-value={(culture.data as any).period.toLowerCase()}>
{(culture.data as any).period} 时期
</div>
)}
</div>
<p class="text-ancient-black/80 dark:text-amber-100/90 text-sm line-clamp-2 mb-4 font-ancient-body">
{culture.data.description}
</p>
<p class="text-ancient-black/80 dark:text-amber-100/90 text-sm line-clamp-2 mb-4 font-ancient-body">
{culture.data.description}
</p>
<div class="flex flex-wrap gap-1.5 mb-4 min-h-[2rem]">
{culture.data.tags.slice(0, 3).map((tag: string) => (
<span class="px-2 py-1 bg-ancient-paper-light/50 dark:bg-dark-surface text-ancient-black/70 dark:text-amber-100/90 text-xs font-ancient-small border border-ancient-accent/20 dark:border-amber-700/40 tag-item" data-tag-value={tag.toLowerCase()}>
{tag}
</span>
))}
{culture.data.tags.length > 3 && (
<span class="px-2 py-1 bg-ancient-paper-light/50 dark:bg-dark-surface text-ancient-black/70 dark:text-amber-100/90 text-xs font-ancient-small border border-ancient-accent/20 dark:border-amber-700/40">
+{culture.data.tags.length - 3}
</span>
)}
</div>
<div class="flex flex-wrap gap-1.5 mb-4 min-h-[2rem]">
{culture.data.tags.slice(0, 3).map((tag: string) => (
<span class="px-2 py-1 bg-ancient-paper-light/50 dark:bg-dark-surface text-ancient-black/70 dark:text-amber-100/90 text-xs font-ancient-small border border-ancient-accent/20 dark:border-amber-700/40 tag-item" data-tag-value={tag.toLowerCase()}>
{tag}
</span>
))}
{culture.data.tags.length > 3 && (
<span class="px-2 py-1 bg-ancient-paper-light/50 dark:bg-dark-surface text-ancient-black/70 dark:text-amber-100/90 text-xs font-ancient-small border border-ancient-accent/20 dark:border-amber-700/40">
+{culture.data.tags.length - 3}
</span>
)}
</div>
{/* 在卡片中添加城市信息显示 */}
<div class="min-h-[1.5rem]">
{culture.data.city && culture.data.city.length > 0 && (
<div class="flex flex-wrap gap-1.5 mt-1 mb-2">
{culture.data.city.slice(0, 2).map((cityName: string) => (
<span class="px-2 py-1 bg-amber-100/50 dark:bg-amber-900/50 text-ancient-black/70 dark:text-amber-100 text-xs font-ancient-small border border-amber-200/50 dark:border-amber-600/50 city-tag" data-city-value={cityName.toLowerCase()}>
{cityName}
</span>
))}
{culture.data.city.length > 2 && (
<span class="px-2 py-1 bg-amber-100/50 dark:bg-amber-900/50 text-ancient-black/70 dark:text-amber-100 text-xs font-ancient-small border border-amber-200/50 dark:border-amber-600/50">
+{culture.data.city.length - 2}
</span>
)}
</div>
)}
</div>
{/* 在卡片中添加城市信息显示 */}
<div class="min-h-[1.5rem]">
{culture.data.city && culture.data.city.length > 0 && (
<div class="flex flex-wrap gap-1.5 mt-1 mb-2">
{culture.data.city.slice(0, 2).map((cityName: string) => (
<span class="px-2 py-1 bg-amber-100/50 dark:bg-amber-900/50 text-ancient-black/70 dark:text-amber-100 text-xs font-ancient-small border border-amber-200/50 dark:border-amber-600/50 city-tag" data-city-value={cityName.toLowerCase()}>
{cityName}
</span>
))}
{culture.data.city.length > 2 && (
<span class="px-2 py-1 bg-amber-100/50 dark:bg-amber-900/50 text-ancient-black/70 dark:text-amber-100 text-xs font-ancient-small border border-amber-200/50 dark:border-amber-600/50">
+{culture.data.city.length - 2}
</span>
)}
</div>
)}
</div>
<div class="flex items-center text-ancient-black/80 dark:text-amber-200 text-sm group-hover:translate-x-1 transition-transform font-ancient-small group-hover:text-ancient-red dark:group-hover:text-amber-300 mt-auto">
查阅详情
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-1" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</div>
<div class="flex items-center text-ancient-black/80 dark:text-amber-200 text-sm group-hover:translate-x-1 font-ancient-small group-hover:text-ancient-red dark:group-hover:text-amber-300 mt-auto">
查阅详情
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-1" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</div>
</div>
</a>
</ScrollReveal>
</div>
</a>
))}
</div>
@ -644,7 +645,7 @@ const buildUrl = (params: Record<string, string | null>) => {
抱歉,未找到相关文化内容。请尝试其他关键词或浏览所有内容。
</p>
<div class="mt-6 flex flex-col space-y-3">
<a href="/culture" class="text-ancient-red hover:text-ancient-red/70 dark:text-ancient-red-dark dark:hover:text-ancient-red-dark/70 font-ancient-small transition-colors">
<a href="/culture" class="text-ancient-red hover:text-ancient-red/70 dark:text-ancient-red-dark dark:hover:text-ancient-red-dark/70 font-ancient-small">
查看所有文化内容 &rarr;
</a>
<button id="reset-filters-btn" class="mx-auto px-4 py-2 bg-ancient-paper/70 dark:bg-ancient-paper-dark/70 text-ancient-black dark:text-ancient-white text-sm font-ancient-small border border-ancient-accent/30 dark:border-ancient-accent-dark/30 hover:border-ancient-accent/50 dark:hover:border-ancient-accent-dark/50 hover:text-ancient-accent dark:hover:text-ancient-accent-dark">
@ -747,23 +748,8 @@ const buildUrl = (params: Record<string, string | null>) => {
<script>
document.addEventListener('DOMContentLoaded', () => {
// 同步黑暗模式与Tailwind的兼容代码
function syncDarkModeClasses() {
const isDarkTheme = document.documentElement.getAttribute('data-theme') === 'dark';
if (isDarkTheme) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
// 初始同步一次
syncDarkModeClasses();
// 监听主题变更事件
window.addEventListener('theme-change', () => {
syncDarkModeClasses();
});
// 移动端筛选抽屉
const mobileFilterToggle = document.getElementById('mobile-filter-toggle');
@ -950,6 +936,13 @@ const buildUrl = (params: Record<string, string | null>) => {
const currentTag = params.get('tag');
const currentSearch = params.get('search');
console.log('当前筛选参数:', {
category: currentCategory,
city: currentCity,
tag: currentTag,
search: currentSearch
});
// 更新分类选中状态
document.querySelectorAll('a[href*="?category"]').forEach(link => {
try {
@ -958,29 +951,23 @@ const buildUrl = (params: Record<string, string | null>) => {
// 检查是否选中
const isSelected = currentCategory === linkCategory;
console.log('分类项:', linkCategory, '是否选中:', isSelected);
// 处理带复选框的分类项(桌面端左侧栏)
const checkbox = link.querySelector('div.w-4.h-4');
if (checkbox) {
console.log('找到分类复选框:', checkbox);
if (isSelected) {
checkbox.className = 'w-4 h-4 border border-ancient-accent/50 dark:border-ancient-accent-dark/50 mr-2 flex-shrink-0 w-full h-full bg-ancient-accent/60 dark:bg-ancient-accent-dark/60';
checkbox.className = 'w-4 h-4 border border-ancient-accent/50 dark:border-ancient-accent-dark/50 mr-2 flex-shrink-0 relative';
checkbox.innerHTML = '<div class="absolute inset-0 flex items-center justify-center"><div class="w-2 h-3 border-r-2 border-b-2 border-ancient-accent dark:border-ancient-accent-dark transform rotate-45 -translate-y-1/4"></div></div>';
// 同时更新父元素背景
link.classList.add('bg-ancient-accent/10', 'dark:bg-ancient-accent-dark/10');
} else {
checkbox.className = 'w-4 h-4 border border-ancient-accent/50 dark:border-ancient-accent-dark/50 mr-2 flex-shrink-0 group-hover:bg-ancient-accent/20 dark:group-hover:bg-ancient-accent-dark/20 transition-colors';
} else {
checkbox.className = 'w-4 h-4 border border-ancient-accent/50 dark:border-ancient-accent-dark/50 mr-2 flex-shrink-0 group-hover:bg-ancient-accent/20 dark:group-hover:bg-ancient-accent-dark/20';
checkbox.innerHTML = '';
link.classList.remove('bg-ancient-accent/10', 'dark:bg-ancient-accent-dark/10');
}
}
// 处理移动端分类标签样式(移动端筛选抽屉)
else if (link.classList.contains('px-3')) {
if (isSelected) {
link.classList.add('border-ancient-accent', 'dark:border-ancient-accent-dark', 'text-ancient-accent', 'dark:text-ancient-accent-dark', 'font-medium', 'bg-ancient-accent/10', 'dark:bg-ancient-accent-dark/10');
link.classList.remove('border-ancient-accent/30', 'dark:border-ancient-accent-dark/30');
} else {
link.classList.remove('border-ancient-accent', 'dark:border-ancient-accent-dark', 'text-ancient-accent', 'dark:text-ancient-accent-dark', 'font-medium', 'bg-ancient-accent/10', 'dark:bg-ancient-accent-dark/10');
link.classList.add('border-ancient-accent/30', 'dark:border-ancient-accent-dark/30');
}
}
} catch (e) {
console.error('Error updating category UI:', e);
}
@ -994,29 +981,22 @@ const buildUrl = (params: Record<string, string | null>) => {
// 检查是否选中
const isSelected = currentCity === linkCity;
console.log('城市项:', linkCity, '是否选中:', isSelected);
// 处理带复选框的城市项(桌面端左侧栏)
const checkbox = link.querySelector('div.w-4.h-4');
if (checkbox) {
console.log('找到城市复选框:', checkbox);
if (isSelected) {
checkbox.className = 'w-4 h-4 border border-amber-300/50 dark:border-amber-700/50 mr-2 flex-shrink-0 w-full h-full bg-amber-400/60 dark:bg-amber-600/60';
// 同时更新父元素背景
link.classList.add('bg-amber-100/50', 'dark:bg-amber-800/20');
} else {
checkbox.className = 'w-4 h-4 border border-amber-300/50 dark:border-amber-700/50 mr-2 flex-shrink-0 group-hover:bg-amber-200/40 dark:group-hover:bg-amber-700/30 transition-colors';
link.classList.remove('bg-amber-100/50', 'dark:bg-amber-800/20');
checkbox.className = 'w-4 h-4 border border-amber-300/50 dark:border-amber-700/50 mr-2 flex-shrink-0 relative';
checkbox.innerHTML = '<div class="absolute inset-0 flex items-center justify-center"><div class="w-2 h-3 border-r-2 border-b-2 border-amber-400 dark:border-amber-600 transform rotate-45 -translate-y-1/4"></div></div>';
// 移除橙色背景的添加
} else {
checkbox.className = 'w-4 h-4 border border-amber-300/50 dark:border-amber-700/50 mr-2 flex-shrink-0 group-hover:bg-amber-200/40 dark:group-hover:bg-amber-700/30';
checkbox.innerHTML = '';
// 移除背景移除代码,因为不再添加背景
}
}
// 处理移动端城市标签样式(移动端筛选抽屉)
else if (link.classList.contains('px-3')) {
if (isSelected) {
link.classList.add('bg-amber-100', 'dark:bg-amber-800/50', 'border-amber-300', 'dark:border-amber-600', 'text-amber-800', 'dark:text-amber-200', 'font-medium', 'shadow-sm');
link.classList.remove('bg-amber-100/50', 'dark:bg-amber-800/30', 'border-amber-200/50', 'dark:border-amber-700/30');
} else {
link.classList.remove('bg-amber-100', 'dark:bg-amber-800/50', 'border-amber-300', 'dark:border-amber-600', 'text-amber-800', 'dark:text-amber-200', 'font-medium', 'shadow-sm');
link.classList.add('bg-amber-100/50', 'dark:bg-amber-800/30', 'border-amber-200/50', 'dark:border-amber-700/30');
}
}
} catch (e) {
console.error('Error updating city UI:', e);
}
@ -1118,7 +1098,6 @@ const buildUrl = (params: Record<string, string | null>) => {
overflow: hidden;
background-color: rgba(248, 245, 232, 0.7);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
}
[data-theme='dark'] .ancient-card {
@ -1156,7 +1135,6 @@ const buildUrl = (params: Record<string, string | null>) => {
right: 0;
width: 80px;
height: 80px;
background-image: url('/images/red-seal.png');
background-size: contain;
background-repeat: no-repeat;
opacity: 0.2;
@ -1175,10 +1153,6 @@ const buildUrl = (params: Record<string, string | null>) => {
}
}
.scroll-decoration {
animation: unrollScroll 1.2s ease-out;
}
/* 印章浮现动画 */
@keyframes revealSeal {
0% {
@ -1195,12 +1169,6 @@ const buildUrl = (params: Record<string, string | null>) => {
}
}
.seal {
animation: revealSeal 1.5s ease-out forwards;
animation-delay: 0.8s;
opacity: 0;
}
/* 水墨渐显动画 */
@keyframes inkReveal {
0% {
@ -1213,9 +1181,7 @@ const buildUrl = (params: Record<string, string | null>) => {
}
}
.bg-ink-splash, .bg-ink-decoration, .bg-ink-flower {
animation: inkReveal 2s ease-out forwards;
}
/* 隐藏滚动条但保留功能 */
.hide-scrollbar {
@ -1255,7 +1221,6 @@ const buildUrl = (params: Record<string, string | null>) => {
border-radius: 0.25rem;
border: 2px solid #8B5A2B;
overflow: hidden;
transition: all 0.3s ease;
box-sizing: border-box;
display: flex;
align-items: center;
@ -1281,7 +1246,6 @@ const buildUrl = (params: Record<string, string | null>) => {
transform: translate(-50%, -50%) scale(0);
color: #8B5A2B;
opacity: 0;
transition: all 0.2s ease;
width: 100%;
height: 100%;
display: flex;
@ -1324,7 +1288,6 @@ const buildUrl = (params: Record<string, string | null>) => {
.tag-item:hover {
transform: scale(1.05);
box-shadow: 0 2px 4px rgba(139, 90, 43, 0.1);
transition: all 0.2s ease;
}
/* 鼠标悬停在标签上的效果 */
@ -1341,7 +1304,6 @@ const buildUrl = (params: Record<string, string | null>) => {
border-radius: 0.25rem;
border: 2px solid rgba(139, 90, 43, 0.5);
overflow: hidden;
transition: all 0.3s ease;
box-sizing: border-box;
display: flex;
align-items: center;
@ -1360,7 +1322,6 @@ const buildUrl = (params: Record<string, string | null>) => {
.flex.items-center.group.cursor-pointer:hover .w-4.h-4 {
background-color: rgba(139, 90, 43, 0.1);
border-color: #8B5A2B;
transition: all 0.2s ease;
}
/* 黑暗模式下的背景和内容区优化 */
@ -1491,7 +1452,6 @@ const buildUrl = (params: Record<string, string | null>) => {
/* 增强卡片阴影渐变效果 */
[data-theme='dark'] .ancient-card {
transition: all 0.4s cubic-bezier(0.215, 0.61, 0.355, 1);
backface-visibility: hidden;
}
@ -1695,7 +1655,6 @@ const buildUrl = (params: Record<string, string | null>) => {
overflow: hidden;
background-color: rgba(248, 245, 232, 0.7);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
}
/* 卡片内容区域 */
@ -1818,10 +1777,6 @@ const buildUrl = (params: Record<string, string | null>) => {
}
/* 暗色模式下卡片阴影和边框过渡效果 */
[data-theme='dark'] .ancient-card {
transition: all 0.4s ease;
}
[data-theme='dark'] .ancient-card:hover {
transform: translateY(-2px);
}
@ -1869,10 +1824,6 @@ const buildUrl = (params: Record<string, string | null>) => {
background-color: var(--color-dark-paper);
}
.bg-ancient-paper-light {
background-color: rgba(248, 245, 232, 0.5);
}
.bg-ancient-paper-dark-light {
background-color: rgba(52, 46, 38, 0.5);
}
@ -1891,17 +1842,12 @@ const buildUrl = (params: Record<string, string | null>) => {
}
/* 地域分布样式 - 明亮模式 */
.font-ancient-body.max-h-48 a[href*="?city"] {
transition: all 0.3s ease;
}
.font-ancient-body.max-h-48 a[href*="?city"]:hover {
background-color: rgba(251, 191, 36, 0.1);
}
.font-ancient-body.max-h-48 a[href*="?city"] .w-4.h-4 {
border-color: rgba(251, 191, 36, 0.5);
transition: all 0.3s ease;
}
.font-ancient-body.max-h-48 a[href*="?city"]:hover .w-4.h-4 {
@ -1919,9 +1865,7 @@ const buildUrl = (params: Record<string, string | null>) => {
}
/* 文化分类样式 - 明亮模式 */
.font-ancient-body.max-h-48 a[href*="?category"] {
transition: all 0.3s ease;
}
.font-ancient-body.max-h-48 a[href*="?category"]:hover {
background-color: rgba(139, 90, 43, 0.1);
@ -1929,7 +1873,6 @@ const buildUrl = (params: Record<string, string | null>) => {
.font-ancient-body.max-h-48 a[href*="?category"] .w-4.h-4 {
border-color: rgba(139, 90, 43, 0.5);
transition: all 0.3s ease;
}
.font-ancient-body.max-h-48 a[href*="?category"]:hover .w-4.h-4 {
@ -1947,9 +1890,6 @@ const buildUrl = (params: Record<string, string | null>) => {
}
/* 文化分类样式 - 暗黑模式 */
[data-theme='dark'] .font-ancient-body.max-h-48 a[href*="?category"] {
transition: all 0.3s ease;
}
[data-theme='dark'] .font-ancient-body.max-h-48 a[href*="?category"]:hover {
background-color: rgba(215, 171, 101, 0.1);
@ -1957,7 +1897,6 @@ const buildUrl = (params: Record<string, string | null>) => {
[data-theme='dark'] .font-ancient-body.max-h-48 a[href*="?category"] .w-4.h-4 {
border-color: rgba(215, 171, 101, 0.5);
transition: all 0.3s ease;
}
[data-theme='dark'] .font-ancient-body.max-h-48 a[href*="?category"]:hover .w-4.h-4 {
@ -1975,9 +1914,6 @@ const buildUrl = (params: Record<string, string | null>) => {
}
/* 地域分布样式 - 暗黑模式 */
[data-theme='dark'] .font-ancient-body.max-h-48 a[href*="?city"] {
transition: all 0.3s ease;
}
[data-theme='dark'] .font-ancient-body.max-h-48 a[href*="?city"]:hover {
background-color: rgba(180, 83, 9, 0.2);
@ -1985,7 +1921,6 @@ const buildUrl = (params: Record<string, string | null>) => {
[data-theme='dark'] .font-ancient-body.max-h-48 a[href*="?city"] .w-4.h-4 {
border-color: rgba(180, 83, 9, 0.5);
transition: all 0.3s ease;
}
[data-theme='dark'] .font-ancient-body.max-h-48 a[href*="?city"]:hover .w-4.h-4 {
@ -2010,7 +1945,6 @@ const buildUrl = (params: Record<string, string | null>) => {
height: 1rem;
border-radius: 0.25rem;
overflow: hidden;
transition: all 0.3s ease;
box-sizing: border-box;
display: flex;
align-items: center;
@ -2061,7 +1995,6 @@ const buildUrl = (params: Record<string, string | null>) => {
/* 特色标签样式 */
.flex.flex-wrap.gap-2 a[href*="?tag"] {
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}

View File

@ -1,7 +1,6 @@
---
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 {
@ -38,210 +37,203 @@ const relatedTravels = allTravels
<!-- 页面标题区域 -->
<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 class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<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>
</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="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="grid grid-cols-1 lg:grid-cols-12 gap-6">
<!-- 左侧内容 -->
<div class="lg:col-span-2">
<ScrollReveal animation="fade">
<div class="prose prose-lg dark:prose-invert max-w-none">
<Content />
</div>
</ScrollReveal>
<div class="lg:col-span-8">
<div class="prose prose-lg dark:prose-invert max-w-none">
<Content />
</div>
</div>
<!-- 右侧边栏 -->
<div class="space-y-8">
<div class="lg:col-span-4 space-y-6">
<!-- 旅行图片 -->
<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 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>
</ScrollReveal>
</div>
<!-- 攻略信息卡片 -->
<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="bg-gray-50 dark:bg-slate-800 dark:border dark:border-slate-700 rounded-lg shadow-md p-6">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center">
<span class="inline-block mr-2 w-1 h-6 bg-color-primary-500 rounded"></span>
攻略信息
</h3>
<div class="space-y-3">
{entry.data.season && (
<div class="flex">
<span class="w-24 flex-shrink-0 text-gray-600 dark:text-white font-medium">适宜季节:</span>
<span class="text-gray-900 dark:text-color-primary-200">{entry.data.season}</span>
</div>
)}
<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>
)}
{entry.data.type && (
<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>
<span class="w-24 flex-shrink-0 text-gray-600 dark:text-white font-medium">攻略类型:</span>
<span class="text-gray-900 dark:text-color-primary-200">{entry.data.type}</span>
</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">
{entry.data.days && (
<div class="flex">
<span class="mr-2">✓</span>
<p>出行前查看天气预报,准备合适的衣物</p>
<span class="w-24 flex-shrink-0 text-gray-600 dark:text-white font-medium">行程天数:</span>
<span class="text-gray-900 dark:text-color-primary-200">{entry.data.days}天</span>
</div>
)}
{entry.data.difficulty && (
<div class="flex">
<span class="mr-2">✓</span>
<p>提前规划路线,预订住宿和交通</p>
<span class="w-24 flex-shrink-0 text-gray-600 dark:text-white font-medium">难度级别:</span>
<span class="text-gray-900 dark:text-color-primary-200">{entry.data.difficulty}</span>
</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 class="flex">
<span class="w-24 flex-shrink-0 text-gray-600 dark:text-white font-medium">旅行主题:</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-primary-600 dark:text-white">
{tag}
</span>
))}
</div>
</div>
</ScrollReveal>
{entry.data.pubDate && (
<div class="flex">
<span class="w-24 flex-shrink-0 text-gray-600 dark:text-white font-medium">发布时间:</span>
<span class="text-gray-900 dark:text-color-primary-200">{new Date(entry.data.pubDate).toLocaleDateString('zh-CN')}</span>
</div>
)}
</div>
</div>
<!-- 旅行小贴士 -->
<div class="bg-color-primary-50 dark:bg-slate-800 dark:border dark:border-color-primary-700 rounded-lg shadow-md p-6">
<h3 class="text-xl font-semibold text-color-primary-800 dark:text-color-primary-400 mb-4 flex items-center">
<span class="inline-block mr-2 w-1 h-6 bg-color-primary-500 rounded"></span>
旅行小贴士
</h3>
<div class="space-y-3 text-color-primary-700 dark:text-white">
<div class="flex">
<span class="mr-2 text-color-primary-500 dark:text-color-primary-400">✓</span>
<p>出行前查看天气预报,准备合适的衣物</p>
</div>
<div class="flex">
<span class="mr-2 text-color-primary-500 dark:text-color-primary-400">✓</span>
<p>提前规划路线,预订住宿和交通</p>
</div>
<div class="flex">
<span class="mr-2 text-color-primary-500 dark:text-color-primary-400">✓</span>
<p>携带必要的药品和紧急联系方式</p>
</div>
<div class="flex">
<span class="mr-2 text-color-primary-500 dark:text-color-primary-400">✓</span>
<p>尊重当地风俗习惯,做文明旅行者</p>
</div>
</div>
</div>
<!-- 相关攻略 -->
{relatedTravels.length > 0 && (
<div class="bg-gray-50 dark:bg-slate-800 dark:border dark:border-slate-700 rounded-lg shadow-md p-6">
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center">
<span class="inline-block mr-2 w-1 h-6 bg-color-primary-500 rounded"></span>
相关攻略
</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 p-3 rounded-lg hover:bg-gray-100 dark:hover:bg-slate-700/50 transition-colors">
<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-300">图片</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-color-primary-300 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-300 line-clamp-2 mt-1">
{travel.data.description.substring(0, 60)}...
</p>
</div>
</div>
</a>
))}
</div>
</div>
)}
<!-- 返回按钮 -->
<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>
<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>
</div>
</div>
</div>

View File

@ -1,25 +1,23 @@
---
import MainLayout from "../../layouts/MainLayout.astro";
import { getCollection, type CollectionEntry } from "astro:content";
import ScrollReveal from "../../components/aceternity/ScrollReveal.astro";
import MainLayout from "../../layouts/MainLayout.astro";
// 获取旅行攻略集合
const travels = await getCollection("travel");
// 获取所有旅行数据并按发布日期排序
const allTravels = await getCollection("travel");
// 按发布日期排序
function sortByDate<T extends { data: { pubDate?: Date | string, updatedDate?: Date | string } }>(a: T, b: T): number {
return new Date(b.data.pubDate || b.data.updatedDate || 0).getTime() -
new Date(a.data.pubDate || a.data.updatedDate || 0).getTime();
const sortByDate = (a: CollectionEntry<"travel">, b: CollectionEntry<"travel">) => {
return new Date(b.data.pubDate || 0).getTime() - new Date(a.data.pubDate || 0).getTime();
}
const sortedTravels = [...travels].sort(sortByDate);
const sortedTravels = [...allTravels].sort(sortByDate);
// 检查是否有旅行攻略内容
const hasTravels = travels.length > 0;
const hasTravels = allTravels.length > 0;
// 提取所有标签并按数量排序
const allTags: {name: string, count: number}[] = [];
travels.forEach((travel) => {
allTravels.forEach((travel: CollectionEntry<"travel">) => {
travel.data.tags.forEach((tag: string) => {
const existing = allTags.find(t => t.name === tag);
if (existing) {
@ -30,57 +28,49 @@ travels.forEach((travel) => {
});
});
const sortedTags = [...allTags].sort((a, b) => b.count - a.count);
// 按出现次数排序
allTags.sort((a, b) => b.count - a.count);
// 提取所有季节
const allSeasons = new Set<string>();
travels.forEach((travel) => {
allTravels.forEach((travel: CollectionEntry<"travel">) => {
if (travel.data.season) {
allSeasons.add(travel.data.season);
}
});
const seasons = Array.from(allSeasons);
// 提取所有类型
const allTypes = new Set<string>();
travels.forEach((travel) => {
allTravels.forEach((travel: CollectionEntry<"travel">) => {
if (travel.data.type) {
allTypes.add(travel.data.type);
}
});
const types = Array.from(allTypes);
// 提取所有难度
const allDifficulties = new Set<string>();
travels.forEach((travel) => {
if (travel.data.difficulty) {
allDifficulties.add(travel.data.difficulty);
}
});
// 提取所有城市
const cities: {name: string, count: number}[] = [];
travels.forEach((travel) => {
if (travel.data.city && travel.data.city.length > 0) {
// 遍历每个城市数组
travel.data.city.forEach(cityName => {
const existingCity = cities.find(c => c.name === cityName);
if (existingCity) {
existingCity.count++;
} else {
cities.push({ name: cityName, count: 1 });
}
const allCities = new Set<string>();
allTravels.forEach((travel: CollectionEntry<"travel">) => {
if (travel.data.city && Array.isArray(travel.data.city)) {
travel.data.city.forEach((cityName: string) => {
allCities.add(cityName);
});
}
});
// 按城市出现次数排序
cities.sort((a, b) => b.count - a.count);
// 将Set转换为数组
const seasonArray = Array.from(allSeasons);
const typeArray = Array.from(allTypes);
const cityArray = Array.from(allCities);
// 分页相关
const itemsPerPage = 10;
const totalPages = Math.ceil(sortedTravels.length / itemsPerPage);
// 当前页码和每页显示数量
const currentPage = 1;
const itemsPerPage = 10;
// 计算总页数
const totalTravels = sortedTravels.length;
const totalPages = Math.ceil(totalTravels / itemsPerPage);
// 获取当前页面的旅行攻略
const visibleTravels = sortedTravels.slice(
(currentPage - 1) * itemsPerPage,
currentPage * itemsPerPage
@ -94,7 +84,7 @@ const visibleTravels = sortedTravels.slice(
<div class="absolute top-16 right-0 w-40 h-40 bg-[url('/images/ink-splash.png')] bg-no-repeat opacity-10"></div>
<div class="absolute bottom-0 left-0 w-32 h-32 bg-[url('/images/coffee-stain.png')] bg-no-repeat opacity-5"></div>
<div class="container mx-auto px-4 relative">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative">
<div class="max-w-4xl mx-auto">
<!-- 手绘风格标题 -->
<div class="mb-10 relative">
@ -153,7 +143,7 @@ const visibleTravels = sortedTravels.slice(
<div class="absolute top-20 right-20 w-60 h-60 bg-[url('/images/map-element.png')] bg-no-repeat opacity-5"></div>
<div class="absolute bottom-40 left-40 w-48 h-48 bg-[url('/images/compass-rose.png')] bg-no-repeat opacity-5 transform rotate-15"></div>
<div class="container mx-auto px-4">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<!-- 移动端筛选切换按钮 -->
<div class="lg:hidden mb-6">
<button id="mobile-filter-toggle" class="w-full py-3 px-4 flex items-center justify-between bg-white dark:bg-slate-800 rounded-sm border border-slate-200 dark:border-slate-700 shadow-md transform -rotate-1 relative">
@ -243,7 +233,7 @@ const visibleTravels = sortedTravels.slice(
最适季节
</h3>
<div class="stickers-container">
{seasons.map((season) => (
{seasonArray.map((season) => (
<div class="filter-sticker season-sticker" data-value={season}>
{season}
</div>
@ -258,7 +248,7 @@ const visibleTravels = sortedTravels.slice(
旅行方式
</h3>
<div class="stickers-container">
{types.map((type) => (
{typeArray.map((type) => (
<div class="filter-sticker type-sticker" data-value={type}>
{type}
</div>
@ -273,9 +263,9 @@ const visibleTravels = sortedTravels.slice(
目的地城市
</h3>
<div class="stickers-container">
{cities.map((city) => (
<div class="filter-sticker city-sticker" data-value={city.name}>
{city.name} <span class="sticker-count">({city.count})</span>
{cityArray.map((city) => (
<div class="filter-sticker city-sticker" data-value={city}>
{city} <span class="sticker-count">({cityArray.filter(c => c === city).length})</span>
</div>
))}
</div>
@ -288,7 +278,7 @@ const visibleTravels = sortedTravels.slice(
旅行灵感
</h3>
<div class="stickers-container">
{sortedTags.slice(0, 10).map((tag) => (
{allTags.slice(0, 10).map((tag) => (
<div class="filter-sticker tag-sticker" data-value={tag.name}>
#{tag.name} <span class="sticker-count">({tag.count})</span>
</div>
@ -344,98 +334,96 @@ const visibleTravels = sortedTravels.slice(
<div id="travel-list" class="space-y-10">
{hasTravels ? (
visibleTravels.map((travel, index) => (
<ScrollReveal animation={index % 2 === 0 ? "slide-right" : "slide-left"}>
<a
href={`/travel/${travel.slug}`}
class="block group"
<a
href={`/travel/${travel.slug}`}
class="block group"
>
<div class={`bg-white dark:bg-slate-800 rounded-sm border border-slate-200 dark:border-slate-700 overflow-hidden shadow-md transform ${index % 2 === 0 ? 'rotate-1' : '-rotate-1'} hover:shadow-lg transition-shadow relative`}
data-tags={JSON.stringify(travel.data.tags)}
data-season={travel.data.season}
data-type={travel.data.type}
data-cities={JSON.stringify(travel.data.city)}
data-title={travel.data.title}
data-description={travel.data.description}
>
<div class={`bg-white dark:bg-slate-800 rounded-sm border border-slate-200 dark:border-slate-700 overflow-hidden shadow-md transform ${index % 2 === 0 ? 'rotate-1' : '-rotate-1'} hover:shadow-lg transition-shadow relative`}
data-tags={JSON.stringify(travel.data.tags)}
data-season={travel.data.season}
data-type={travel.data.type}
data-cities={JSON.stringify(travel.data.city)}
data-title={travel.data.title}
data-description={travel.data.description}
>
<!-- 装饰性元素 -->
<div class="absolute top-3 right-3 w-16 h-16 bg-[url('/images/polaroid-corner.png')] bg-contain bg-no-repeat opacity-20"></div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-0">
<div class="md:col-span-1 h-full">
<div class="h-48 md:h-full bg-primary-100 dark:bg-slate-700 relative border-b md:border-r border-slate-200 dark:border-slate-700">
<div class="flex items-center justify-center h-full font-handwriting italic text-slate-500 dark:text-slate-400">
{travel.data.title} 照片
<!-- 装饰性元素 -->
<div class="absolute top-3 right-3 w-16 h-16 bg-[url('/images/polaroid-corner.png')] bg-contain bg-no-repeat opacity-20"></div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-0">
<div class="md:col-span-1 h-full">
<div class="h-48 md:h-full bg-primary-100 dark:bg-slate-700 relative border-b md:border-r border-slate-200 dark:border-slate-700">
<div class="flex items-center justify-center h-full font-handwriting italic text-slate-500 dark:text-slate-400">
{travel.data.title} 照片
</div>
{travel.data.featured && (
<div class="absolute top-3 left-3 px-3 py-1 bg-primary-100 dark:bg-primary-900/40 text-primary-800 dark:text-primary-400 text-xs font-handwriting border border-primary-200 dark:border-primary-800/50 transform -rotate-3 shadow-sm">
★ 私藏路线
</div>
{travel.data.featured && (
<div class="absolute top-3 left-3 px-3 py-1 bg-primary-100 dark:bg-primary-900/40 text-primary-800 dark:text-primary-400 text-xs font-handwriting border border-primary-200 dark:border-primary-800/50 transform -rotate-3 shadow-sm">
★ 私藏路线
</div>
)}
</div>
)}
</div>
<div class="md:col-span-2 p-6">
<h3 class="text-2xl font-handwriting text-slate-800 dark:text-primary-100 mb-3 group-hover:text-primary-800 dark:group-hover:text-primary-400 transition-colors">
{travel.data.title}
</h3>
</div>
<div class="md:col-span-2 p-6">
<h3 class="text-2xl font-handwriting text-slate-800 dark:text-primary-100 mb-3 group-hover:text-primary-800 dark:group-hover:text-primary-400 transition-colors">
{travel.data.title}
</h3>
<div class="flex flex-wrap gap-4 mb-4 text-sm font-handwriting text-slate-600 dark:text-slate-400">
{travel.data.season && (
<div class="flex items-center">
<span class="inline-block w-4 h-4 mr-1 bg-[url('/images/season-small.png')] bg-contain bg-no-repeat"></span>
{travel.data.season}
</div>
)}
<div class="flex flex-wrap gap-4 mb-4 text-sm font-handwriting text-slate-600 dark:text-slate-400">
{travel.data.season && (
<div class="flex items-center">
<span class="inline-block w-4 h-4 mr-1 bg-[url('/images/season-small.png')] bg-contain bg-no-repeat"></span>
{travel.data.season}
</div>
)}
{travel.data.type && (
<div class="flex items-center">
<span class="inline-block w-4 h-4 mr-1 bg-[url('/images/type-small.png')] bg-contain bg-no-repeat"></span>
{travel.data.type}
</div>
)}
{travel.data.days && (
<div class="flex items-center">
<span class="inline-block w-4 h-4 mr-1 bg-[url('/images/days-small.png')] bg-contain bg-no-repeat"></span>
{travel.data.days}天
</div>
)}
{travel.data.difficulty && (
<div class="flex items-center">
<span class="inline-block w-4 h-4 mr-1 bg-[url('/images/difficulty-small.png')] bg-contain bg-no-repeat"></span>
难度: {travel.data.difficulty}
</div>
)}
</div>
{travel.data.type && (
<div class="flex items-center">
<span class="inline-block w-4 h-4 mr-1 bg-[url('/images/type-small.png')] bg-contain bg-no-repeat"></span>
{travel.data.type}
</div>
)}
<p class="font-handwriting text-slate-600 dark:text-slate-400 leading-relaxed mb-4 line-clamp-3">
{travel.data.description}
</p>
{travel.data.days && (
<div class="flex items-center">
<span class="inline-block w-4 h-4 mr-1 bg-[url('/images/days-small.png')] bg-contain bg-no-repeat"></span>
{travel.data.days}天
</div>
)}
<div class="flex flex-wrap gap-2 mb-3">
{travel.data.tags.slice(0, 3).map((tag: string) => (
<span class="px-2 py-0.5 text-xs font-handwriting bg-slate-100 dark:bg-slate-700 text-slate-600 dark:text-slate-400 border border-slate-200 dark:border-slate-600">
#{tag}
</span>
))}
{travel.data.tags.length > 3 && (
<span class="px-2 py-0.5 text-xs font-handwriting bg-slate-100 dark:bg-slate-700 text-slate-600 dark:text-slate-400 border border-slate-200 dark:border-slate-600">
+{travel.data.tags.length - 3}
</span>
)}
</div>
<div class="text-primary-700 dark:text-primary-500 text-sm font-handwriting group-hover:underline mt-2 flex items-center">
阅读完整笔记
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-1" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</div>
{travel.data.difficulty && (
<div class="flex items-center">
<span class="inline-block w-4 h-4 mr-1 bg-[url('/images/difficulty-small.png')] bg-contain bg-no-repeat"></span>
难度: {travel.data.difficulty}
</div>
)}
</div>
<p class="font-handwriting text-slate-600 dark:text-slate-400 leading-relaxed mb-4 line-clamp-3">
{travel.data.description}
</p>
<div class="flex flex-wrap gap-2 mb-3">
{travel.data.tags.slice(0, 3).map((tag: string) => (
<span class="px-2 py-0.5 text-xs font-handwriting bg-slate-100 dark:bg-slate-700 text-slate-600 dark:text-slate-400 border border-slate-200 dark:border-slate-600">
#{tag}
</span>
))}
{travel.data.tags.length > 3 && (
<span class="px-2 py-0.5 text-xs font-handwriting bg-slate-100 dark:bg-slate-700 text-slate-600 dark:text-slate-400 border border-slate-200 dark:border-slate-600">
+{travel.data.tags.length - 3}
</span>
)}
</div>
<div class="text-primary-700 dark:text-primary-500 text-sm font-handwriting group-hover:underline mt-2 flex items-center">
阅读完整笔记
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-1" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</div>
</div>
</div>
</a>
</ScrollReveal>
</div>
</a>
))
) : (
<div class="bg-white dark:bg-slate-800 p-8 text-center rounded-sm border border-slate-200 dark:border-slate-700 shadow-md mb-10 relative transform rotate-1">

View File

@ -90,12 +90,6 @@
--color-dark-primary-900: #faefdb;
}
/* 确保在无JavaScript环境下ScrollReveal元素仍然可见 */
.no-js .scroll-reveal {
opacity: 1 !important;
transform: none !important;
}
/* 当JS加载完成时移除no-js类 */
html {
&.no-js {