毕设大部分筛选没问题
This commit is contained in:
parent
b5260f1836
commit
ced067142f
@ -1,11 +1,27 @@
|
||||
// @ts-check
|
||||
import { defineConfig } from 'astro/config';
|
||||
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
vite: {
|
||||
plugins: [tailwindcss()]
|
||||
},
|
||||
|
||||
// 服务器配置
|
||||
server: {
|
||||
port: 3000,
|
||||
host: true
|
||||
},
|
||||
|
||||
// Markdown 配置
|
||||
markdown: {
|
||||
syntaxHighlight: 'prism',
|
||||
gfm: true,
|
||||
shikiConfig: {
|
||||
theme: 'github-dark',
|
||||
langs: [],
|
||||
wrap: true,
|
||||
}
|
||||
}
|
||||
});
|
@ -14,25 +14,17 @@
|
||||
|
||||
body * {
|
||||
transition: background-color var(--transition-duration) ease,
|
||||
border-color var(--transition-duration) ease,
|
||||
color var(--transition-duration) ease,
|
||||
fill var(--transition-duration) ease,
|
||||
stroke var(--transition-duration) ease,
|
||||
box-shadow var(--transition-duration) ease;
|
||||
}
|
||||
|
||||
/* 特定元素过渡效果增强 */
|
||||
.card-transition {
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease, background-color var(--transition-duration) ease;
|
||||
}
|
||||
|
||||
/* 防止某些元素过渡,如轮播图等需要即时响应的元素 */
|
||||
/* 防止某些元素过渡 */
|
||||
.no-transition,
|
||||
.no-transition * {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
/* 防止动画闪烁 */
|
||||
/* 响应用户减少动画的设置 */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
html, body * {
|
||||
transition: none !important;
|
||||
|
@ -9,7 +9,7 @@ const { class: className = '' } = Astro.props;
|
||||
<button
|
||||
id="themeToggle"
|
||||
aria-label="切换主题"
|
||||
class={`p-2 rounded-full hover:bg-gray-200 dark:hover:bg-color-dark-card focus:outline-none focus:ring-2 focus:ring-color-primary-400 dark:focus:ring-color-dark-primary-600 ${className}`}
|
||||
class={`p-2 rounded-full hover:bg-gray-200 dark:hover:bg-color-dark-card focus:outline-none ${className}`}
|
||||
>
|
||||
<!-- 亮色主题图标 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon light-icon h-6 w-6 text-gray-800 dark:hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
@ -26,43 +26,29 @@ const { class: className = '' } = Astro.props;
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const themeToggle = document.getElementById('themeToggle');
|
||||
|
||||
// 检查用户之前的主题设置
|
||||
const getStoredTheme = () => {
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
if (savedTheme) return savedTheme;
|
||||
|
||||
// 如果没有存储的主题,检查系统偏好
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
};
|
||||
const getTheme = () => localStorage.getItem('theme') ||
|
||||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
||||
|
||||
// 应用主题
|
||||
const applyTheme = (theme: string) => {
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
localStorage.setItem('theme', theme);
|
||||
|
||||
// 发送主题变更事件,方便其他组件响应
|
||||
window.dispatchEvent(new CustomEvent('theme-change', { detail: { theme } }));
|
||||
};
|
||||
|
||||
// 切换主题
|
||||
const toggleTheme = () => {
|
||||
const currentTheme = document.documentElement.getAttribute('data-theme') || 'light';
|
||||
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
|
||||
applyTheme(newTheme);
|
||||
};
|
||||
|
||||
// 初始化主题
|
||||
applyTheme(getStoredTheme());
|
||||
applyTheme(getTheme());
|
||||
|
||||
// 事件监听
|
||||
// 切换主题事件
|
||||
if (themeToggle) {
|
||||
themeToggle.addEventListener('click', toggleTheme);
|
||||
themeToggle.addEventListener('click', () => {
|
||||
const currentTheme = document.documentElement.getAttribute('data-theme') || 'light';
|
||||
applyTheme(currentTheme === 'light' ? 'dark' : 'light');
|
||||
});
|
||||
}
|
||||
|
||||
// 监听系统主题变化
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
|
||||
if (!localStorage.getItem('theme')) {
|
||||
// 只有当用户没有手动设置主题时才跟随系统变化
|
||||
applyTheme(e.matches ? 'dark' : 'light');
|
||||
}
|
||||
});
|
||||
|
@ -17,8 +17,8 @@ const id = `morphing-text-${Math.random().toString(36).substr(2, 9)}`;
|
||||
<div class={`relative mx-auto w-full max-w-screen-xl text-center font-sans font-bold ${className}`} id={id}>
|
||||
<!-- 容器高度设置为自动,让内容决定高度 -->
|
||||
<div class="relative flex justify-center items-center text-center min-h-[1.5em]">
|
||||
<span class="text-span-1 block ${textSize} opacity-100 blur-none transition-all absolute left-1/2 transform -translate-x-1/2"></span>
|
||||
<span class="text-span-2 absolute left-1/2 transform -translate-x-1/2 block ${textSize} opacity-0 blur-none transition-all"></span>
|
||||
<span class="text-span-1 block ${textSize} opacity-100 transition-all absolute left-1/2 transform -translate-x-1/2">{phrases[0]}</span>
|
||||
<span class="text-span-2 absolute left-1/2 transform -translate-x-1/2 block ${textSize} opacity-0 transition-all"></span>
|
||||
</div>
|
||||
|
||||
<!-- SVG 滤镜 -->
|
||||
@ -49,84 +49,66 @@ const id = `morphing-text-${Math.random().toString(36).substr(2, 9)}`;
|
||||
if (!text1 || !text2) return;
|
||||
|
||||
// 设置初始文本
|
||||
text1.textContent = phrases[0];
|
||||
text2.textContent = phrases[1];
|
||||
|
||||
// 应用滤镜
|
||||
container.style.filter = 'url(#threshold) blur(0.6px)';
|
||||
|
||||
// 变形时间和冷却时间(秒)
|
||||
const morphTime = 1.5;
|
||||
const cooldownTime = 0.5;
|
||||
|
||||
let textIndex = 0;
|
||||
let morph = 0;
|
||||
let cooldown = cooldownTime;
|
||||
|
||||
let currentlyDisplayedIs1 = true;
|
||||
let lastTime = new Date();
|
||||
let animationFrameId;
|
||||
|
||||
function setMorphStyles(fraction) {
|
||||
// 为第二个文本(进入)设置样式
|
||||
text2.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`;
|
||||
text2.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`;
|
||||
|
||||
// 为第一个文本(退出)设置样式
|
||||
const invertedFraction = 1 - fraction;
|
||||
text1.style.filter = `blur(${Math.min(8 / invertedFraction - 8, 100)}px)`;
|
||||
text1.style.opacity = `${Math.pow(invertedFraction, 0.4) * 100}%`;
|
||||
|
||||
// 设置当前和下一个文本内容
|
||||
text1.textContent = phrases[textIndex % phrases.length];
|
||||
text2.textContent = phrases[(textIndex + 1) % phrases.length];
|
||||
}
|
||||
|
||||
function doMorph() {
|
||||
morph -= cooldown;
|
||||
cooldown = 0;
|
||||
|
||||
let fraction = morph / morphTime;
|
||||
|
||||
if (fraction > 1) {
|
||||
cooldown = cooldownTime;
|
||||
fraction = 1;
|
||||
}
|
||||
|
||||
setMorphStyles(fraction);
|
||||
|
||||
if (fraction === 1) {
|
||||
textIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
function doCooldown() {
|
||||
morph = 0;
|
||||
|
||||
text2.style.filter = "none";
|
||||
text2.style.opacity = "100%";
|
||||
|
||||
text1.style.filter = "none";
|
||||
text1.style.opacity = "0%";
|
||||
}
|
||||
|
||||
function animate() {
|
||||
animationFrameId = requestAnimationFrame(animate);
|
||||
|
||||
const newTime = new Date();
|
||||
const dt = (newTime.getTime() - lastTime.getTime()) / 1000;
|
||||
const dt = (newTime - lastTime) / 1000;
|
||||
lastTime = newTime;
|
||||
|
||||
cooldown -= dt;
|
||||
|
||||
if (cooldown <= 0) {
|
||||
doMorph();
|
||||
morph -= cooldown;
|
||||
cooldown = 0;
|
||||
|
||||
let fraction = morph / morphTime;
|
||||
|
||||
if (fraction > 1) {
|
||||
cooldown = cooldownTime;
|
||||
fraction = 1;
|
||||
}
|
||||
|
||||
// 设置元素样式
|
||||
const visibleText = currentlyDisplayedIs1 ? text1 : text2;
|
||||
const hiddenText = currentlyDisplayedIs1 ? text2 : text1;
|
||||
|
||||
hiddenText.style.filter = `blur(${Math.min(8 / fraction - 8, 100)}px)`;
|
||||
hiddenText.style.opacity = `${Math.pow(fraction, 0.4) * 100}%`;
|
||||
|
||||
const invertedFraction = 1 - fraction;
|
||||
visibleText.style.filter = `blur(${Math.min(8 / invertedFraction - 8, 100)}px)`;
|
||||
visibleText.style.opacity = `${Math.pow(invertedFraction, 0.4) * 100}%`;
|
||||
|
||||
visibleText.textContent = phrases[textIndex % phrases.length];
|
||||
hiddenText.textContent = phrases[(textIndex + 1) % phrases.length];
|
||||
|
||||
if (fraction === 1) {
|
||||
textIndex = (textIndex + 1) % phrases.length;
|
||||
currentlyDisplayedIs1 = !currentlyDisplayedIs1;
|
||||
}
|
||||
} else {
|
||||
doCooldown();
|
||||
morph = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 启动动画
|
||||
animate();
|
||||
setTimeout(animate, 100);
|
||||
|
||||
// 清理
|
||||
window.addEventListener('beforeunload', () => {
|
||||
|
@ -0,0 +1,35 @@
|
||||
---
|
||||
title: "承德避暑山庄 - 清朝皇家园林"
|
||||
description: "承德避暑山庄是清代皇帝夏季避暑和处理政务的场所,是我国现存最大的古代皇家园林,融合了中国南北方园林建筑艺术。"
|
||||
featured: true
|
||||
image: "/images/attractions/chengde-resort.jpg"
|
||||
city: ["承德"]
|
||||
tags: ["皇家园林", "文化遗产", "世界遗产", "清朝建筑", "历史"]
|
||||
pubDate: 2023-06-22
|
||||
---
|
||||
|
||||
# 承德避暑山庄
|
||||
|
||||
承德避暑山庄,位于河北省承德市中心北部,是清代康熙、乾隆皇帝夏季避暑和处理政务的场所,也是中国保存最完整、规模最大的皇家园林之一。它与周围的外八庙一起,被联合国教科文组织列为世界文化遗产。
|
||||
|
||||
## 宏伟规模
|
||||
|
||||
避暑山庄建于1703年(康熙四十二年),历经康熙、雍正、乾隆三朝,耗时89年建成。整个山庄占地面积约564万平方米,是北京颐和园的两倍多。园内建筑与自然景观完美结合,包括宫殿区、湖泊区和山峦区三大部分。
|
||||
|
||||
## 建筑特色
|
||||
|
||||
避暑山庄巧妙地将中国南北方园林风格融为一体,园内有72景,其中最著名的有"热河烟树"、"松塔迎客"、"月色澄莲"等。园中的建筑风格多样,有汉族传统建筑,也有蒙古包、藏式佛塔等少数民族建筑风格,体现了清朝"天下一统"的政治理念。
|
||||
|
||||
## 历史意义
|
||||
|
||||
承德避暑山庄不仅是一处风景优美的皇家园林,更是清朝统治者处理民族事务、接待少数民族首领和外国使节的重要场所。这里见证了清朝与周边民族和国家的友好交往历史,具有重要的历史和政治意义。
|
||||
|
||||
## 参观信息
|
||||
|
||||
- **开放时间**:旺季(4月1日-10月31日)7:30-18:00,淡季(11月1日-次年3月31日)8:00-17:00
|
||||
- **门票**:旺季115元/人,淡季70元/人
|
||||
- **最佳游览季节**:夏秋季节(6月-10月)
|
||||
- **建议游览时间**:1-2天
|
||||
- **交通**:从北京可乘坐高铁或长途汽车到承德,市内有多路公交车可到达景区
|
||||
|
||||
来承德避暑山庄,穿越时空感受清朝皇家园林的壮丽与精美,领略"塞外小北京"的独特魅力。
|
@ -1,64 +0,0 @@
|
||||
---
|
||||
title: 承德避暑山庄
|
||||
description: 中国清代皇家园林,世界文化遗产,占地564万平方米,是世界上最大的皇家园林之一。清朝皇帝夏天在此避暑,处理政务。园内山水相融,景色优美,建筑风格多样。
|
||||
featured: true
|
||||
image: https://picsum.photos/seed/chengde/800/600
|
||||
location: 承德市
|
||||
tags: ['世界文化遗产', '皇家园林', '历史建筑']
|
||||
pubDate: 2023-03-15
|
||||
updatedDate: 2023-12-01
|
||||
---
|
||||
|
||||
# 承德避暑山庄
|
||||
|
||||
## 景点概况
|
||||
|
||||
承德避暑山庄,又名"热河行宫",位于河北省承德市双桥区,是清代皇帝夏天避暑和处理政务的场所,也是中国现存最大的古代帝王宫苑。避暑山庄始建于1703年(清康熙四十二年),历经康熙、雍正、乾隆三朝,耗时89年建成。
|
||||
|
||||
园内建筑面积8.7万平方米,整个山庄依山就势,园林结构严谨,建筑布局灵活,集中国园林艺术之精华,融汉、蒙、满等民族建筑风格于一体。
|
||||
|
||||
## 历史沿革
|
||||
|
||||
避暑山庄创建于1703年,是清代康熙皇帝为避暑与抵御北方少数民族威胁而建。山庄的选址有着重要的战略意义,位于进出关内外的交通要道和游牧民族与农耕地区的交界处。
|
||||
|
||||
康熙年间主要建成了宫殿区、湖区和部分平原区,雍正时期进行了扩建,而在乾隆年间则达到鼎盛,修建了大部分的建筑群和外八庙。
|
||||
|
||||
## 建筑特色
|
||||
|
||||
避暑山庄布局巧妙,融宫殿建筑与自然景观为一体,被划分为宫殿区、湖区、平原区和山区四个部分:
|
||||
|
||||
1. **宫殿区**:位于山庄南部,是皇帝处理政务和日常起居的场所,建筑富丽堂皇。
|
||||
2. **湖区**:位于山庄中部,包括八个大小不一的湖泊,湖中点缀着岛屿和各式亭台楼阁。
|
||||
3. **平原区**:位于湖区以北,模仿内蒙古草原风光,建有蒙古包等。
|
||||
4. **山区**:位于山庄北部,占总面积四分之三,主要是自然风景区,点缀有寺庙和亭台。
|
||||
|
||||
## 文化价值
|
||||
|
||||
避暑山庄不仅是清朝政治中心之一,也是中国古代园林艺术的杰出代表。它体现了"天人合一"的中国传统哲学思想,以及清代统治者"慎终怀远"的政治理念。
|
||||
|
||||
1987年,承德避暑山庄及周围寺庙被联合国教科文组织列入世界文化遗产名录。
|
||||
|
||||
## 著名景点
|
||||
|
||||
避暑山庄内有72景,其中最著名的有:
|
||||
|
||||
- **烟波致爽**:湖区主要景点,可欣赏湖光山色。
|
||||
- **月色江声**:观赏月亮和聆听流水声的最佳地点。
|
||||
- **芳泉映柳**:有泉水环绕的柳树园地。
|
||||
- **松风水月**:可欣赏松树、微风、湖水和月色的胜景。
|
||||
- **四知书屋**:乾隆皇帝读书的地方。
|
||||
|
||||
## 交通指南
|
||||
|
||||
- **地址**:河北省承德市双桥区武烈河北路178号
|
||||
- **公交**:乘坐1路、6路公交车可直达
|
||||
- **自驾**:从北京出发,沿京承高速公路行驶约230公里可达
|
||||
|
||||
## 参观提示
|
||||
|
||||
- 开放时间:8:00-17:30(旺季),8:30-17:00(淡季)
|
||||
- 门票信息:淡季80元,旺季100元(含园内电瓶车)
|
||||
- 建议游览时间:一整天
|
||||
- 最佳游览季节:夏秋季(7-10月)
|
||||
|
||||
来避暑山庄,感受"塞外江南"的独特魅力,领略清朝帝王的皇家气派!
|
@ -0,0 +1,81 @@
|
||||
---
|
||||
title: "定州开元寺 - 北方佛教古刹明珠"
|
||||
description: "定州开元寺始建于唐开元年间,是中国北方著名的佛教古刹,以其壮观的建筑群、珍贵的文物和独特的佛教艺术而闻名。"
|
||||
featured: true
|
||||
image: "/images/attractions/dingzhou-kaiyuan.jpg"
|
||||
city: ["定州"]
|
||||
tags: ["佛教古刹", "历史遗迹", "文化遗产", "唐代建筑", "佛教艺术"]
|
||||
pubDate: 2023-09-18
|
||||
---
|
||||
|
||||
# 定州开元寺
|
||||
|
||||
定州开元寺,位于河北省定州市城南,始建于唐开元二十六年(公元738年),是我国北方地区保存较为完整的唐代佛教建筑群之一。历经唐、五代、宋、金、元、明、清等朝代的修缮扩建,形成了今天规模宏大、气势恢宏的古刹格局。作为国家重点文物保护单位,定州开元寺以其深厚的历史底蕴和丰富的文化遗产,成为河北地区重要的佛教圣地和旅游胜地。
|
||||
|
||||
## 历史沿革
|
||||
|
||||
定州开元寺由唐玄宗下诏修建,最初名为"开元寺",取"开元盛世"之意。五代时期曾毁于战火,后在宋代进行了大规模重建,并更名为"大中祥符寺"。金代又改回"开元寺",元明清三代均有扩建和修缮。
|
||||
|
||||
开元寺在中国佛教史上有着重要地位,历史上曾是北方佛学研究和传播的重要中心,多位高僧大德曾在此讲经说法、传授佛法。
|
||||
|
||||
## 建筑特色
|
||||
|
||||
定州开元寺占地面积约30000平方米,建筑面积约8000平方米,现存主要建筑有山门、天王殿、大雄宝殿、藏经楼、东西配殿等,整体布局严谨,气势恢宏。
|
||||
|
||||
### 山门
|
||||
|
||||
开元寺山门高大壮观,三间两层,上悬"开元古寺"匾额,为清代所建。山门内有钟鼓楼,东为钟楼,西为鼓楼,象征"晨钟暮鼓"的佛教传统。
|
||||
|
||||
### 天王殿
|
||||
|
||||
天王殿为五开间建筑,殿内供奉弥勒佛和四大天王塑像。殿顶为重檐歇山顶,飞檐翘角,气势雄伟。殿内的木雕、石刻、彩绘装饰艺术精湛,体现了唐宋时期的建筑艺术特色。
|
||||
|
||||
### 大雄宝殿
|
||||
|
||||
大雄宝殿是开元寺的主体建筑,宋代重建,明清时期多次修缮。殿内供奉释迦牟尼佛、文殊菩萨和普贤菩萨,俗称"三世佛"。殿顶为重檐歇山顶,殿内有精美的壁画和雕塑,艺术价值极高。
|
||||
|
||||
### 藏经楼
|
||||
|
||||
藏经楼为二层木结构建筑,是存放佛经和佛教文物的场所。楼内珍藏有明清时期的佛教典籍、经卷和艺术品,是研究中国佛教史和艺术史的重要资料。
|
||||
|
||||
## 文物珍藏
|
||||
|
||||
定州开元寺内珍藏有大量珍贵文物,主要包括:
|
||||
|
||||
1. **佛教造像**:寺内保存有唐代至清代的佛教造像数百尊,其中宋金时期的彩塑艺术尤为精湛,造型生动,色彩艳丽。
|
||||
|
||||
2. **石刻艺术**:开元寺石刻艺术丰富多彩,包括石碑、石柱、浮雕等,内容有佛教故事、历史记载和艺术图案,是研究古代石刻艺术的重要资料。
|
||||
|
||||
3. **壁画遗存**:虽经历代战乱,寺内仍保存有部分宋金时期的壁画遗存,题材多为佛教故事和佛陀生平,技法精湛,风格独特。
|
||||
|
||||
4. **佛教典籍**:藏经楼珍藏有明清时期的佛教经卷、版画和手抄本,对研究佛教历史和古代印刷术有重要价值。
|
||||
|
||||
## 文化价值
|
||||
|
||||
定州开元寺不仅是一座古老的佛教寺院,更是中国古代宗教、建筑、艺术和文化的重要载体:
|
||||
|
||||
1. **建筑艺术价值**:开元寺建筑融合了唐宋以来北方佛教建筑的特点,是研究中国古代建筑艺术的重要实例。
|
||||
|
||||
2. **宗教文化价值**:作为北方地区重要的佛教中心,开元寺见证了中国佛教的发展历程,保存了丰富的佛教文化遗产。
|
||||
|
||||
3. **历史研究价值**:寺内的碑刻、壁画和文物为研究唐宋以来的历史、文化、艺术提供了珍贵资料。
|
||||
|
||||
4. **民俗文化价值**:开元寺与当地民俗文化紧密结合,形成了独特的庙会文化和民间信仰习俗。
|
||||
|
||||
## 游览信息
|
||||
|
||||
- **开放时间**:8:00-17:30(全年开放)
|
||||
- **门票**:30元/人
|
||||
- **建议游览时间**:2-3小时
|
||||
- **最佳游览季节**:春秋两季
|
||||
- **特别活动**:农历正月十五和四月初八有庙会活动
|
||||
|
||||
## 交通指南
|
||||
|
||||
- **自驾**:从石家庄出发沿京昆高速到定州出口下,按指示牌前往市区南部即可到达
|
||||
- **公共交通**:
|
||||
- 在石家庄火车站乘坐前往定州的长途汽车,约1小时可到达
|
||||
- 到达定州后可乘坐2路公交车直达开元寺
|
||||
- **高铁**:乘坐高铁至定州东站,出站后乘坐出租车约15分钟可到达
|
||||
|
||||
游览定州开元寺,感受北方佛教古刹的庄严肃穆,品味唐宋以来的建筑艺术精华,聆听古老佛寺的历史回响,领略中华传统文化的博大精深。
|
@ -0,0 +1,59 @@
|
||||
---
|
||||
title: "山海关长城 - 天下第一关"
|
||||
description: "山海关长城是明长城东部起点,素有'天下第一关'之称,是中国长城文化的重要象征,也是秦皇岛最著名的历史文化景观。"
|
||||
featured: true
|
||||
image: "/images/attractions/shanhaiguan.jpg"
|
||||
city: ["秦皇岛"]
|
||||
tags: ["长城", "历史", "文化遗产", "世界遗产", "关隘"]
|
||||
pubDate: 2023-04-20
|
||||
---
|
||||
|
||||
# 山海关长城
|
||||
|
||||
山海关,又称"榆关",位于河北省秦皇岛市东北部,是明长城的东部起点,素有"天下第一关"之称。它北依燕山,南临渤海,扼守华北平原东北咽喉,自古就是兵家必争之地和军事要塞,也是中华文明与塞外文化交流的重要门户。
|
||||
|
||||
## 历史背景
|
||||
|
||||
山海关始建于明洪武年间(1381年),是明长城九镇之一的"榆关"所在地。明朝将领徐达主持修建了关城,后历代均有修缮和加固。明末1644年,山海关守将吴三桂"开关迎清",使清军得以入关,成为中国历史上著名的"山海关之变"。这里见证了中国明清两朝更替的重要历史事件,有着丰富的历史文化内涵。
|
||||
|
||||
## 建筑特色
|
||||
|
||||
山海关城墙全长约4公里,呈矩形,分为关城和附郭城两部分。关城东西长约1公里,南北宽约750米,四角各有一座角楼,四面各有一座城门,分别是:
|
||||
|
||||
- 东门:镇东门,上有"天下第一关"匾额
|
||||
- 西门:迎恩门
|
||||
- 南门:望洋门
|
||||
- 北门:威远门
|
||||
|
||||
城墙高约14米,底宽约7米,顶宽约5米,全部用城砖砌筑而成。整个关城气势雄伟,防御工事严密,是明代军事防御体系的典型代表。
|
||||
|
||||
## 主要景点
|
||||
|
||||
山海关景区包括多处历史文化景点:
|
||||
|
||||
1. **天下第一关楼**: 山海关东门城楼,楼上悬挂着"天下第一关"匾额,为清乾隆所书。登楼可俯瞰关城全貌,远眺碧海青山。
|
||||
|
||||
2. **老龙头**: 又称"入海长城",是明长城唯一入海处,有"万里长城第一台"之称。这里长城如巨龙探入大海,气势磅礴,是中国长城文化的象征之一。
|
||||
|
||||
3. **角山长城**: 山海关长城北部最高处,是观赏长城雄姿的绝佳位置。这里的长城蜿蜒于崇山峻岭之间,体现了长城依山就势的建筑特点。
|
||||
|
||||
4. **关帝庙**: 位于关城内,是供奉关羽的场所,体现了古代军事与宗教文化的结合。
|
||||
|
||||
5. **榆关古镇**: 保存了明清时期的街道布局和建筑风格,游客可以在此体验古时边关小镇的生活氛围。
|
||||
|
||||
## 文化价值
|
||||
|
||||
山海关不仅是重要的军事防御工程,也是中华文化的重要载体。这里流传着众多历史故事和民间传说,如"萧何月下追韩信"、"孟姜女哭长城"等。同时,山海关也是中国古代文人墨客寄托情怀的地方,留下了大量诗词歌赋,如"山似海湾痴老树,城如船舶驻沧浪"等名句,丰富了中国的文学艺术宝库。
|
||||
|
||||
## 旅游建议
|
||||
|
||||
- **最佳游览时间**: 春季(4-5月)和秋季(9-10月)气候宜人,是观光的最佳季节
|
||||
- **建议游览时间**: 1-2天
|
||||
- **开放时间**: 夏季7:30-18:30,冬季8:00-17:30
|
||||
- **门票**: 山海关古城区120元/人(旺季),老龙头50元/人
|
||||
- **交通**:
|
||||
- 从秦皇岛市区乘坐25路公交车可直达山海关
|
||||
- 北京、天津等地有直达山海关的火车
|
||||
- 自驾游可沿京哈高速公路前往
|
||||
|
||||
游览山海关长城,感受"天下第一关"的雄伟壮观,领略中华民族悠久历史与灿烂文化的同时,也能欣赏到独特的海河交融的自然风光。
|
30
web/graduation/src/content/attractions/zhaozhou-bridge.md
Normal file
30
web/graduation/src/content/attractions/zhaozhou-bridge.md
Normal file
@ -0,0 +1,30 @@
|
||||
---
|
||||
title: "赵州桥 - 世界最古老的石拱桥"
|
||||
description: "赵州桥是世界上现存最古老、最长的单孔石拱桥,始建于隋朝,是中国古代桥梁建筑的瑰宝和杰出代表。"
|
||||
featured: true
|
||||
image: "/images/attractions/zhaozhou-bridge.jpg"
|
||||
city: ["石家庄"]
|
||||
tags: ["历史", "建筑", "文化遗产", "世界遗产", "石拱桥"]
|
||||
pubDate: 2023-05-15
|
||||
---
|
||||
|
||||
# 赵州桥
|
||||
|
||||
赵州桥,又称安济桥,位于河北省石家庄市赵县城南2.5公里处的洨河上。作为世界上现存最古老、跨度最大的单孔敞肩石拱桥,它于隋代大业年间(公元605年-618年)由著名匠师李春设计建造。
|
||||
|
||||
## 建筑特色
|
||||
|
||||
赵州桥全长50.82米,宽9.6米,跨度37.37米,桥面两侧设石栏板42块。桥拱呈圆弧形,共由28个巨大的石块精确砌筑而成。其最特别之处在于采用了开肩拱的独特结构,桥墩两肩各有两个辅助小孔,不仅减轻了桥身重量,还有助于泄洪,这一设计理念至今仍被现代桥梁建筑所应用。
|
||||
|
||||
## 历史意义
|
||||
|
||||
作为世界文化遗产,赵州桥历经1400多年风雨沧桑,见证了中国古代多个朝代更迭,至今仍保持通车功能。它不仅是中国古代桥梁建筑艺术的杰出代表,更是人类工程史上的伟大奇迹,充分展示了中国古代工匠的智慧和技艺。
|
||||
|
||||
## 参观信息
|
||||
|
||||
- **开放时间**:8:00-18:00(全年开放)
|
||||
- **门票**:40元/人(学生半价)
|
||||
- **最佳游览季节**:春秋两季
|
||||
- **交通**:从石家庄市区可乘坐前往赵县的长途汽车,到达后转乘当地公交或出租车前往景区
|
||||
|
||||
来赵州桥,感受中国古代桥梁建筑的宏伟与精巧,领略千年工艺的卓越成就。
|
@ -8,7 +8,7 @@ const attractionsCollection = defineCollection({
|
||||
description: z.string(),
|
||||
featured: z.boolean().default(false),
|
||||
image: z.string().optional(),
|
||||
city: z.string().optional(),
|
||||
city: z.array(z.string()).default([]),
|
||||
tags: z.array(z.string()).default([]),
|
||||
pubDate: z.date().optional(),
|
||||
}),
|
||||
@ -23,7 +23,7 @@ const cultureCollection = defineCollection({
|
||||
category: z.string(),
|
||||
featured: z.boolean().default(false),
|
||||
image: z.string().optional(),
|
||||
city: z.string().optional(),
|
||||
city: z.array(z.string()).default([]),
|
||||
tags: z.array(z.string()).default([]),
|
||||
pubDate: z.date().optional(),
|
||||
}),
|
||||
@ -38,7 +38,7 @@ const cuisineCollection = defineCollection({
|
||||
category: z.string(),
|
||||
featured: z.boolean().default(false),
|
||||
image: z.string().optional(),
|
||||
city: z.string().optional(),
|
||||
city: z.array(z.string()).default([]),
|
||||
ingredients: z.array(z.string()).default([]),
|
||||
taste: z.string().optional(),
|
||||
cookTime: z.string().optional(),
|
||||
@ -58,7 +58,7 @@ const travelCollection = defineCollection({
|
||||
type: z.string(),
|
||||
featured: z.boolean().default(false),
|
||||
image: z.string().optional(),
|
||||
city: z.string().optional(),
|
||||
city: z.array(z.string()).default([]),
|
||||
days: z.number().optional(),
|
||||
difficulty: z.enum(['简单', '中等', '困难']).optional(),
|
||||
tags: z.array(z.string()).default([]),
|
||||
|
47
web/graduation/src/content/cuisine/donkey-burger.md
Normal file
47
web/graduation/src/content/cuisine/donkey-burger.md
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
title: "驴肉火烧 - 河北特色传统美食"
|
||||
description: "驴肉火烧是河北保定地区传统名吃,以酥脆的火烧饼和香嫩的驴肉为主料,具有肉烂味香、肥而不腻的特点。"
|
||||
category: "特色小吃"
|
||||
featured: true
|
||||
image: "/images/cuisine/donkey-burger.jpg"
|
||||
city: ["保定"]
|
||||
ingredients: ["面粉", "驴肉", "花椒", "八角", "桂皮", "酱油", "盐", "葱", "姜", "蒜"]
|
||||
taste: "咸鲜香酥"
|
||||
cookTime: "3小时"
|
||||
difficulty: "中等"
|
||||
tags: ["驴肉", "火烧", "传统美食", "保定特色", "河北小吃"]
|
||||
pubDate: 2023-08-05
|
||||
---
|
||||
|
||||
# 驴肉火烧
|
||||
|
||||
驴肉火烧,又称"驴火",是河北保定地区的传统名吃,已有上百年的历史。它由两片酥脆的火烧夹入煮得酥烂的驴肉而成,咬一口,外酥里嫩,肉香四溢,是无数食客心中的美味记忆。
|
||||
|
||||
## 历史渊源
|
||||
|
||||
驴肉火烧起源于清朝,最初是保定地区民间的家常美食。据传,清代乾隆皇帝微服私访时曾品尝过驴肉火烧,大为赞赏,从此声名远播。如今,它已成为河北美食文化的重要代表,在全国各地都有其爱好者。
|
||||
|
||||
## 制作特点
|
||||
|
||||
驴肉火烧的制作分为两部分:火烧饼和驴肉的制作。
|
||||
|
||||
**火烧饼**:以优质面粉为主料,通过揉面、发酵、烙烤等工序制作而成。成品火烧外焦里嫩,酥脆可口,是驴肉火烧的关键载体。
|
||||
|
||||
**驴肉**:选用新鲜的驴肉,加入花椒、八角、桂皮等几十种调料,通过文火慢炖3-4小时,使肉质酥烂,入味而不柴,肥而不腻。成品驴肉色泽红褐,香气四溢。
|
||||
|
||||
## 品尝方法
|
||||
|
||||
最传统的享用方式是将火烧掰开,夹入适量的驴肉片,再加入少许蒜泥、香菜末或辣椒油提味。入口时先感觉到火烧的酥脆,继而是驴肉的鲜香,最后是各种调料的层次感,风味独特。
|
||||
|
||||
## 营养价值
|
||||
|
||||
驴肉被誉为"黑色食品",具有较高的营养价值。它富含蛋白质,脂肪含量低,且含有多种维生素和矿物质。在中医理论中,驴肉性平温,有补气养血、滋补强身的功效,尤其适合体虚贫血者食用。
|
||||
|
||||
## 品尝地点
|
||||
|
||||
- **老字号**:保定市老城区的"马家驴肉火烧"、"满江红驴肉火烧"
|
||||
- **价格范围**:10-25元/份
|
||||
- **最佳品尝季节**:秋冬季节
|
||||
- **推荐搭配**:小米粥、豆汁或当地特色杂粮粥
|
||||
|
||||
品尝驴肉火烧,体验河北传统美食的独特魅力,感受历史悠久的保定饮食文化。
|
@ -1,93 +0,0 @@
|
||||
---
|
||||
title: 保定驴肉火烧
|
||||
description: 河北保定的传统小吃,以烤制的火烧饼夹入精选的驴肉,肉质鲜美,饼酥脆可口,香气四溢,是保定最具代表性的地方风味美食。
|
||||
category: 传统小吃
|
||||
featured: true
|
||||
image: https://picsum.photos/seed/donkey-burger/800/600
|
||||
origin: 保定市
|
||||
ingredients: ['驴肉', '火烧饼', '青椒', '香菜', '五香粉', '酱汁']
|
||||
taste: 鲜香酥脆
|
||||
tags: ['河北名吃', '传统美食', '地方特色']
|
||||
pubDate: 2023-04-05
|
||||
updatedDate: 2023-10-20
|
||||
---
|
||||
|
||||
# 保定驴肉火烧
|
||||
|
||||
## 美食简介
|
||||
|
||||
保定驴肉火烧是河北保定地区的传统名吃,距今已有上百年的历史。它由两块圆形的酥脆火烧饼夹着精细切片的卤驴肉制成,佐以青椒、香菜等配料,香气四溢,口感丰富,是河北最具代表性的地方风味小吃之一。
|
||||
|
||||
驴肉火烧之所以能够成为保定的招牌美食,在于其选料严格、工艺精湛、味道独特。驴肉肉质细嫩且低脂肪、高蛋白,火烧饼则酥脆可口,两者搭配堪称绝配。
|
||||
|
||||
## 历史渊源
|
||||
|
||||
关于保定驴肉火烧的起源,有多种说法。最具代表性的说法认为,它始于清朝末年的保定城内。当时的保定是京畿重地,商业繁荣,小吃文化发达。一家姓茹的老字号饭馆为了充分利用食材,将卤制的驴肉切片夹在当地特色的火烧饼中售卖,没想到大受欢迎,逐渐成为保定的特色美食。
|
||||
|
||||
另一种说法将其起源追溯到更早的明代,传说明朝大将徐达攻打保定时,因军粮不足,士兵只能以驴肉夹饼充饥,没想到这种简单的吃法味道鲜美,战后流传开来。
|
||||
|
||||
## 制作工艺
|
||||
|
||||
保定驴肉火烧的制作分为两大部分:火烧饼的制作和驴肉的卤制。
|
||||
|
||||
### 火烧饼制作
|
||||
1. **和面**:选用优质面粉,加入适量清水、食用碱和盐,揉至光滑。
|
||||
2. **发酵**:将和好的面团放置发酵至体积增大约一倍。
|
||||
3. **整形**:将面团分割成小剂子,压扁成圆饼状。
|
||||
4. **烤制**:传统方法是在炉壁上烤制,使饼两面呈金黄色,外酥里嫩。
|
||||
|
||||
### 驴肉卤制
|
||||
1. **选料**:选用新鲜的驴肉,以后腿肉为佳。
|
||||
2. **清洗**:将驴肉彻底清洗,去除血水。
|
||||
3. **卤制**:将肉放入配有十余种香料的卤水中,小火慢炖3-4小时。
|
||||
4. **冷却**:卤好后取出,自然冷却。
|
||||
5. **切片**:将卤好的驴肉切成薄片,约2-3毫米厚。
|
||||
|
||||
### 组合制作
|
||||
1. 将火烧饼从中间切开,不要切断。
|
||||
2. 在切开的饼内放入适量切好的驴肉片。
|
||||
3. 加入青椒丝、香菜等配料。
|
||||
4. 可根据个人口味加入特制的酱料。
|
||||
|
||||
## 营养价值
|
||||
|
||||
驴肉被称为"黑色的肉中之王",具有极高的营养价值:
|
||||
- 高蛋白低脂肪:蛋白质含量高达20%以上,脂肪含量仅为2%左右。
|
||||
- 富含微量元素:含有丰富的铁、锌、硒等微量元素。
|
||||
- 氨基酸丰富:含有人体所需的多种必需氨基酸。
|
||||
- 药用价值:中医认为驴肉性平味甘,具有补血益气、滋阴养胃的功效。
|
||||
|
||||
火烧饼则提供了充足的碳水化合物,两者搭配营养均衡,既美味又健康。
|
||||
|
||||
## 品尝之道
|
||||
|
||||
品尝保定驴肉火烧有几个关键要点:
|
||||
1. **趁热吃**:火烧刚出炉时最为酥脆,驴肉热时肉汁丰富。
|
||||
2. **细嚼慢咽**:充分品味火烧的酥香和驴肉的鲜美。
|
||||
3. **配料搭配**:可根据个人口味添加青椒、香菜、蒜泥等。
|
||||
4. **饮品搭配**:传统上配以豆汁或小米粥,现代也可配清茶或啤酒。
|
||||
|
||||
## 保定名店
|
||||
|
||||
保定有多家历史悠久的驴肉火烧老字号,其中最具代表性的有:
|
||||
|
||||
1. **茹记驴肉火烧**:创建于清末,被誉为驴肉火烧的鼻祖,多代传承的秘制配方。
|
||||
- 地址:保定市莲池区裕华西路
|
||||
|
||||
2. **万顺斋驴肉火烧**:百年老店,以肉质鲜嫩、火烧酥脆著称。
|
||||
- 地址:保定市新市区东风路
|
||||
|
||||
3. **德馨斋驴肉火烧**:创建于1936年,特点是驴肉卤制时间长,味道更浓郁。
|
||||
- 地址:保定市莲池区东三省胡同
|
||||
|
||||
## 现代传承
|
||||
|
||||
随着时代的发展,保定驴肉火烧已走出河北,在全国范围内获得了广泛认可。许多保定人将驴肉火烧的制作技艺带到全国各地,开设专门店铺。同时,现代工艺也在不断改进传统制作方法,如采用真空包装技术延长驴肉保鲜期,研发速冻火烧等,使这一传统美食更加方便快捷。
|
||||
|
||||
保定市政府也高度重视这一文化遗产的保护和传承,定期举办驴肉火烧文化节,评选"驴肉火烧名店",并支持相关研究和创新,确保这一传统美食在现代社会继续发扬光大。
|
||||
|
||||
## 旅游提示
|
||||
|
||||
来保定旅游的游客可以将品尝正宗的驴肉火烧作为必不可少的行程之一。最好选择当地知名的老字号店铺,体验最地道的口味。很多游客也会购买真空包装的驴肉带回家与亲友分享,成为保定特色伴手礼。
|
||||
|
||||
品尝驴肉火烧时,可以搭配游览保定的古莲花池、直隶总督署等历史景点,体验完整的保定文化之旅。
|
76
web/graduation/src/content/cuisine/tangshan-doufu.md
Normal file
76
web/graduation/src/content/cuisine/tangshan-doufu.md
Normal file
@ -0,0 +1,76 @@
|
||||
---
|
||||
title: "唐山豆腐宴 - 中国北方豆香美食文化"
|
||||
description: "唐山豆腐宴是河北唐山地区的传统特色美食,以豆腐为主料,制作工艺精细,变化多样,口味丰富,被誉为'豆腐的盛宴'。"
|
||||
category: "地方特色"
|
||||
featured: true
|
||||
image: "/images/cuisine/tangshan-doufu.jpg"
|
||||
city: ["唐山"]
|
||||
ingredients: ["豆腐", "黄豆", "调味料", "素菜", "肉类"]
|
||||
taste: "鲜香清淡"
|
||||
cookTime: "因菜而异"
|
||||
difficulty: "中等"
|
||||
tags: ["豆腐宴", "传统美食", "健康饮食", "宫廷菜", "河北特色"]
|
||||
pubDate: 2023-05-18
|
||||
---
|
||||
|
||||
# 唐山豆腐宴
|
||||
|
||||
唐山豆腐宴,是河北省唐山市的传统特色美食,以豆腐为主要食材,融合了北方烹饪技艺和当地饮食特色,创造出数十种豆腐菜肴,被誉为"中国豆腐美食的集大成者"。这种独特的宴席文化不仅展现了豆腐的多样性和可塑性,也体现了唐山人民朴实、创新的饮食智慧。
|
||||
|
||||
## 历史渊源
|
||||
|
||||
唐山豆腐宴源起于明清时期,相传与清代宫廷御膳有一定渊源。据史料记载,乾隆皇帝下江南时曾品尝并赞赏唐山豆腐,甚至将其引入宫廷御膳。随着时间的推移,唐山豆腐宴逐渐在民间流传开来,并不断发展创新,形成了今天丰富多彩的菜系。
|
||||
|
||||
唐山大地肥沃,盛产优质黄豆,加上唐山地处渤海湾,水质优良,为制作上乘豆腐提供了得天独厚的条件。当地人用心研究豆腐制作技艺,并开发出多种烹饪方法,使豆腐宴成为当地独特的饮食文化符号。
|
||||
|
||||
## 特色工艺
|
||||
|
||||
唐山豆腐制作工艺精细,讲究选料、浸泡、磨浆、点卤等多道工序,每一步都影响着豆腐的品质。当地豆腐主要分为以下几类:
|
||||
|
||||
- **老豆腐**:质地坚实,口感细腻,是制作红烧、炖、炒等菜肴的基础。
|
||||
- **嫩豆腐**:水分多,质地柔软,适合做汤羹、蒸菜等。
|
||||
- **豆腐脑**:最为细嫩,多作早餐或甜品。
|
||||
- **豆腐干**:经过压制去水,有咸、五香等多种口味,可直接食用或做菜。
|
||||
- **豆腐皮**:富含蛋白质,可制作多种素菜或肉菜的包裹材料。
|
||||
|
||||
## 代表菜品
|
||||
|
||||
唐山豆腐宴通常包含20-30道菜品,每道菜都有精心的制作工艺和独特的口味,主要代表菜品有:
|
||||
|
||||
### 镇宴三绝
|
||||
|
||||
- **八仙过海**:选用上等嫩豆腐,雕刻成八个仙人形象,放入高汤中,配以海鲜,象征八仙过海的传说。
|
||||
- **百花豆腐**:将嫩豆腐切成薄片,上面点缀各色蔬菜,形如百花盛开,蒸制而成,清香鲜美。
|
||||
- **玉龙戏珠**:用豆腐皮包裹馅料,捏制成龙形,配以红色"珍珠"点缀,造型生动,口感丰富。
|
||||
|
||||
### 传统名菜
|
||||
|
||||
- **麻婆豆腐**:唐山版麻婆豆腐油而不腻,麻而不辣,保持了豆腐的本味。
|
||||
- **豆腐包子**:用豆腐替代面粉做皮,包入鲜美馅料,蒸熟后外软内香。
|
||||
- **豆腐烧茄子**:将豆腐与茄子一同炖煮,吸收酱汁,味道醇厚。
|
||||
- **豆腐丸子汤**:将豆腐捣碎加入配料制成丸子,放入鲜汤中煮制,鲜美可口。
|
||||
- **罐儿豆腐**:将豆腐切块,与肉末、香菇等一同放入小罐中蒸制,风味独特。
|
||||
|
||||
### 创新菜式
|
||||
|
||||
- **豆腐冰淇淋**:将豆腐制成甜品,滑嫩爽口,营养健康。
|
||||
- **彩色豆腐拼盘**:用天然食材为豆腐着色,制成多彩拼盘,美观诱人。
|
||||
- **豆腐西施酒**:用豆腐发酵而成的特色酒,低度微甜,别具一格。
|
||||
|
||||
## 文化价值
|
||||
|
||||
唐山豆腐宴不仅是一种美食,更是一种文化象征。它体现了以下价值:
|
||||
|
||||
1. **健康饮食**:豆腐富含植物蛋白,低脂肪,符合现代健康饮食理念。
|
||||
2. **勤俭美德**:利用简单食材创造丰富美食,展现了中华民族的勤俭智慧。
|
||||
3. **文化创新**:在传统基础上不断创新,使古老食材焕发新生。
|
||||
4. **地域特色**:成为唐山地区重要的文化名片和旅游资源。
|
||||
|
||||
## 品尝建议
|
||||
|
||||
- **最佳食用季节**:四季皆宜,夏季尤佳
|
||||
- **推荐餐厅**:唐山饭店、丰润豆腐宴、唐山老字号豆香村
|
||||
- **价格范围**:套餐价格200-800元/桌不等,依菜品数量和档次而定
|
||||
- **饮食礼仪**:先品尝原味豆腐,再享用其他菜品,以领略豆腐的本真风味
|
||||
|
||||
来唐山,品味一席豆腐盛宴,感受中国北方饮食文化的精致与智慧,体验豆香四溢的美食之旅。
|
56
web/graduation/src/content/cuisine/zhajiang-noodles.md
Normal file
56
web/graduation/src/content/cuisine/zhajiang-noodles.md
Normal file
@ -0,0 +1,56 @@
|
||||
---
|
||||
title: "正宗老北京炸酱面 - 河北传统面食经典"
|
||||
description: "炸酱面是北京及河北地区传统名吃,以面条配以特制炸酱为特色,咸香可口、风味独特,是一道家喻户晓的经典面食。"
|
||||
category: "传统面食"
|
||||
featured: true
|
||||
image: "/images/cuisine/zhajiang-noodles.jpg"
|
||||
city: ["保定","石家庄","唐山"]
|
||||
ingredients: ["面粉", "猪肉", "黄酱", "甜面酱", "黄豆酱", "葱", "黄瓜", "豆芽", "萝卜"]
|
||||
taste: "咸鲜微甜"
|
||||
cookTime: "40分钟"
|
||||
difficulty: "简单"
|
||||
tags: ["面食", "家常菜", "传统美食", "北方特色", "经典名吃"]
|
||||
pubDate: 2023-08-25
|
||||
---
|
||||
|
||||
# 正宗老北京炸酱面
|
||||
|
||||
炸酱面,是北京及河北地区历史悠久的传统名吃,也是华北地区最具代表性的面食之一。这道菜以新鲜的手擀面条配以特制的肉丁炸酱为主要特色,佐以各种新鲜蔬菜,风味独特,色香味俱全,深受各地食客喜爱。
|
||||
|
||||
## 历史渊源
|
||||
|
||||
炸酱面起源于清末民初的北京,是由满族传统饮食演变而来。最初在北京宫廷和富贵人家餐桌上出现,后来逐渐流传到民间,成为老百姓日常生活中的美食。在河北的许多城市,尤其是与北京接壤的地区,炸酱面也有着广泛的影响,形成了独具特色的地方风味。
|
||||
|
||||
## 制作特点
|
||||
|
||||
正宗的炸酱面制作主要分为两部分:面条的制作和炸酱的熬制。
|
||||
|
||||
**面条**:选用优质面粉和清水,经过和面、揉面、压面、切条等工序,制作出筋道有嚼劲的手擀面。河北地区的面条通常会比北京的稍粗一些,更有嚼劲。
|
||||
|
||||
**炸酱**:传统炸酱的制作非常讲究,主要原料包括肥瘦猪肉丁、黄酱、甜面酱、黄豆酱等。将肉丁用油炒香后加入各种酱料慢炖,直至香气四溢,酱色红亮,肉质酥烂。河北地区的炸酱常会加入更多的豆瓜酱,使味道更加浓郁。
|
||||
|
||||
## 品尝方法
|
||||
|
||||
传统的炸酱面配菜丰富,通常包括黄瓜丝、萝卜丝、豆芽、青豆、香菜等,这些配菜在河北被称为"码子"。食用时,先将各种生蔬菜码放在煮好的面条上,最后浇上热腾腾的炸酱,然后用筷子将面条和炸酱均匀拌匀后食用,这样每一口都能尝到酱香和蔬菜的清爽。
|
||||
|
||||
## 地方特色
|
||||
|
||||
虽然炸酱面源于北京,但在河北各地也发展出了自己的特色:
|
||||
|
||||
- **保定炸酱面**:酱料中加入了更多的甜面酱,口味偏甜咸,配菜注重脆爽口感。
|
||||
- **石家庄炸酱面**:酱料浓郁,用料稍重,偏向大众口味。
|
||||
- **唐山炸酱面**:酱料中常加入海鲜,增添了独特的鲜味。
|
||||
|
||||
## 营养价值
|
||||
|
||||
炸酱面营养全面,面食提供碳水化合物,炸酱中的肉丁提供蛋白质和脂肪,各种新鲜蔬菜则提供丰富的维生素和膳食纤维。它是一道营养均衡的完整餐食。
|
||||
|
||||
## 品尝地点
|
||||
|
||||
- **石家庄**:老胜芳炸酱面、马记炸酱面
|
||||
- **保定**:老西关炸酱面、王家炸酱面
|
||||
- **唐山**:老唐山炸酱面馆
|
||||
- **价格范围**:12-25元/碗
|
||||
- **最佳品尝季节**:四季皆宜,夏季尤为清爽可口
|
||||
|
||||
品尝一碗正宗的炸酱面,体验中国北方传统面食文化的精髓,感受简单食材中蕴含的深厚历史与丰富风味。
|
77
web/graduation/src/content/culture/cangzhou-wushu.md
Normal file
77
web/graduation/src/content/culture/cangzhou-wushu.md
Normal file
@ -0,0 +1,77 @@
|
||||
---
|
||||
title: "沧州武术 - 中国北方武术文化的重要流派"
|
||||
description: "沧州武术以其刚猛有力、实战性强而闻名,是中国北方武术的重要流派,有'天下武术出河北,河北武术看沧州'的美誉。"
|
||||
category: "武术文化"
|
||||
featured: true
|
||||
image: "/images/culture/cangzhou-wushu.jpg"
|
||||
city: ["沧州"]
|
||||
tags: ["非物质文化遗产", "武术", "传统文化", "民间体育", "功夫"]
|
||||
pubDate: 2023-06-15
|
||||
---
|
||||
|
||||
# 沧州武术
|
||||
|
||||
沧州武术,源于河北省沧州地区,是中国北方武术文化的重要组成部分,以其刚猛有力、实战性强、技法丰富而闻名于世。沧州素有"武术之乡"、"杂技之乡"的美誉,有"天下武术出河北,河北武术看沧州"的说法,形成了独具特色的武术文化体系。
|
||||
|
||||
## 历史渊源
|
||||
|
||||
沧州武术源远流长,至少可以追溯到明清时期。明代沧州籍武术家张松溪编著的《拳经》是中国最早的武术理论著作之一。清代沧州武术得到了进一步发展,形成了诸多流派。近代以来,沧州武术走向全国,甚至走向世界,为中华武术的传播与发展做出了重要贡献。
|
||||
|
||||
## 流派特色
|
||||
|
||||
沧州武术主要包括以下几大流派:
|
||||
|
||||
### 八极拳
|
||||
|
||||
八极拳是沧州最具代表性的拳种之一,创始于明代,由武术家吴钟传承发展。八极拳以"近打"著称,讲究"寸劲"、"寸拳",强调"三节合一",即肩、肘、腕三个关节同时发力。其特点是刚猛有力、严谨凶狠、实战性强,有"拳打北京城,脚踢沈家楼"的说法。
|
||||
|
||||
### 形意拳
|
||||
|
||||
沧州形意拳由戴龙邦、李洛能等大师发扬光大。它融合了中国传统"五行"哲学思想,以五行拳为基础,讲究"三体式"、"五行拳"、"十二形"等内容。其特点是动作简练、步法稳健、内外兼修、刚柔并济。
|
||||
|
||||
### 太极拳
|
||||
|
||||
沧州太极拳以杨氏太极为主,同时也有陈氏、武氏等流派。沧州太极拳保持了传统太极拳柔和、流畅的特点,同时也融入了北方武术的刚猛特性,形成了独特的风格。
|
||||
|
||||
### 通臂拳
|
||||
|
||||
通臂拳是沧州地区的特色拳种,讲究连绵不断、快速发力。其特点是以腰为轴,以肩为枢,强调"三节合一",发力沉稳而迅猛。
|
||||
|
||||
## 武术名家
|
||||
|
||||
沧州武术历史上涌现出许多杰出的武术家:
|
||||
|
||||
- **李书文**:八极拳名家,人称"神拳李书文",精通八极拳和劈挂拳,是近代八极拳的集大成者。
|
||||
- **郭云深**:形意拳大师,为形意拳的传播与发展做出了重要贡献。
|
||||
- **王西安**:当代沧州武术代表人物,对推广沧州武术贡献巨大。
|
||||
- **刘云樵**:八极拳、形意拳名家,被称为"北方武术大师"。
|
||||
|
||||
## 文化传承
|
||||
|
||||
沧州武术不仅是一种体育活动,更是一种文化传承,具有深厚的文化底蕴:
|
||||
|
||||
1. **武德文化**:沧州武术强调"习武先习德",注重武德修养,讲究"礼义廉耻"、"忠义仁勇"。
|
||||
|
||||
2. **教学体系**:沧州武术有完整的教学体系,从基本功到拳法套路,从单人练习到对打实战,层次分明,循序渐进。
|
||||
|
||||
3. **武术表演**:沧州武术与杂技、戏曲等艺术形式相结合,发展出了独特的武术表演艺术,如沧州武术杂技。
|
||||
|
||||
4. **医武结合**:沧州武术与中医理论相结合,形成了独特的武术养生体系,包括气功、推拿、点穴等技术。
|
||||
|
||||
## 当代发展
|
||||
|
||||
近年来,沧州市大力推动武术文化的保护与传承:
|
||||
|
||||
- 成立了沧州武术研究院,系统整理和研究沧州武术文化。
|
||||
- 举办"沧州武术节"等大型活动,扩大沧州武术的影响力。
|
||||
- 开展武术进校园活动,培养年轻一代对传统武术的兴趣。
|
||||
- 建立武术博物馆和武术文化园,展示沧州武术的历史与成就。
|
||||
|
||||
## 体验沧州武术
|
||||
|
||||
- **参观地点**:沧州武术博物馆、沧州铁狮子武术文化园
|
||||
- **学习机会**:沧州各武术馆、沧州武术学校提供短期和长期培训
|
||||
- **观赏表演**:沧州大剧院定期举行武术杂技表演
|
||||
- **武术节**:每年农历九月举办沧州武术文化节
|
||||
|
||||
来沧州,感受中国北方武术的刚猛与力量,领略武术文化的博大精深,体验中华传统文化的魅力与智慧。
|
39
web/graduation/src/content/culture/hebei-bangzi.md
Normal file
39
web/graduation/src/content/culture/hebei-bangzi.md
Normal file
@ -0,0 +1,39 @@
|
||||
---
|
||||
title: "河北梆子 - 北方传统戏曲艺术瑰宝"
|
||||
description: "河北梆子是中国北方著名的地方戏曲剧种,发源于河北,以其高亢嘹亮的唱腔、生动活泼的表演风格闻名于世。"
|
||||
category: "戏曲艺术"
|
||||
featured: true
|
||||
image: "/images/culture/hebei-bangzi.jpg"
|
||||
city: ["石家庄"]
|
||||
tags: ["非物质文化遗产", "戏曲", "传统艺术", "民俗文化", "表演艺术"]
|
||||
pubDate: 2023-07-10
|
||||
---
|
||||
|
||||
# 河北梆子
|
||||
|
||||
河北梆子,又称"河北京梆子",是中国北方著名的传统戏曲剧种,主要流行于河北省及其周边地区。它与京剧、评剧、晋剧并称为中国北方四大戏曲剧种,因其打击乐器以梆子为主而得名,2006年被列入第一批国家级非物质文化遗产名录。
|
||||
|
||||
## 历史渊源
|
||||
|
||||
河北梆子形成于清代中叶(约18世纪中期),由山西梆子传入河北后融合当地民间音乐发展而成。经过200多年的发展,河北梆子形成了自己独特的艺术风格,并对京剧的形成和发展产生了重要影响。
|
||||
|
||||
## 艺术特色
|
||||
|
||||
河北梆子以其高亢嘹亮的唱腔、洪亮的嗓音、生动活泼的表演风格而著称。其主要音乐伴奏乐器有板胡、京胡、月琴等弦乐,以及梆子、堂鼓等打击乐器。表演上强调"四功五法"(唱、念、做、打及眼、手、身、步、法),注重舞台形体动作的夸张与美感。
|
||||
|
||||
## 经典剧目
|
||||
|
||||
河北梆子的经典剧目丰富多彩,如《窦娥冤》、《三娘教子》、《杨家将》、《秦香莲》、《贩马记》等,这些剧目表现了各个时代的历史故事和人物命运,蕴含着深刻的社会意义和道德教化。
|
||||
|
||||
## 当代发展
|
||||
|
||||
随着社会的变迁,河北梆子也在不断创新和发展。近年来,通过编排新剧目、培养新人才、创新表演形式等方式,河北梆子正努力适应现代观众的审美需求,同时保持其独特的艺术魅力和文化价值。许多剧团定期在河北各城市巡回演出,让这一传统艺术形式继续焕发生机。
|
||||
|
||||
## 观看体验
|
||||
|
||||
- **演出场所**:石家庄河北梆子剧院、保定河北梆子剧院等
|
||||
- **演出时间**:常规演出一般在周末晚间,重要节假日会有特别场次
|
||||
- **票价范围**:30-200元不等,视演出规模和座位区域而定
|
||||
- **最佳体验季节**:全年均可,春节期间有特别演出
|
||||
|
||||
体验河北梆子,感受中国北方传统戏曲的独特魅力,聆听历史与文化的动人故事。
|
@ -1,86 +0,0 @@
|
||||
---
|
||||
title: 京剧
|
||||
description: 中国国粹,河北是京剧重要的发源地之一。京剧融合了多种地方戏曲艺术,包括河北梆子等,形成了独特的艺术风格。以生、旦、净、丑四种角色为主,通过唱念做打展现戏剧内容。
|
||||
category: 戏曲艺术
|
||||
featured: true
|
||||
image: https://picsum.photos/seed/jingju/800/600
|
||||
area: 河北全省
|
||||
tags: ['非物质文化遗产', '传统戏曲', '国粹']
|
||||
pubDate: 2023-02-10
|
||||
updatedDate: 2023-11-15
|
||||
---
|
||||
|
||||
# 京剧
|
||||
|
||||
## 艺术概况
|
||||
|
||||
京剧,被誉为中国国粹,是中国最具代表性的传统戏曲艺术形式之一。它形成于19世纪中叶的北京,但河北作为其重要的发源地之一,对京剧的形成和发展有着不可忽视的贡献。京剧通过唱念做打四种基本功,结合音乐、舞蹈、文学、武术等多种艺术形式,以程式化的表演形式展现丰富多彩的历史故事和人物形象。
|
||||
|
||||
## 历史渊源
|
||||
|
||||
京剧的形成可以追溯到清朝乾隆五十五年(1790年),当时以徽班为首的安徽戏曲团体进入北京,与来自湖北的汉调艺人以及当地的昆曲、高腔等艺术形式相互融合,逐渐形成了具有独特风格的京剧。
|
||||
|
||||
在这一过程中,源自河北的"河北梆子"对京剧的音乐、唱腔和表演风格都产生了重要影响。河北梆子作为京剧"四大声腔"之一,以其高亢激昂的唱腔特点,为京剧增添了独特的艺术魅力。
|
||||
|
||||
## 艺术特色
|
||||
|
||||
京剧的主要艺术特色包括:
|
||||
|
||||
1. **角色行当**:分为生(男性角色)、旦(女性角色)、净(性格豪放的男性角色,脸谱化妆)、丑(滑稽角色)四大类,每类又有细分。
|
||||
|
||||
2. **表演程式**:以"唱、念、做、打"为基本功,其中:
|
||||
- 唱:以二黄和西皮两大声腔为主
|
||||
- 念:包括韵白和京白两种念白方式
|
||||
- 做:程式化的动作和身段
|
||||
- 打:武打动作和技巧
|
||||
|
||||
3. **脸谱艺术**:通过不同的颜色和图案表现角色的性格特点,如红色代表忠义,黑色代表刚正不阿,蓝色代表勇猛等。
|
||||
|
||||
4. **音乐伴奏**:以弦乐和打击乐为主,包括京胡、月琴、三弦、笛子、唢呐等乐器。
|
||||
|
||||
## 河北京剧
|
||||
|
||||
河北京剧具有鲜明的地方特色,既保留了京剧的基本程式,又融入了河北地方戏曲的特点。河北京剧演员讲究字正腔圆,唱腔铿锵有力,表演朴实生动,深受当地观众喜爱。
|
||||
|
||||
河北京剧的代表剧目包括《四郎探母》、《铡美案》、《赵氏孤儿》等,这些剧目通过悲壮、激昂的表演风格,展示了英雄人物的气概和民族精神。
|
||||
|
||||
## 代表剧目
|
||||
|
||||
京剧的经典剧目数以千计,其中最具代表性的包括:
|
||||
|
||||
- **《霸王别姬》**:讲述西楚霸王项羽和虞姬的爱情悲剧。
|
||||
- **《贵妃醉酒》**:展现杨贵妃醉酒时的娇态和哀怨。
|
||||
- **《三岔口》**:以武打见长的戏曲,展示了高超的武功技艺。
|
||||
- **《四郎探母》**:讲述杨四郎回到大宋探望母亲的感人故事。
|
||||
- **《赵氏孤儿》**:表现忠臣程婴舍己为人的高尚品格。
|
||||
|
||||
## 传承保护
|
||||
|
||||
2010年,京剧被联合国教科文组织列入"人类非物质文化遗产代表作名录"。河北省一直致力于京剧艺术的保护和传承工作:
|
||||
|
||||
1. 成立专业京剧团体,如河北京剧院、石家庄京剧团等。
|
||||
2. 举办京剧表演赛事和艺术节,推广京剧艺术。
|
||||
3. 在学校开展京剧教育,培养年轻一代对传统文化的兴趣。
|
||||
4. 支持京剧名家开展收徒传艺活动,确保技艺代代相传。
|
||||
|
||||
## 欣赏指南
|
||||
|
||||
观赏京剧可以从以下几个方面入手:
|
||||
|
||||
1. **角色辨认**:了解生旦净丑的不同特点和表演风格。
|
||||
2. **唱腔欣赏**:聆听京剧独特的板式变化和韵味。
|
||||
3. **表演程式**:欣赏演员的身段、手势和眼神等细节。
|
||||
4. **故事情节**:了解剧目的历史背景和故事内容。
|
||||
|
||||
初次接触京剧的观众可以从《贵妃醉酒》、《三岔口》等易于理解的剧目入手,循序渐进地领略京剧的艺术魅力。
|
||||
|
||||
## 观演信息
|
||||
|
||||
在河北欣赏正宗京剧表演,可以关注以下场所:
|
||||
|
||||
- **河北省京剧院**:定期举办各类京剧演出
|
||||
- **河北大剧院**:邀请国内知名京剧团体演出
|
||||
- **各市文化中心**:不定期举办京剧专场演出
|
||||
- **传统戏楼**:如保定古莲花池戏楼,提供传统戏台演出体验
|
||||
|
||||
京剧作为中华文化的瑰宝,凝聚着中国人的智慧和艺术追求。在河北这片文化沃土上,京剧艺术不断焕发出新的生机和活力。
|
57
web/graduation/src/content/culture/yan-opera.md
Normal file
57
web/graduation/src/content/culture/yan-opera.md
Normal file
@ -0,0 +1,57 @@
|
||||
---
|
||||
title: "评剧 - 河北独特的地方戏曲艺术"
|
||||
description: "评剧是起源于河北的重要地方戏曲剧种,以唱腔优美、表演细腻、注重情感表达为特点,被誉为'花调戏'和'女子戏'。"
|
||||
category: "戏曲艺术"
|
||||
featured: true
|
||||
image: "/images/culture/yan-opera.jpg"
|
||||
city: ["唐山"]
|
||||
tags: ["非物质文化遗产", "戏曲", "传统艺术", "女子戏", "河北文化"]
|
||||
pubDate: 2023-09-12
|
||||
---
|
||||
|
||||
# 评剧
|
||||
|
||||
评剧,原名"乱弹",是中国重要的地方戏曲剧种之一,发源于河北省唐山市丰润区(原丰润县)。因其唱腔优美动听、表演细腻生动、以女性角色为主而闻名,被誉为"中国最美丽的戏曲"之一,是河北省最具代表性的文化瑰宝。
|
||||
|
||||
## 历史渊源
|
||||
|
||||
评剧起源于19世纪末20世纪初的河北冀东地区,最初是一种名为"莲花落"的民间说唱艺术。经过农村艺人的不断改进和发展,逐渐形成了独立的戏曲剧种。评剧的"评"字原为"平",意为平调,后因谐音而改称"评剧"。在20世纪上半叶,评剧迅速在北京和全国各地流行开来,成为与京剧、豫剧并称的中国三大戏曲剧种之一。
|
||||
|
||||
## 艺术特色
|
||||
|
||||
评剧以其鲜明的艺术特点在众多戏曲剧种中独树一帜:
|
||||
|
||||
**唱腔特点**:评剧唱腔俗称"二黄调",柔美优雅,婉转动听,尤其善于表达细腻的情感和内心活动。其音域适中,节奏舒缓,适合表现抒情性的内容,被誉为"花调戏"。
|
||||
|
||||
**表演风格**:评剧表演讲究真实、细腻、生活化,不像京剧那样程式化严格,而是更注重人物内心情感的自然流露。这种表演风格使评剧更贴近生活,更易于观众理解和接受。
|
||||
|
||||
**角色体系**:评剧以"旦角"(女性角色)为中心,重视女性形象的塑造和女性情感的表达,因此也被称为"女子戏"。评剧的女性角色形象丰满,性格鲜明,尤其擅长表现女性在爱情和婚姻中的追求与挣扎。
|
||||
|
||||
## 经典剧目
|
||||
|
||||
评剧的经典剧目众多,最著名的包括:
|
||||
|
||||
- **《花为媒》**:讲述了穷秀才张元秀与贫家女李玉莲相爱,却遭遇封建礼教阻挠的故事,表现了青年男女追求自由婚姻的勇气。
|
||||
- **《刘巧儿》**:描绘了农村姑娘刘巧儿反抗封建婚姻制度,争取婚姻自由的悲剧故事。
|
||||
- **《杨三姐告状》**:讲述了清代农家女杨三姐为父兄申冤,与贪官斗争的故事,塑造了一个勇敢正直的女性形象。
|
||||
|
||||
## 代表人物
|
||||
|
||||
评剧历史上出现了许多杰出的表演艺术家,其中最著名的有:
|
||||
|
||||
- **新凤霞**:评剧表演艺术大师,开创了"新派评剧"表演风格,代表作《花为媒》《刘巧儿》等。
|
||||
- **小白玉霜**:评剧"小白派"创始人,表演细腻真切,唱腔优美动听。
|
||||
- **筱俊亭**:评剧旦角表演大师,擅长塑造刚柔并济的女性形象。
|
||||
|
||||
## 当代发展
|
||||
|
||||
随着时代的发展,评剧也在不断创新。现代评剧在保持传统艺术特色的基础上,积极吸收现代艺术元素,创作了一批反映当代生活的新剧目。同时,评剧艺术院校培养了大批年轻的评剧演员,为这一传统艺术的传承和发展注入了新鲜血液。
|
||||
|
||||
## 观赏体验
|
||||
|
||||
- **演出场所**:唐山大剧院、唐山评剧团、北京长安大戏院等
|
||||
- **演出时间**:每周末和节假日定期有演出,大型节庆期间会有特别演出
|
||||
- **票价范围**:30-300元不等,视演出规模和座位位置而定
|
||||
- **最佳体验季节**:春节、元宵节期间有集中展演
|
||||
|
||||
欣赏评剧,感受河北独特的戏曲艺术魅力,体验中国传统文化中细腻动人的情感表达。
|
96
web/graduation/src/content/travel/chengde-summer-tour.md
Normal file
96
web/graduation/src/content/travel/chengde-summer-tour.md
Normal file
@ -0,0 +1,96 @@
|
||||
---
|
||||
title: "承德三日避暑之旅 - 清凉山水与皇家园林"
|
||||
description: "这是一条专为夏季设计的承德避暑旅游路线,涵盖避暑山庄、外八庙、木兰围场等经典景点,让您在酷暑中体验清凉山水与皇家园林的完美结合。"
|
||||
season: "夏季"
|
||||
type: "休闲游"
|
||||
featured: true
|
||||
image: "/images/travel/chengde-summer.jpg"
|
||||
city: ["承德", "热河"]
|
||||
days: 3
|
||||
difficulty: "简单"
|
||||
tags: ["避暑", "皇家园林", "历史文化", "自然风光", "世界遗产"]
|
||||
pubDate: 2023-07-25
|
||||
---
|
||||
|
||||
# 承德三日避暑之旅
|
||||
|
||||
承德,这座被誉为"塞外北京"的历史文化名城,以其宜人的夏季气候和丰富的文化遗产吸引着无数游客。夏季的承德,平均气温比北京低4-5℃,是北方地区理想的避暑胜地。本攻略为您规划了三天的行程,带您领略避暑山庄的皇家风范、感受外八庙的宗教文化魅力、探索木兰围场的自然风光。
|
||||
|
||||
## 第一天:避暑山庄一日游
|
||||
|
||||
### 上午
|
||||
|
||||
- **07:30-12:00** 【避暑山庄】早晨抵达避暑山庄,参观山庄的宫殿区,包括澹泊敬诚殿、烟波致爽殿、清音阁等主要宫殿建筑。了解清代皇帝在此处理政务和休闲生活的历史。
|
||||
|
||||
### 中午
|
||||
|
||||
- **12:00-13:30** 在山庄附近的餐厅享用午餐,推荐品尝承德当地特色菜肴如围场烤全羊、承德火锅等。
|
||||
|
||||
### 下午
|
||||
|
||||
- **13:30-17:30** 继续游览避暑山庄的湖区和山区景观,如烟波致爽、月色澄莲、热河烟树等著名景点。可在湖区乘船游览,欣赏湖光山色的美景。
|
||||
|
||||
### 晚上
|
||||
|
||||
- **18:00-19:30** 在市区享用晚餐,品尝承德特色美食。
|
||||
- **20:00** 入住酒店休息,或可选择在承德市区夜景散步,欣赏城市夜色。
|
||||
|
||||
## 第二天:外八庙与普宁寺
|
||||
|
||||
### 上午
|
||||
|
||||
- **08:30-12:00** 【外八庙】参观外八庙中最具代表性的普宁寺和普陀宗乘之庙。普宁寺内有世界最大的木雕佛像(释迦牟尼坐像),普陀宗乘之庙仿照西藏布达拉宫建造,具有浓郁的藏族建筑风格。
|
||||
|
||||
### 中午
|
||||
|
||||
- **12:00-13:30** 在庙区附近用午餐,可品尝当地特色素斋或小吃。
|
||||
|
||||
### 下午
|
||||
|
||||
- **13:30-17:00** 继续参观须弥福寿之庙和安远庙,感受不同民族宗教建筑风格的融合与特色。
|
||||
- **17:00-18:30** 返回市区,在市区休息或购物。
|
||||
|
||||
### 晚上
|
||||
|
||||
- **18:30-20:00** 晚餐后可以欣赏《鼎盛王朝·康熙大典》实景剧演出(需提前预订),了解康熙与承德的历史故事。
|
||||
|
||||
## 第三天:木兰围场自然风光
|
||||
|
||||
### 上午
|
||||
|
||||
- **08:00-12:00** 【木兰围场】前往位于承德北部的木兰围场景区,参观御道口草原森林公园,体验辽阔的草原风光和清新的森林空气。可以骑马、放风筝、观赏野花等活动。
|
||||
|
||||
### 中午
|
||||
|
||||
- **12:00-13:30** 在景区内的蒙古包或农家乐享用午餐,品尝围场烤全羊、手把肉等特色美食。
|
||||
|
||||
### 下午
|
||||
|
||||
- **13:30-16:30** 参观塞罕坝国家森林公园,欣赏人工林海和天然湿地景观,感受"绿色长城"的壮观与生态保护的成就。
|
||||
- **16:30-18:00** 返回市区,整理行装准备返程。
|
||||
|
||||
## 住宿推荐
|
||||
|
||||
- **高档**:承德金龙国际大酒店、承德勒泰假日酒店
|
||||
- **中档**:承德避暑山庄宾馆、承德金山饭店
|
||||
- **经济**:如家快捷酒店(承德火车站店)、7天连锁酒店
|
||||
|
||||
## 交通建议
|
||||
|
||||
- **外部交通**:从北京可乘坐高铁(约2小时)或长途汽车(约4小时)抵达承德
|
||||
- **市内交通**:
|
||||
- 公交车:承德市内公交网络发达,可乘坐5路、15路等公交线路到达主要景点
|
||||
- 出租车:起步价约8元,市区主要景点间车程一般不超过20分钟
|
||||
- 景区观光车:避暑山庄和外八庙内有观光车服务,单程票价约10元
|
||||
|
||||
## 旅行贴士
|
||||
|
||||
1. **最佳旅游时间**:7-8月是承德避暑的最佳季节,平均气温约24℃
|
||||
2. **着装建议**:夏季白天温暖但早晚温差大,建议携带轻薄外套
|
||||
3. **门票信息**:
|
||||
- 避暑山庄:旺季115元/人,淡季70元/人
|
||||
- 外八庙联票:旺季约180元/人,可选择单独购买感兴趣的寺庙门票
|
||||
- 木兰围场:各景点门票约60-120元不等
|
||||
4. **特别提示**:参观寺庙时注意着装得体,尊重宗教习俗;林区防蚊虫叮咬,注意防晒
|
||||
|
||||
来承德避暑,感受清代皇家园林的恢宏气势,领略塞外自然风光的独特魅力,度过一个清凉舒适的夏日之旅。
|
103
web/graduation/src/content/travel/langfang-spring-tour.md
Normal file
103
web/graduation/src/content/travel/langfang-spring-tour.md
Normal file
@ -0,0 +1,103 @@
|
||||
---
|
||||
title: "廊坊春日花海之旅 - 京津冀花卉观赏攻略"
|
||||
description: "一份详细的廊坊春季赏花旅游攻略,带您领略京津两大城市之间这颗璀璨明珠的春日风光,体验花海美景与田园风情。"
|
||||
season: "春季"
|
||||
type: "赏花游"
|
||||
featured: true
|
||||
image: "/images/travel/langfang-spring.jpg"
|
||||
city: ["廊坊"]
|
||||
days: 2
|
||||
difficulty: "简单"
|
||||
tags: ["赏花", "乡村游", "亲子", "踏青", "文化体验"]
|
||||
pubDate: 2023-03-10
|
||||
---
|
||||
|
||||
# 廊坊春日花海之旅
|
||||
|
||||
廊坊市位于河北省东部,京津走廊的中心地带,素有"京津走廊明珠"的美誉。每到春季,这座城市便化身为一座缤纷花园,郁金香、樱花、杏花、油菜花等竞相绽放,吸引着无数游客前来踏青赏花。本攻略为您规划了两天的行程,带您体验廊坊的春日风光、花海美景和人文历史。
|
||||
|
||||
## 最佳旅游时间
|
||||
|
||||
3月中旬至5月初是廊坊春季赏花的最佳时段:
|
||||
- 3月中下旬:杏花、梨花盛开
|
||||
- 4月上中旬:郁金香、樱花绽放
|
||||
- 4月下旬至5月初:油菜花、牡丹、芍药争艳
|
||||
|
||||
## 第一天:香河赏花与文化之旅
|
||||
|
||||
### 上午
|
||||
|
||||
- **09:00-11:30** 【香河爱情海购物公园】这是华北地区最大的郁金香主题公园,拥有数百万株荷兰进口郁金香,品种超过100种。春季有"郁金香花海节",各色郁金香竞相绽放,令人陶醉。公园内还设有郁金香科普展示区,游客可了解郁金香的历史文化和种植知识。
|
||||
|
||||
### 中午
|
||||
|
||||
- **12:00-13:30** 在香河古城附近的农家院或特色餐厅享用午餐,推荐品尝香河肉饼、农家炖菜等当地特色美食。
|
||||
|
||||
### 下午
|
||||
|
||||
- **14:00-16:30** 【香河古城】这是一座具有千年历史的古城,保存了大量的明清建筑。漫步在古城街巷,参观荣国府、大清邮局、三义庙等历史遗迹,感受传统文化的魅力。春季的古城杏花、梨花盛开,古色古香的建筑与花朵相映成趣,是拍照的绝佳地点。
|
||||
|
||||
- **16:30-18:00** 【香河家具城】作为"中国北方家具之都",来香河不妨参观一下规模宏大的家具城,了解中国传统家具文化和现代家居设计,也可选购喜欢的家具和工艺品。
|
||||
|
||||
### 晚上
|
||||
|
||||
- **18:30-20:00** 返回廊坊市区,在市中心的万达广场或凯隆广场享用晚餐,品尝廊坊特色美食。
|
||||
- **20:00** 入住廊坊市区酒店休息。
|
||||
|
||||
## 第二天:固安春色与生态探索
|
||||
|
||||
### 上午
|
||||
|
||||
- **08:30-12:00** 【固安油菜花海】每年4月中下旬,固安县的油菜花进入盛花期,金黄色的花海延绵数公里,蔚为壮观。游客可以漫步花海、拍照留念,也可以参加当地组织的油菜花节活动,体验农耕文化和乡村生活。
|
||||
|
||||
### 中午
|
||||
|
||||
- **12:00-13:30** 在油菜花海附近的农家乐享用午餐,推荐品尝农家炖鸡、手工面食等地道美食。
|
||||
|
||||
### 下午
|
||||
|
||||
- **14:00-16:30** 【大清御河生态走廊】这是一条贯穿廊坊市区的生态景观带,春季绿柳成荫,花草繁茂。沿着河岸漫步,欣赏沿河两岸的景观设计和生态环境,也可租赁自行车沿着专用车道骑行,感受春风拂面的惬意。
|
||||
|
||||
- **16:30-18:00** 【文化广场樱花园】廊坊市区的文化广场种植了大量樱花树,四月份是观赏樱花的最佳时节。傍晚时分,落日余晖下的樱花别有一番韵味,是拍摄浪漫照片的好时机。
|
||||
|
||||
### 晚上
|
||||
|
||||
- **18:30** 结束行程,返程或继续在廊坊市区游览夜景。
|
||||
|
||||
## 交通建议
|
||||
|
||||
- **外部交通**:
|
||||
- 高铁:北京、天津至廊坊约20-30分钟
|
||||
- 公路:京沪高速、京哈高速等多条高速公路经过廊坊
|
||||
- 公交:北京六里桥、永定门等长途汽车站有直达廊坊的班车
|
||||
|
||||
- **市内交通**:
|
||||
- 出租车:起步价约8元,市区内一般在20元左右
|
||||
- 公交车:覆盖主要景点,票价1-2元
|
||||
- 景区观光车:部分景区内提供观光车服务
|
||||
- 共享单车:市区内可使用共享单车短途出行
|
||||
|
||||
## 住宿推荐
|
||||
|
||||
- **高档**:廊坊万达嘉华酒店、廊坊世纪星卓越酒店
|
||||
- **中档**:廊坊国际酒店、廊坊福朋喜来登酒店
|
||||
- **经济**:如家快捷酒店、格林豪泰、七天连锁酒店
|
||||
- **特色**:香河农家院,可体验乡村生活
|
||||
|
||||
## 美食推荐
|
||||
|
||||
1. **香河肉饼**:香河县传统特色小吃,外酥里嫩,肉香四溢
|
||||
2. **固安扒鸡**:选用当地散养鸡,经特殊工艺制作,肉质鲜嫩
|
||||
3. **廊坊柳条肉**:当地有名的家常菜,肉质细嫩,味道鲜美
|
||||
4. **杨村糕点**:历史悠久的传统糕点,品种繁多,口感独特
|
||||
5. **永清豆腐宴**:以豆腐为主料制作的多种菜肴,清淡健康
|
||||
|
||||
## 旅行贴士
|
||||
|
||||
1. **着装建议**:春季温差较大,建议穿着舒适的轻便衣物,并带一件外套
|
||||
2. **花期预报**:出发前可关注当地旅游官网或公众号的花期预报
|
||||
3. **赏花礼仪**:欣赏花朵时请勿采摘或踩踏,保护自然环境
|
||||
4. **交通提示**:周末和节假日赏花景点人流量大,建议提前规划路线
|
||||
5. **摄影装备**:准备好相机和充足的存储卡,捕捉美丽的春日花景
|
||||
|
||||
廊坊春季之旅,让您在京津两大城市之间,找到一片宁静美丽的花海天地,感受春天的生机与活力,收获满满的幸福和美好记忆。
|
@ -1,193 +0,0 @@
|
||||
---
|
||||
title: 河北夏季避暑休闲之旅
|
||||
description: 河北夏季有众多避暑胜地,秦皇岛北戴河海滨、承德避暑山庄、张家口崇礼都是理想的避暑休闲目的地,享受凉爽惬意的假期。
|
||||
season: 夏季
|
||||
type: 旅行贴士
|
||||
featured: true
|
||||
image: https://picsum.photos/seed/hebei-summer/800/600
|
||||
days: 5
|
||||
difficulty: 简单
|
||||
tags: ['避暑胜地', '海滨度假', '休闲旅游']
|
||||
pubDate: 2023-05-20
|
||||
updatedDate: 2023-11-30
|
||||
---
|
||||
|
||||
# 河北夏季避暑休闲之旅
|
||||
|
||||
## 攻略概述
|
||||
|
||||
夏季是旅游的旺季,但高温往往让人望而却步。而河北省凭借其独特的地理位置和多样的地形条件,拥有众多避暑胜地,是夏季旅游的理想选择。从东部的海滨度假区到北部的山地避暑胜地,再到历史悠久的皇家园林,河北为游客提供了多种避暑休闲的选择。
|
||||
|
||||
本攻略将为您详细介绍河北夏季最佳的避暑目的地、精心规划的5日行程、特色体验活动以及实用的旅行贴士,帮助您度过一个凉爽舒适的夏日假期。
|
||||
|
||||
## 最佳旅行时间
|
||||
|
||||
**6月中旬至8月底**是游览河北避暑胜地的黄金时期。此时河北内陆地区气温较高,而本攻略推荐的避暑目的地气温适宜,通常比内陆地区低5-10℃。尤其是7月中旬到8月中旬,正值内陆高温季节,河北的避暑胜地优势更为明显。
|
||||
|
||||
## 推荐目的地
|
||||
|
||||
### 1. 秦皇岛北戴河
|
||||
|
||||
北戴河是中国最著名的海滨避暑胜地之一,夏季平均气温比内陆低8℃左右。这里拥有绵延的金色沙滩、清澈的海水和舒适的海风,是消暑纳凉的绝佳去处。
|
||||
|
||||
**主要景点**:
|
||||
- **北戴河海滨**:绵延数公里的沙滩,海水清澈,适合游泳、沙滩排球等活动。
|
||||
- **鸽子窝公园**:融合了园林景观与海滨风光,是观赏日出的最佳地点。
|
||||
- **老虎石海上公园**:因礁石形似虎头而得名,海景壮观。
|
||||
- **联峰山公园**:山顶可俯瞰整个北戴河海滨。
|
||||
|
||||
**特色体验**:
|
||||
- 清晨在沙滩漫步,感受第一缕阳光
|
||||
- 品尝新鲜的海鲜大餐
|
||||
- 参加沙滩排球或沙雕比赛
|
||||
- 在海边露营,欣赏星空
|
||||
|
||||
### 2. 承德避暑山庄
|
||||
|
||||
作为清代皇家避暑胜地,避暑山庄不仅拥有丰富的历史文化遗产,还因其独特的地理位置和园林设计,成为夏季理想的避暑地。山庄内山水相融,植被茂密,气温比北京低5-8℃。
|
||||
|
||||
**主要景点**:
|
||||
- **避暑山庄主体**:包括宫殿区、湖区、平原区和山区,布局巧妙,景色宜人。
|
||||
- **外八庙**:包括普宁寺、普佑寺等,展现了清代多民族融合的建筑艺术。
|
||||
- **磬锤峰**:避暑山庄附近的自然景观,形似磬锤,景色壮观。
|
||||
|
||||
**特色体验**:
|
||||
- 穿着清代服饰在山庄内拍照留念
|
||||
- 参加山庄内的文化体验活动,如宫廷茶艺、满族剪纸等
|
||||
- 在园内的亭台楼阁中休憩,感受皇家避暑的惬意
|
||||
|
||||
### 3. 张家口崇礼
|
||||
|
||||
崇礼因2022年冬奥会而闻名,但其实夏季的崇礼也是绝佳的避暑胜地。这里海拔较高,夏季平均气温仅为20℃左右,草原青翠,空气清新,是避暑休闲的理想选择。
|
||||
|
||||
**主要景点**:
|
||||
- **崇礼滑雪场**:夏季转型为高山草甸和户外运动基地。
|
||||
- **太舞滑雪小镇**:冬奥会场馆,夏季可参观奥运遗址并体验各种户外活动。
|
||||
- **草原天路**:盘山公路,沿途风景如画,是自驾游的绝佳线路。
|
||||
- **大境门**:历史悠久的古代关隘,现为重要的旅游景点。
|
||||
|
||||
**特色体验**:
|
||||
- 高山徒步或山地自行车
|
||||
- 草原露营,观星
|
||||
- 体验草原骑马、射箭等活动
|
||||
- 品尝当地特色美食如莜面、烤全羊等
|
||||
|
||||
## 5日精选行程
|
||||
|
||||
### Day 1:抵达秦皇岛
|
||||
- **上午**:抵达秦皇岛,入住北戴河海滨酒店
|
||||
- **下午**:游览北戴河海滨,在沙滩上休闲放松,适应海边环境
|
||||
- **晚上**:在海边餐厅享用新鲜海鲜大餐,体验当地夜市文化
|
||||
|
||||
### Day 2:深度游北戴河
|
||||
- **上午**:参观鸽子窝公园,欣赏日出和海滨风光
|
||||
- **下午**:游览老虎石海上公园,体验海边刺激项目
|
||||
- **晚上**:在沙滩参加篝火晚会或沙滩音乐节(夏季常有活动)
|
||||
|
||||
### Day 3:前往承德
|
||||
- **上午**:从秦皇岛出发前往承德(车程约3小时)
|
||||
- **下午**:抵达承德后入住酒店,游览承德市区,调整状态
|
||||
- **晚上**:品尝承德特色菜,如承德火锅、双鱼涮肉等
|
||||
|
||||
### Day 4:游览避暑山庄
|
||||
- **全天**:游览避暑山庄及外八庙,深度了解清代历史文化
|
||||
- **推荐路线**:上午游览宫殿区和湖区,下午游览平原区和部分外八庙
|
||||
- **晚上**:观看承德民俗文化表演,体验满族文化
|
||||
|
||||
### Day 5:前往崇礼
|
||||
- **上午**:从承德出发前往崇礼(车程约3.5小时)
|
||||
- **下午**:抵达崇礼,游览太舞滑雪小镇,体验夏季高山活动
|
||||
- **晚上**:在山间酒店或民宿住宿,享受凉爽的夏夜
|
||||
|
||||
## 交通指南
|
||||
|
||||
### 外部交通
|
||||
- **航空**:秦皇岛山海关机场和张家口宁远机场都有定期航班
|
||||
- **铁路**:京津冀地区高铁网络发达,从北京到秦皇岛、承德、张家口均有高速列车
|
||||
- **公路**:京承高速、京沈高速等多条高速公路连接主要城市
|
||||
|
||||
### 内部交通
|
||||
- **租车自驾**:最为便捷的出行方式,特别是在崇礼地区
|
||||
- **公共交通**:各城市均有完善的公交系统,景区间有旅游专线
|
||||
- **网约车**:主要城市都有滴滴等网约车服务
|
||||
- **景区交通**:大型景区内有电瓶车等交通工具
|
||||
|
||||
## 住宿推荐
|
||||
|
||||
### 秦皇岛北戴河
|
||||
- **高端选择**:北戴河嘉轩酒店、秦皇岛海景国际大酒店
|
||||
- **中端选择**:北戴河阿那亚一宿、如家精选酒店
|
||||
- **经济选择**:北戴河海滨青年旅舍、驿家365连锁酒店
|
||||
|
||||
### 承德
|
||||
- **高端选择**:承德喜来登酒店、承德避暑山庄皇冠假日酒店
|
||||
- **中端选择**:承德金龙温泉酒店、承德万豪酒店
|
||||
- **经济选择**:如家快捷酒店、汉庭酒店
|
||||
|
||||
### 崇礼
|
||||
- **高端选择**:崇礼富龙滑雪场酒店、万龙滑雪场度假酒店
|
||||
- **中端选择**:太舞滑雪小镇酒店、崇礼云顶酒店
|
||||
- **经济选择**:崇礼家庭民宿、青年旅舍
|
||||
|
||||
## 美食指南
|
||||
|
||||
### 秦皇岛
|
||||
- **海鲜**:螃蟹、对虾、扇贝等各类新鲜海鲜
|
||||
- **特色小吃**:面茶、烧烤、杂鱼汤等
|
||||
|
||||
### 承德
|
||||
- **满族菜**:关东糟熘鱼、清蒸鹿尾、八旗布丁等
|
||||
- **地方特色**:承德火锅、双鱼涮肉、驴肉火烧
|
||||
|
||||
### 崇礼
|
||||
- **农家菜**:莜面、土豆、山野菜等
|
||||
- **烤全羊**:草原特色美食
|
||||
- **奶制品**:酸奶、奶豆腐、奶茶等
|
||||
|
||||
## 旅行贴士
|
||||
|
||||
### 装备建议
|
||||
- **衣物**:虽是避暑胜地,但早晚温差大,建议带薄外套
|
||||
- **防晒**:高原和海边紫外线强,做好防晒措施
|
||||
- **泳装**:在北戴河需要,可以海滨游泳
|
||||
- **徒步鞋**:适合在崇礼的山地徒步
|
||||
|
||||
### 安全提示
|
||||
- **海边安全**:注意遵守游泳区域规定,不要在无人看管的海域游泳
|
||||
- **高原反应**:崇礼海拔虽不算高,但部分敏感人群可能有轻微高原反应
|
||||
- **天气变化**:山区天气多变,出行前查看天气预报
|
||||
|
||||
### 其他建议
|
||||
- **最佳游览时间**:避开周末和节假日,人流量会少很多
|
||||
- **预订建议**:夏季是旅游旺季,建议提前1-2个月预订酒店和交通
|
||||
- **当地习俗**:承德有满族和蒙古族居民,崇礼有蒙古族传统,注意尊重当地习俗
|
||||
|
||||
## 花费参考
|
||||
|
||||
### 交通费用
|
||||
- 北京到秦皇岛高铁:约150-250元/人
|
||||
- 秦皇岛到承德汽车:约150元/人
|
||||
- 承德到崇礼汽车:约180元/人
|
||||
- 租车费用:约300-500元/天
|
||||
|
||||
### 住宿费用
|
||||
- 高端酒店:800-2000元/晚
|
||||
- 中端酒店:400-800元/晚
|
||||
- 经济型住宿:150-400元/晚
|
||||
|
||||
### 餐饮费用
|
||||
- 海鲜大餐:200-500元/人
|
||||
- 普通正餐:50-100元/人
|
||||
- 特色小吃:20-50元/人
|
||||
|
||||
### 门票费用
|
||||
- 北戴河景区:大多免费或30-50元
|
||||
- 避暑山庄:115-145元(淡旺季不同)
|
||||
- 外八庙联票:约100元
|
||||
- 崇礼景区:多为30-80元
|
||||
|
||||
## 总结
|
||||
|
||||
河北夏季避暑休闲之旅集海滨风光、皇家园林与高山草原于一体,为游客提供多样化的避暑选择。在炎炎夏日,您可以在北戴河感受海风拂面的舒适,在避暑山庄体验皇家的惬意生活,在崇礼的高山草原呼吸最清新的空气。这条路线既能让您避开酷暑,又能体验河北丰富的自然风光和人文历史,是夏季旅行的绝佳选择。
|
||||
|
||||
祝您旅途愉快!
|
@ -10,6 +10,13 @@ interface Props {
|
||||
}
|
||||
|
||||
const { title, description = "河北游礼宣传网站 - 探索河北的文化与魅力" } = Astro.props;
|
||||
|
||||
// 社交媒体数据
|
||||
const socialLinks = [
|
||||
{ name: "微信", url: "#" },
|
||||
{ name: "微博", url: "#" },
|
||||
{ name: "抖音", url: "#" }
|
||||
];
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
@ -27,7 +34,7 @@ const { title, description = "河北游礼宣传网站 - 探索河北的文化
|
||||
<SmoothScroll />
|
||||
|
||||
<div class="min-h-screen flex flex-col">
|
||||
<header class="sticky top-0 z-50 bg-white border-b border-border-color shadow-sm dark:bg-color-dark-surface">
|
||||
<header class="sticky top-0 z-50 bg-white dark:bg-color-dark-surface">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-16">
|
||||
<!-- 网站Logo和名称 -->
|
||||
@ -46,7 +53,7 @@ const { title, description = "河北游礼宣传网站 - 探索河北的文化
|
||||
<a href="/travel" class="text-gray-700 hover:text-color-primary-600 dark:text-gray-300 dark:hover:text-color-primary-400">旅游攻略</a>
|
||||
</nav>
|
||||
|
||||
<!-- 主题切换按钮 -->
|
||||
<!-- 主题切换按钮和移动端菜单 -->
|
||||
<div class="flex items-center">
|
||||
<ThemeToggle />
|
||||
|
||||
@ -94,24 +101,14 @@ const { title, description = "河北游礼宣传网站 - 探索河北的文化
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold mb-4 text-gray-900 dark:text-white">关注我们</h3>
|
||||
<div class="flex space-x-4">
|
||||
<a href="#" class="text-gray-600 hover:text-color-primary-600 dark:text-gray-400 dark:hover:text-color-primary-400">
|
||||
<span class="sr-only">微信</span>
|
||||
<svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="#" class="text-gray-600 hover:text-color-primary-600 dark:text-gray-400 dark:hover:text-color-primary-400">
|
||||
<span class="sr-only">微博</span>
|
||||
<svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="#" class="text-gray-600 hover:text-color-primary-600 dark:text-gray-400 dark:hover:text-color-primary-400">
|
||||
<span class="sr-only">抖音</span>
|
||||
<svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>
|
||||
</svg>
|
||||
</a>
|
||||
{socialLinks.map(({name, url}) => (
|
||||
<a href={url} class="social-icon text-gray-600 hover:text-color-primary-600 dark:text-gray-400 dark:hover:text-color-primary-400">
|
||||
<span class="sr-only">{name}</span>
|
||||
<svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/>
|
||||
</svg>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -123,23 +120,28 @@ const { title, description = "河北游礼宣传网站 - 探索河北的文化
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 移动端菜单切换逻辑
|
||||
// 移动端菜单切换
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const mobileMenuToggle = document.getElementById('mobileMenuToggle');
|
||||
const mobileMenu = document.getElementById('mobileMenu');
|
||||
|
||||
// 移动端菜单切换
|
||||
const toggleMobileMenu = () => {
|
||||
if (mobileMenu) {
|
||||
mobileMenu.classList.toggle('hidden');
|
||||
}
|
||||
};
|
||||
|
||||
// 事件监听
|
||||
if (mobileMenuToggle) {
|
||||
mobileMenuToggle.addEventListener('click', toggleMobileMenu);
|
||||
}
|
||||
mobileMenuToggle?.addEventListener('click', () => {
|
||||
mobileMenu?.classList.toggle('hidden');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
<style>
|
||||
.social-icon {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.social-icon:hover {
|
||||
color: var(--theme-primary);
|
||||
}
|
||||
</style>
|
@ -33,54 +33,73 @@ const relatedAttractions = allAttractions
|
||||
---
|
||||
|
||||
<MainLayout title={`${entry.data.title} - 河北游礼`}>
|
||||
<!-- 移动端浮动返回按钮 -->
|
||||
<div class="md:hidden fixed bottom-6 left-1/2 transform -translate-x-1/2 z-50">
|
||||
<a
|
||||
href="/attractions"
|
||||
class="flex items-center space-x-2 px-5 py-3 bg-primary-600 text-white rounded-full shadow-lg hover:bg-primary-700 transition-colors"
|
||||
aria-label="返回所有景点"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 17l-5-5m0 0l5-5m-5 5h12" />
|
||||
</svg>
|
||||
<span>返回景点列表</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- 页面标题区域 -->
|
||||
<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-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="/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>
|
||||
)}
|
||||
<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>
|
||||
|
||||
{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 max-w-3xl">{entry.data.description}</p>
|
||||
</ScrollReveal>
|
||||
<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>
|
||||
</div>
|
||||
<div class="hidden lg:block lg:col-span-1">
|
||||
<!-- 与底部边栏对齐的空白区域 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 主要内容区域 -->
|
||||
<div class="py-12 bg-white dark:bg-dark-bg">
|
||||
<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="grid grid-cols-1 lg:grid-cols-3 gap-12">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8 lg:gap-12">
|
||||
<!-- 左侧内容 -->
|
||||
<div class="lg:col-span-2">
|
||||
<ScrollReveal animation="fade">
|
||||
@ -91,19 +110,54 @@ const relatedAttractions = allAttractions
|
||||
</div>
|
||||
|
||||
<!-- 右侧边栏 -->
|
||||
<div class="space-y-8">
|
||||
<div class="space-y-6 md:space-y-8">
|
||||
<!-- 景点图片 -->
|
||||
<ScrollReveal animation="slide-up">
|
||||
<div class="rounded-lg overflow-hidden shadow-md">
|
||||
<div class="h-64 bg-gray-300 dark:bg-gray-700 flex items-center justify-center">
|
||||
<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>
|
||||
</ScrollReveal>
|
||||
|
||||
<!-- 移动端快速信息栏 -->
|
||||
<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="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>
|
||||
|
||||
<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>
|
||||
</ScrollReveal>
|
||||
</div>
|
||||
|
||||
<!-- 景点信息卡片 -->
|
||||
<ScrollReveal animation="slide-up" delay={100}>
|
||||
<div class="bg-gray-50 dark:bg-color-dark-card rounded-lg shadow-md p-6">
|
||||
<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">
|
||||
@ -114,7 +168,7 @@ const relatedAttractions = allAttractions
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div class="flex">
|
||||
<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) => (
|
||||
@ -136,63 +190,66 @@ const relatedAttractions = allAttractions
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
|
||||
<!-- 交通信息 -->
|
||||
<div class="bg-primary-50 dark:bg-primary-900/20 rounded-lg p-6 shadow-sm border border-primary-100 dark:border-primary-800">
|
||||
<h3 class="text-lg font-semibold text-primary-800 dark:text-primary-300 mb-4 flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2 text-primary-600 dark:text-primary-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
|
||||
</svg>
|
||||
交通指南
|
||||
</h3>
|
||||
<ul class="space-y-3 text-gray-700 dark:text-gray-300">
|
||||
<li class="flex items-start">
|
||||
<span class="text-primary-500 dark:text-primary-400 mr-2">🚌</span>
|
||||
<span>公交路线: 10路, 15路, 22路到河北博物馆站下车</span>
|
||||
</li>
|
||||
<li class="flex items-start">
|
||||
<span class="text-primary-500 dark:text-primary-400 mr-2">🚗</span>
|
||||
<span>自驾路线: 导航至"{entry.data.title}"即可</span>
|
||||
</li>
|
||||
<li class="flex items-start">
|
||||
<span class="text-primary-500 dark:text-primary-400 mr-2">🚄</span>
|
||||
<span>高铁/火车: 到达石家庄站后可换乘公交或出租车</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- 开放时间和门票 -->
|
||||
<div class="bg-secondary-50 dark:bg-secondary-900/20 rounded-lg p-6 shadow-sm border border-secondary-100 dark:border-secondary-800">
|
||||
<h3 class="text-lg font-semibold text-secondary-800 dark:text-secondary-300 mb-4 flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2 text-secondary-600 dark:text-secondary-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
参观信息
|
||||
</h3>
|
||||
<div class="space-y-3 text-gray-700 dark:text-gray-300">
|
||||
<p class="flex items-center">
|
||||
<span class="text-secondary-500 dark:text-secondary-400 mr-2">⏰</span>
|
||||
<span>开放时间: 09:00-17:00 (周一至周日)</span>
|
||||
</p>
|
||||
<p class="flex items-center">
|
||||
<span class="text-secondary-500 dark:text-secondary-400 mr-2">🎫</span>
|
||||
<span>门票: 成人票50元, 学生票25元</span>
|
||||
</p>
|
||||
<p class="flex items-center">
|
||||
<span class="text-secondary-500 dark:text-secondary-400 mr-2">📞</span>
|
||||
<span>咨询电话: 0311-12345678</span>
|
||||
</p>
|
||||
<!-- 信息卡片组 -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-1 gap-4">
|
||||
<!-- 交通信息 -->
|
||||
<div class="bg-primary-50 dark:bg-primary-900/20 rounded-lg p-5 shadow-sm border border-primary-100 dark:border-primary-800">
|
||||
<h3 class="text-lg font-semibold text-primary-800 dark:text-primary-300 mb-3 flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2 text-primary-600 dark:text-primary-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
|
||||
</svg>
|
||||
交通指南
|
||||
</h3>
|
||||
<ul class="space-y-2 text-gray-700 dark:text-gray-300 text-sm md:text-base">
|
||||
<li class="flex items-start">
|
||||
<span class="text-primary-500 dark:text-primary-400 mr-2">🚌</span>
|
||||
<span>公交路线: 10路, 15路, 22路到河北博物馆站下车</span>
|
||||
</li>
|
||||
<li class="flex items-start">
|
||||
<span class="text-primary-500 dark:text-primary-400 mr-2">🚗</span>
|
||||
<span>自驾路线: 导航至"{entry.data.title}"即可</span>
|
||||
</li>
|
||||
<li class="flex items-start">
|
||||
<span class="text-primary-500 dark:text-primary-400 mr-2">🚄</span>
|
||||
<span>高铁/火车: 到达石家庄站后可换乘公交或出租车</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- 开放时间和门票 -->
|
||||
<div class="bg-secondary-50 dark:bg-secondary-900/20 rounded-lg p-5 shadow-sm border border-secondary-100 dark:border-secondary-800">
|
||||
<h3 class="text-lg font-semibold text-secondary-800 dark:text-secondary-300 mb-3 flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2 text-secondary-600 dark:text-secondary-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
参观信息
|
||||
</h3>
|
||||
<div class="space-y-2 text-gray-700 dark:text-gray-300 text-sm md:text-base">
|
||||
<p class="flex items-center">
|
||||
<span class="text-secondary-500 dark:text-secondary-400 mr-2">⏰</span>
|
||||
<span>开放时间: 09:00-17:00 (周一至周日)</span>
|
||||
</p>
|
||||
<p class="flex items-center">
|
||||
<span class="text-secondary-500 dark:text-secondary-400 mr-2">🎫</span>
|
||||
<span>门票: 成人票50元, 学生票25元</span>
|
||||
</p>
|
||||
<p class="flex items-center">
|
||||
<span class="text-secondary-500 dark:text-secondary-400 mr-2">📞</span>
|
||||
<span>咨询电话: 0311-12345678</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 周边推荐 -->
|
||||
<div class="bg-accent-50 dark:bg-accent-900/20 rounded-lg p-6 shadow-sm border border-accent-100 dark:border-accent-800">
|
||||
<h3 class="text-lg font-semibold text-accent-800 dark:text-accent-300 mb-4 flex items-center">
|
||||
<div class="bg-accent-50 dark:bg-accent-900/20 rounded-lg p-5 shadow-sm border border-accent-100 dark:border-accent-800">
|
||||
<h3 class="text-lg font-semibold text-accent-800 dark:text-accent-300 mb-3 flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2 text-accent-600 dark:text-accent-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l1.519 4.674a1 1 0 00.95.69h4.915c.969 0 1.371 1.24.588 1.81l-3.976 2.888a1 1 0 00-.363 1.118l1.518 4.674c.3.922-.755 1.688-1.538 1.118l-3.976-2.888a1 1 0 00-1.176 0l-3.976 2.888c-.783.57-1.838-.197-1.538-1.118l1.518-4.674a1 1 0 00-.363-1.118l-3.976-2.888c-.784-.57-.38-1.81.588-1.81h4.914a1 1 0 00.951-.69l1.519-4.674z" />
|
||||
</svg>
|
||||
周边推荐
|
||||
</h3>
|
||||
<ul class="space-y-2 text-gray-700 dark:text-gray-300">
|
||||
<ul class="space-y-2 text-gray-700 dark:text-gray-300 text-sm md:text-base">
|
||||
<li class="flex items-start">
|
||||
<span class="text-accent-500 dark:text-accent-400 mr-2">🏯</span>
|
||||
<span>历史文化街区 (步行10分钟)</span>
|
||||
@ -210,13 +267,13 @@ const relatedAttractions = allAttractions
|
||||
|
||||
<!-- 相关景点 -->
|
||||
{relatedAttractions.length > 0 && (
|
||||
<div class="bg-primary-50 dark:bg-primary-900/20 rounded-lg p-6 shadow-sm border border-primary-100 dark:border-primary-800 mt-6">
|
||||
<h3 class="text-lg font-semibold text-primary-800 dark:text-primary-300 mb-4">相关景点</h3>
|
||||
<div class="space-y-4">
|
||||
<div class="bg-primary-50 dark:bg-primary-900/20 rounded-lg p-5 shadow-sm border border-primary-100 dark:border-primary-800">
|
||||
<h3 class="text-lg font-semibold text-primary-800 dark:text-primary-300 mb-3">相关景点</h3>
|
||||
<div class="space-y-3">
|
||||
{relatedAttractions.map((attraction: CollectionEntry<"attractions">) => (
|
||||
<a href={`/attractions/${attraction.slug}`} class="block group">
|
||||
<div class="flex items-start space-x-3 p-3 rounded-lg hover:bg-primary-100 dark:hover:bg-primary-900/30 transition-colors">
|
||||
<div class="w-16 h-16 rounded bg-primary-200 dark:bg-primary-800 flex items-center justify-center text-primary-700 dark:text-primary-300 flex-shrink-0">
|
||||
<div class="w-12 h-12 md:w-16 md:h-16 rounded bg-primary-200 dark:bg-primary-800 flex items-center justify-center text-primary-700 dark:text-primary-300 flex-shrink-0">
|
||||
{attraction.data.title.substring(0, 1)}
|
||||
</div>
|
||||
<div>
|
||||
@ -234,75 +291,19 @@ const relatedAttractions = allAttractions
|
||||
</div>
|
||||
)}
|
||||
|
||||
<!-- 返回按钮 -->
|
||||
<ScrollReveal animation="slide-up" delay={300}>
|
||||
<a
|
||||
href="/attractions"
|
||||
class="block w-full py-3 text-center bg-color-primary-600 text-white rounded-md hover:bg-color-primary-700 transition-colors dark:bg-color-dark-primary-600 dark:hover:bg-color-dark-primary-500"
|
||||
>
|
||||
返回所有景点
|
||||
</a>
|
||||
</ScrollReveal>
|
||||
<!-- 返回按钮 - 仅在非移动端显示 -->
|
||||
<div 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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 相关景点 -->
|
||||
<div class="py-16 bg-gradient-to-b from-white to-primary-50 dark:from-dark-bg dark:to-primary-900/10">
|
||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<ScrollReveal animation="fade">
|
||||
<h2 class="text-3xl font-bold text-gray-900 dark:text-white mb-8 text-center">探索更多河北景点</h2>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-8 max-w-6xl mx-auto">
|
||||
{relatedAttractions.map((attraction: CollectionEntry<"attractions">) => (
|
||||
<a href={`/attractions/${attraction.slug}`} class="group">
|
||||
<div class="bg-white dark:bg-dark-surface rounded-lg overflow-hidden shadow-md transition-all duration-300 hover:shadow-lg border border-primary-100 dark:border-primary-900/50 h-full flex flex-col">
|
||||
<div class="h-48 bg-primary-100 dark:bg-primary-900/30 relative overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gradient-to-br from-primary-500/20 to-accent-500/30 group-hover:opacity-70 opacity-0 transition-opacity duration-300"></div>
|
||||
<div class="flex items-center justify-center h-full text-primary-700 dark:text-primary-300">
|
||||
{attraction.data.title}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 flex-grow">
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-2 group-hover:text-primary-600 dark:group-hover:text-primary-400 transition-colors">
|
||||
{attraction.data.title}
|
||||
</h3>
|
||||
|
||||
<p class="text-gray-600 dark:text-gray-400 text-sm mb-4 line-clamp-2">
|
||||
{attraction.data.description}
|
||||
</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{attraction.data.tags.slice(0, 3).map((tag: string) => (
|
||||
<span class="text-xs px-2 py-1 bg-primary-50 dark:bg-primary-900/40 text-primary-700 dark:text-primary-300 rounded-full">
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 border-t border-primary-100 dark:border-primary-800/50 flex justify-between items-center">
|
||||
<span class="text-sm text-primary-600 dark:text-primary-400 font-medium">查看详情</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 text-primary-500 dark:text-primary-400 group-hover:translate-x-1 transition-transform" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-12">
|
||||
<a href="/attractions" class="inline-flex items-center px-6 py-3 bg-primary-600 hover:bg-primary-700 dark:bg-primary-700 dark:hover:bg-primary-600 text-white font-medium rounded-lg shadow-md hover:shadow-lg transition-all duration-300">
|
||||
<span>浏览全部景点</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 ml-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</ScrollReveal>
|
||||
</div>
|
||||
</div>
|
||||
</MainLayout>
|
File diff suppressed because it is too large
Load Diff
@ -86,6 +86,17 @@ const relatedCuisines = allCuisines
|
||||
<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>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -50,9 +50,15 @@ const relatedCultures = allCultures
|
||||
<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 && (
|
||||
{entry.data.city && entry.data.city.length > 0 && (
|
||||
<div class="flex items-center text-white/90">
|
||||
<span class="mr-1">📍</span> {entry.data.city}
|
||||
<span class="mr-1">📍</span>
|
||||
{entry.data.city.map((cityName, index) => (
|
||||
<>
|
||||
<span>{cityName}</span>
|
||||
{index < entry.data.city.length - 1 && <span>, </span>}
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -111,10 +117,17 @@ const relatedCultures = allCultures
|
||||
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">文化信息</h3>
|
||||
|
||||
<div class="space-y-3">
|
||||
{entry.data.city && (
|
||||
{entry.data.city && entry.data.city.length > 0 && (
|
||||
<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 class="text-gray-900 dark:text-white">
|
||||
{entry.data.city.map((cityName, index) => (
|
||||
<>
|
||||
<span>{cityName}</span>
|
||||
{index < entry.data.city.length - 1 && <span>, </span>}
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,16 +6,10 @@ import MorphingText from "../components/aceternity/MorphingText.astro";
|
||||
---
|
||||
|
||||
<MainLayout title="首页 - 河北游礼">
|
||||
<!-- 主页文字特效区域 -->
|
||||
<!-- 主页文字特效区域 - 使用更简洁的背景设计 -->
|
||||
<section class="hero-section relative w-full h-screen flex items-center justify-center overflow-hidden">
|
||||
<!-- 背景效果 -->
|
||||
<div class="absolute inset-0 bg-gradient-to-br from-primary-50 via-white to-secondary-100 dark:from-dark-bg dark:via-dark-surface dark:to-dark-primary-100"></div>
|
||||
|
||||
<!-- 背景装饰 -->
|
||||
<div class="absolute inset-0 opacity-10 bg-grid-pattern"></div>
|
||||
|
||||
<!-- 径向渐变叠加 -->
|
||||
<div class="absolute inset-0 bg-radial-gradient opacity-80"></div>
|
||||
<!-- 单一背景层 - 合并多层背景效果 -->
|
||||
<div class="absolute inset-0 bg-hero-gradient"></div>
|
||||
|
||||
<!-- 文字特效容器 -->
|
||||
<div class="relative z-10 text-center px-4 w-full max-w-7xl mx-auto">
|
||||
@ -26,32 +20,28 @@ import MorphingText from "../components/aceternity/MorphingText.astro";
|
||||
textSize="text-8xl sm:text-9xl md:text-[10rem] lg:text-[12rem]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 页面指示器 -->
|
||||
<div class="absolute bottom-6 left-1/2 transform -translate-x-1/2 flex space-x-4">
|
||||
<a href="#highlights" class="text-primary-600 dark:text-primary-400 animate-bounce">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</MainLayout>
|
||||
|
||||
<style>
|
||||
/* 背景网格图案 */
|
||||
.bg-grid-pattern {
|
||||
/* 合并背景样式为单一更高效的背景 */
|
||||
.bg-hero-gradient {
|
||||
background: linear-gradient(to bottom right, var(--color-primary-50), white, var(--color-secondary-100));
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 增加网格图案作为背景装饰 */
|
||||
.bg-hero-gradient::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image:
|
||||
linear-gradient(to right, rgba(180, 83, 9, 0.05) 1px, transparent 1px),
|
||||
linear-gradient(to bottom, rgba(180, 83, 9, 0.05) 1px, transparent 1px);
|
||||
background-size: 40px 40px;
|
||||
}
|
||||
|
||||
/* 径向渐变 */
|
||||
.bg-radial-gradient {
|
||||
background: radial-gradient(circle at center, transparent 0%, var(--color-primary-50, rgba(255, 251, 235, 0.8)) 70%);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* 特殊样式来增强文字大小 */
|
||||
@ -61,36 +51,10 @@ import MorphingText from "../components/aceternity/MorphingText.astro";
|
||||
line-height: 1.1 !important;
|
||||
}
|
||||
|
||||
/* 深色模式适配 */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.bg-radial-gradient {
|
||||
background: radial-gradient(circle at center, rgba(69, 51, 25, 0.5) 0%, var(--color-dark-bg, rgba(26, 22, 19, 0.8)) 70%);
|
||||
.bg-hero-gradient {
|
||||
background: linear-gradient(to bottom right, var(--color-dark-primary-100), var(--color-dark-bg), var(--color-dark-primary-50));
|
||||
}
|
||||
}
|
||||
|
||||
/* 背景渐变动画 */
|
||||
@keyframes gradient-shift {
|
||||
0% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
100% { background-position: 0% 50%; }
|
||||
}
|
||||
|
||||
.hero-section::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(120deg,
|
||||
var(--color-primary-600, rgba(217, 119, 6, 0.05)),
|
||||
var(--color-secondary-600, rgba(182, 125, 73, 0.05)),
|
||||
var(--color-accent-600, rgba(175, 63, 63, 0.05)));
|
||||
background-size: 200% 200%;
|
||||
animation: gradient-shift 15s ease infinite;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
/* 波浪底部装饰 */
|
||||
.bg-wave-pattern {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 120' preserveAspectRatio='none'%3E%3Cpath d='M0,0V46.29c47.79,22.2,103.59,32.17,158,28,70.36-5.37,136.33-33.31,206.8-37.5C438.64,32.43,512.34,53.67,583,72.05c69.27,18,138.3,24.88,209.4,13.08,36.15-6,69.85-17.84,104.45-29.34C989.49,25,1113-14.29,1200,52.47V0Z' opacity='.25' fill='%23f59e0b'%3E%3C/path%3E%3Cpath d='M0,0V15.81C13,36.92,27.64,56.86,47.69,72.05,99.41,111.27,165,111,224.58,91.58c31.15-10.15,60.09-26.07,89.67-39.8,40.92-19,84.73-46,130.83-49.67,36.26-2.85,70.9,9.42,98.6,31.56,31.77,25.39,62.32,62,103.63,73,40.44,10.79,81.35-6.69,119.13-24.28s75.16-39,116.92-43.05c59.73-5.85,113.28,22.88,168.9,38.84,30.2,8.66,59,6.17,87.09-7.5,22.43-10.89,48-26.93,60.65-49.24V0Z' opacity='.5' fill='%23d97706'%3E%3C/path%3E%3Cpath d='M0,0V5.63C149.93,59,314.09,71.32,475.83,42.57c43-7.64,84.23-20.12,127.61-26.46,59-8.63,112.48,12.24,165.56,35.4C827.93,77.22,886,95.24,951.2,90c86.53-7,172.46-45.71,248.8-84.81V0Z' fill='%23b45309' opacity='.25'%3E%3C/path%3E%3C/svg%3E");
|
||||
background-size: cover;
|
||||
background-position: center top;
|
||||
}
|
||||
</style>
|
@ -14,6 +14,9 @@ function sortByDate<T extends { data: { pubDate?: Date | string, updatedDate?: D
|
||||
|
||||
const sortedTravels = [...travels].sort(sortByDate);
|
||||
|
||||
// 检查是否有旅行攻略内容
|
||||
const hasTravels = travels.length > 0;
|
||||
|
||||
// 提取所有标签并按数量排序
|
||||
const allTags: {name: string, count: number}[] = [];
|
||||
travels.forEach((travel) => {
|
||||
@ -59,13 +62,16 @@ const difficulties = Array.from(allDifficulties);
|
||||
// 提取所有城市
|
||||
const cities: {name: string, count: number}[] = [];
|
||||
travels.forEach((travel) => {
|
||||
if (travel.data.city) {
|
||||
const existingCity = cities.find(c => c.name === travel.data.city);
|
||||
if (existingCity) {
|
||||
existingCity.count++;
|
||||
} else {
|
||||
cities.push({ name: travel.data.city, count: 1 });
|
||||
}
|
||||
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 });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -170,7 +176,9 @@ const visibleTravels = sortedTravels.slice(
|
||||
<label class="block font-handwriting text-lg text-slate-700 dark:text-slate-300 mb-2">查找旅程</label>
|
||||
<div class="relative">
|
||||
<input
|
||||
id="search-input"
|
||||
type="text"
|
||||
name="search"
|
||||
placeholder="输入关键词..."
|
||||
class="w-full px-4 py-2 bg-theme-primary-bg dark:bg-slate-700/50 border-b-2 border-slate-300 dark:border-slate-600 font-handwriting text-slate-800 dark:text-slate-200 focus:outline-none focus:border-theme-primary dark:focus:border-theme-primary placeholder-slate-400"
|
||||
/>
|
||||
@ -180,6 +188,12 @@ const visibleTravels = sortedTravels.slice(
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
id="search-button"
|
||||
class="mt-2 w-full py-2 px-4 bg-primary-100 dark:bg-primary-900/30 text-primary-800 dark:text-primary-400 font-handwriting text-sm border border-primary-200 dark:border-primary-800/40 hover:bg-primary-200 dark:hover:bg-primary-800/40 transition-colors"
|
||||
>
|
||||
开始搜索
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 季节关联 -->
|
||||
@ -275,123 +289,163 @@ const visibleTravels = sortedTravels.slice(
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 无搜索结果提示 - 在客户端控制显示 -->
|
||||
<div id="no-results-message" class="hidden 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">
|
||||
<div class="absolute -top-3 right-5 w-12 h-12 bg-[url('/images/tape-piece.png')] bg-contain bg-no-repeat opacity-70"></div>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 mx-auto text-slate-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
|
||||
<h3 class="mt-4 text-xl font-handwriting text-slate-800 dark:text-slate-200">旅行笔记缺失</h3>
|
||||
<p id="search-term-message" class="mt-2 font-handwriting text-slate-600 dark:text-slate-400">
|
||||
抱歉,未找到相关旅行笔记。请尝试其他关键词或浏览所有旅行记录。
|
||||
</p>
|
||||
|
||||
<div class="mt-6">
|
||||
<a href="/travel" class="inline-flex items-center text-primary-700 dark:text-primary-500 font-handwriting hover:underline">
|
||||
查看所有旅行笔记
|
||||
<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>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 旅行笔记列表 -->
|
||||
<div class="space-y-10">
|
||||
{visibleTravels.map((travel, index) => (
|
||||
<ScrollReveal animation={index % 2 === 0 ? "slide-right" : "slide-left"}>
|
||||
<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`}>
|
||||
<!-- 装饰性元素 -->
|
||||
<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 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"
|
||||
>
|
||||
<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`}>
|
||||
<!-- 装饰性元素 -->
|
||||
<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>
|
||||
)}
|
||||
</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 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="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>
|
||||
|
||||
{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>
|
||||
)}
|
||||
<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.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>
|
||||
)}
|
||||
<p class="font-handwriting text-slate-600 dark:text-slate-400 leading-relaxed mb-4 line-clamp-3">
|
||||
{travel.data.description}
|
||||
</p>
|
||||
|
||||
{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 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>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</ScrollReveal>
|
||||
))}
|
||||
</a>
|
||||
</ScrollReveal>
|
||||
))
|
||||
) : (
|
||||
<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">
|
||||
<div class="absolute -top-3 right-5 w-12 h-12 bg-[url('/images/tape-piece.png')] bg-contain bg-no-repeat opacity-70"></div>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-16 w-16 mx-auto text-slate-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
|
||||
<h3 class="mt-4 text-xl font-handwriting text-slate-800 dark:text-slate-200">暂无旅行笔记</h3>
|
||||
<p class="mt-2 font-handwriting text-slate-600 dark:text-slate-400">
|
||||
目前还没有发布任何旅行笔记。请稍后再来查看,或探索网站的其他内容。
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<!-- 分页 - 手绘风格 -->
|
||||
<div class="mt-12 flex justify-center">
|
||||
<div class="inline-flex border border-slate-300 dark:border-slate-700 overflow-hidden bg-white dark:bg-slate-800">
|
||||
<button class="px-4 py-2 border-r border-slate-300 dark:border-slate-700 font-handwriting text-slate-700 dark:text-slate-300 hover:bg-primary-50 dark:hover:bg-slate-700">
|
||||
上一页
|
||||
</button>
|
||||
<button class="px-4 py-2 border-r border-slate-300 dark:border-slate-700 font-handwriting text-white bg-primary-600 dark:bg-primary-700">
|
||||
1
|
||||
</button>
|
||||
{totalPages > 1 && (
|
||||
{hasTravels && totalPages > 1 && (
|
||||
<div class="mt-12 flex justify-center">
|
||||
<div class="inline-flex border border-slate-300 dark:border-slate-700 overflow-hidden bg-white dark:bg-slate-800">
|
||||
<button class="px-4 py-2 border-r border-slate-300 dark:border-slate-700 font-handwriting text-slate-700 dark:text-slate-300 hover:bg-primary-50 dark:hover:bg-slate-700">
|
||||
2
|
||||
上一页
|
||||
</button>
|
||||
)}
|
||||
{totalPages > 2 && (
|
||||
<button class="px-4 py-2 border-r border-slate-300 dark:border-slate-700 font-handwriting text-slate-700 dark:text-slate-300 hover:bg-primary-50 dark:hover:bg-slate-700">
|
||||
3
|
||||
<button class="px-4 py-2 border-r border-slate-300 dark:border-slate-700 font-handwriting text-white bg-primary-600 dark:bg-primary-700">
|
||||
1
|
||||
</button>
|
||||
)}
|
||||
{totalPages > 1 && (
|
||||
<button class="px-4 py-2 font-handwriting text-slate-700 dark:text-slate-300 hover:bg-primary-50 dark:hover:bg-slate-700">
|
||||
下一页
|
||||
</button>
|
||||
)}
|
||||
{totalPages > 1 && (
|
||||
<button class="px-4 py-2 border-r border-slate-300 dark:border-slate-700 font-handwriting text-slate-700 dark:text-slate-300 hover:bg-primary-50 dark:hover:bg-slate-700">
|
||||
2
|
||||
</button>
|
||||
)}
|
||||
{totalPages > 2 && (
|
||||
<button class="px-4 py-2 border-r border-slate-300 dark:border-slate-700 font-handwriting text-slate-700 dark:text-slate-300 hover:bg-primary-50 dark:hover:bg-slate-700">
|
||||
3
|
||||
</button>
|
||||
)}
|
||||
{totalPages > 1 && (
|
||||
<button class="px-4 py-2 font-handwriting text-slate-700 dark:text-slate-300 hover:bg-primary-50 dark:hover:bg-slate-700">
|
||||
下一页
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<!-- 底部引言 - 旅行者的话 -->
|
||||
<div class="mt-16 text-center max-w-2xl mx-auto">
|
||||
@ -432,6 +486,343 @@ const visibleTravels = sortedTravels.slice(
|
||||
<script>
|
||||
// 客户端交互逻辑
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// 基础元素
|
||||
const searchInput = document.getElementById('search-input') as HTMLInputElement;
|
||||
const searchButton = document.getElementById('search-button');
|
||||
const testNoResultsBtn = document.getElementById('test-no-results-btn');
|
||||
const travelCards = document.querySelectorAll('.space-y-10 a');
|
||||
const noResultsMessage = document.getElementById('no-results-message');
|
||||
const searchTermMessage = document.getElementById('search-term-message');
|
||||
const travelList = document.getElementById('travel-list');
|
||||
|
||||
// 复选框元素
|
||||
const seasonCheckboxes = document.querySelectorAll('.grid.grid-cols-2.gap-2 input[type="checkbox"]');
|
||||
const typeCheckboxes = document.querySelectorAll('.space-y-2 input[type="checkbox"]');
|
||||
const cityCheckboxes = document.querySelectorAll('.mb-8:nth-of-type(4) input[type="checkbox"]');
|
||||
|
||||
// 标签元素
|
||||
const tagElements = document.querySelectorAll('.flex.flex-wrap.gap-2 span');
|
||||
|
||||
console.log('客户端: 搜索输入框存在:', !!searchInput);
|
||||
console.log('客户端: 找到旅行卡片数量:', travelCards.length);
|
||||
console.log('客户端: 无结果提示元素存在:', !!noResultsMessage);
|
||||
|
||||
// 客户端解析URL查询参数
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const searchParamFromUrl = urlParams.get('search');
|
||||
const seasonParam = urlParams.get('season');
|
||||
const typeParam = urlParams.get('type');
|
||||
const cityParam = urlParams.get('city');
|
||||
const tagParam = urlParams.get('tag');
|
||||
|
||||
console.log('客户端: URL中的搜索参数:', searchParamFromUrl);
|
||||
|
||||
// 客户端筛选函数
|
||||
function filterTravels() {
|
||||
// 获取当前搜索词
|
||||
const searchValue = searchInput?.value.trim().toLowerCase() || '';
|
||||
const selectedSeasons: string[] = [];
|
||||
const selectedTypes: string[] = [];
|
||||
const selectedCities: string[] = [];
|
||||
|
||||
// 获取选中的季节
|
||||
seasonCheckboxes.forEach((checkbox: Element) => {
|
||||
if ((checkbox as HTMLInputElement).checked) {
|
||||
const seasonText = checkbox.parentElement?.nextElementSibling?.textContent?.trim().toLowerCase() || '';
|
||||
if (seasonText) selectedSeasons.push(seasonText);
|
||||
}
|
||||
});
|
||||
|
||||
// 获取选中的旅行类型
|
||||
typeCheckboxes.forEach((checkbox: Element) => {
|
||||
if ((checkbox as HTMLInputElement).checked) {
|
||||
const typeText = checkbox.parentElement?.nextElementSibling?.textContent?.trim().toLowerCase() || '';
|
||||
if (typeText) selectedTypes.push(typeText);
|
||||
}
|
||||
});
|
||||
|
||||
// 获取选中的城市
|
||||
cityCheckboxes.forEach((checkbox: Element) => {
|
||||
if ((checkbox as HTMLInputElement).checked) {
|
||||
const cityText = checkbox.parentElement?.nextElementSibling?.textContent?.trim().toLowerCase() || '';
|
||||
if (cityText) {
|
||||
// 去除计数信息,仅保留城市名
|
||||
const cityName = cityText.split('(')[0].trim();
|
||||
selectedCities.push(cityName);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log('客户端: 正在筛选旅行卡片, 搜索词:', searchValue);
|
||||
console.log('客户端: 选中的季节:', selectedSeasons);
|
||||
console.log('客户端: 选中的旅行类型:', selectedTypes);
|
||||
console.log('客户端: 选中的城市:', selectedCities);
|
||||
|
||||
let matchCount = 0;
|
||||
|
||||
// 处理标签搜索 - 如果搜索词与URL中的tag参数匹配,就把它当作标签搜索
|
||||
const isTagSearch = tagParam && searchValue.toLowerCase() === tagParam.toLowerCase();
|
||||
|
||||
// 如果没有筛选条件,显示所有卡片
|
||||
if (!searchValue && selectedSeasons.length === 0 && selectedTypes.length === 0 && selectedCities.length === 0) {
|
||||
console.log('客户端: 没有筛选条件,显示所有旅行卡片');
|
||||
if (noResultsMessage) {
|
||||
noResultsMessage.classList.add('hidden');
|
||||
}
|
||||
if (travelList) {
|
||||
travelList.classList.remove('hidden');
|
||||
}
|
||||
|
||||
travelCards.forEach((card) => {
|
||||
card.classList.remove('hidden');
|
||||
});
|
||||
|
||||
return travelCards.length;
|
||||
}
|
||||
|
||||
// 遍历所有旅行卡片进行筛选
|
||||
travelCards.forEach((card) => {
|
||||
const cardTitle = card.querySelector('h3')?.textContent?.toLowerCase() || '';
|
||||
const cardDesc = card.querySelector('p.font-handwriting.text-slate-600')?.textContent?.toLowerCase() || '';
|
||||
const cardTags = card.querySelectorAll('span.px-2.py-0\\.5.text-xs');
|
||||
const cardInfo = card.querySelectorAll('.flex.flex-wrap.gap-4 .flex.items-center');
|
||||
|
||||
// 获取卡片的季节、类型和城市信息
|
||||
let cardSeason = '';
|
||||
let cardType = '';
|
||||
let cardCities: string[] = [];
|
||||
let tagsText = '';
|
||||
|
||||
cardInfo.forEach(info => {
|
||||
const infoText = info.textContent?.toLowerCase() || '';
|
||||
if (infoText.includes('难度')) {
|
||||
// 跳过难度信息
|
||||
} else if (infoText.includes('天')) {
|
||||
// 跳过天数信息
|
||||
} else if (cardSeason === '') {
|
||||
cardSeason = infoText;
|
||||
} else if (cardType === '') {
|
||||
cardType = infoText;
|
||||
}
|
||||
});
|
||||
|
||||
// 提取卡片标签文本
|
||||
cardTags.forEach(tag => {
|
||||
tagsText += (tag.textContent?.toLowerCase() || '') + ' ';
|
||||
});
|
||||
|
||||
// 寻找城市信息 - 从DOM中寻找城市标签
|
||||
// 首先尝试查找城市专用标签
|
||||
const cityElements = card.querySelectorAll('.city-tag, .location-tag');
|
||||
if (cityElements && cityElements.length > 0) {
|
||||
cityElements.forEach(cityElem => {
|
||||
const cityText = cityElem.textContent?.toLowerCase().trim() || '';
|
||||
if (cityText) {
|
||||
cardCities.push(cityText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 如果没有找到专用城市标签,尝试从cardInfo中提取
|
||||
if (cardCities.length === 0) {
|
||||
// 检查是否有标记了城市信息的元素
|
||||
const cityInfoElements = card.querySelectorAll('[data-city], .city-info');
|
||||
if (cityInfoElements && cityInfoElements.length > 0) {
|
||||
cityInfoElements.forEach(cityElem => {
|
||||
const cityText = cityElem.textContent?.toLowerCase().trim() || '';
|
||||
cardCities.push(cityText);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 如果依然没有找到,尝试从描述和标题中提取
|
||||
if (cardCities.length === 0) {
|
||||
// 检查标题和描述中是否包含已知城市
|
||||
selectedCities.forEach(city => {
|
||||
if (cardTitle.includes(city) || cardDesc.includes(city)) {
|
||||
cardCities.push(city);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 匹配条件
|
||||
const matchesSearch = !searchValue ||
|
||||
cardTitle.includes(searchValue) ||
|
||||
cardDesc.includes(searchValue) ||
|
||||
tagsText.includes(searchValue);
|
||||
|
||||
const matchesSeasons = selectedSeasons.length === 0 || selectedSeasons.some(season => cardSeason.includes(season));
|
||||
const matchesTypes = selectedTypes.length === 0 || selectedTypes.some(type => cardType.includes(type));
|
||||
|
||||
// 检查是否有任何选中的城市存在于卡片城市中
|
||||
// 如果没有找到城市标签,但存在城市筛选条件,尝试在标题和描述中寻找
|
||||
let matchesCities = selectedCities.length === 0;
|
||||
if (!matchesCities) {
|
||||
if (cardCities.length > 0) {
|
||||
// 如果找到了城市标签,检查是否匹配
|
||||
matchesCities = cardCities.some(cardCity =>
|
||||
selectedCities.some(selectedCity => cardCity.includes(selectedCity))
|
||||
);
|
||||
} else {
|
||||
// 如果没有找到城市标签,尝试在标题和描述中寻找
|
||||
matchesCities = selectedCities.some(city =>
|
||||
cardTitle.includes(city) || cardDesc.includes(city)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 所有条件都匹配才显示
|
||||
const isMatch = matchesSearch && matchesSeasons && matchesTypes && matchesCities;
|
||||
|
||||
if (isMatch) {
|
||||
matchCount++;
|
||||
card.classList.remove('hidden');
|
||||
} else {
|
||||
card.classList.add('hidden');
|
||||
}
|
||||
});
|
||||
|
||||
console.log('客户端: 筛选后匹配旅行卡片数:', matchCount);
|
||||
|
||||
// 更新无结果提示显示
|
||||
if (matchCount === 0) {
|
||||
console.log('客户端: 没有匹配结果,显示无结果提示');
|
||||
if (noResultsMessage) {
|
||||
noResultsMessage.classList.remove('hidden');
|
||||
|
||||
// 更新无结果消息中的搜索词
|
||||
if (searchTermMessage) {
|
||||
if (isTagSearch) {
|
||||
searchTermMessage.textContent = `抱歉,未找到标签为 "${searchValue}" 的旅行笔记。请尝试其他标签或浏览所有旅行记录。`;
|
||||
} else if (searchValue) {
|
||||
searchTermMessage.textContent = `抱歉,未找到与 "${searchValue}" 相关的旅行笔记。请尝试其他关键词或浏览所有旅行记录。`;
|
||||
} else if (selectedSeasons.length > 0 || selectedTypes.length > 0 || selectedCities.length > 0) {
|
||||
searchTermMessage.textContent = `抱歉,未找到符合当前筛选条件的旅行笔记。请尝试调整筛选条件或浏览所有旅行记录。`;
|
||||
} else {
|
||||
searchTermMessage.textContent = `抱歉,未找到相关旅行笔记。请尝试其他关键词或浏览所有旅行记录。`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏旅行列表
|
||||
if (travelList) {
|
||||
travelList.classList.add('hidden');
|
||||
}
|
||||
} else {
|
||||
// 隐藏无结果提示
|
||||
if (noResultsMessage) {
|
||||
noResultsMessage.classList.add('hidden');
|
||||
}
|
||||
// 显示旅行列表
|
||||
if (travelList) {
|
||||
travelList.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
return matchCount;
|
||||
}
|
||||
|
||||
// 初始化筛选状态
|
||||
if (searchInput && searchParamFromUrl) {
|
||||
console.log('客户端: 从URL设置搜索框值为:', searchParamFromUrl);
|
||||
searchInput.value = searchParamFromUrl;
|
||||
// 触发筛选
|
||||
setTimeout(filterTravels, 100);
|
||||
} else if (tagParam || seasonParam || typeParam || cityParam) {
|
||||
// 如果URL中包含标签或其他筛选参数,也执行筛选
|
||||
|
||||
// 如果有标签参数,先在搜索框中设置它,这样筛选函数可以找到它
|
||||
if (tagParam && searchInput) {
|
||||
searchInput.value = tagParam;
|
||||
}
|
||||
|
||||
// 如果有季节参数,选中对应的复选框
|
||||
if (seasonParam) {
|
||||
seasonCheckboxes.forEach((checkbox: Element) => {
|
||||
const seasonText = checkbox.parentElement?.nextElementSibling?.textContent?.trim().toLowerCase() || '';
|
||||
if (seasonText.toLowerCase() === seasonParam.toLowerCase()) {
|
||||
(checkbox as HTMLInputElement).checked = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 如果有类型参数,选中对应的复选框
|
||||
if (typeParam) {
|
||||
typeCheckboxes.forEach((checkbox: Element) => {
|
||||
const typeText = checkbox.parentElement?.nextElementSibling?.textContent?.trim().toLowerCase() || '';
|
||||
if (typeText.toLowerCase() === typeParam.toLowerCase()) {
|
||||
(checkbox as HTMLInputElement).checked = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 如果有城市参数,选中对应的复选框
|
||||
if (cityParam) {
|
||||
cityCheckboxes.forEach((checkbox: Element) => {
|
||||
const cityText = checkbox.parentElement?.nextElementSibling?.textContent?.trim().toLowerCase() || '';
|
||||
const cityName = cityText.split('(')[0].trim().toLowerCase();
|
||||
if (cityName === cityParam.toLowerCase()) {
|
||||
(checkbox as HTMLInputElement).checked = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 触发筛选
|
||||
setTimeout(filterTravels, 100);
|
||||
}
|
||||
|
||||
// 绑定搜索按钮点击事件
|
||||
if (searchButton) {
|
||||
searchButton.addEventListener('click', () => {
|
||||
const query = searchInput?.value.trim() || '';
|
||||
if (query) {
|
||||
window.location.href = `/travel?search=${encodeURIComponent(query)}`;
|
||||
} else {
|
||||
filterTravels();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 绑定搜索输入框回车事件
|
||||
if (searchInput) {
|
||||
searchInput.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
const query = searchInput.value.trim();
|
||||
if (query) {
|
||||
window.location.href = `/travel?search=${encodeURIComponent(query)}`;
|
||||
} else {
|
||||
filterTravels();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 测试按钮事件
|
||||
if (testNoResultsBtn) {
|
||||
testNoResultsBtn.addEventListener('click', () => {
|
||||
if (searchInput) {
|
||||
searchInput.value = 'xyzabcdefghijklmn123456789'; // 使用一个几乎不可能匹配的查询词
|
||||
filterTravels();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 为复选框添加事件监听
|
||||
const allCheckboxes = [...Array.from(seasonCheckboxes), ...Array.from(typeCheckboxes), ...Array.from(cityCheckboxes)];
|
||||
allCheckboxes.forEach((checkbox: Element) => {
|
||||
(checkbox as HTMLInputElement).addEventListener('change', filterTravels);
|
||||
});
|
||||
|
||||
// 为标签添加点击事件
|
||||
tagElements.forEach((tag) => {
|
||||
tag.addEventListener('click', () => {
|
||||
const tagText = tag.textContent?.trim().replace('#', '').trim() || '';
|
||||
if (tagText) {
|
||||
window.location.href = `/travel?tag=${encodeURIComponent(tagText)}`;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 选项卡切换
|
||||
const tabLinks = document.querySelectorAll('.container .whitespace-nowrap');
|
||||
|
||||
|
756
web/graduation/src/styles/content-styles.css
Normal file
756
web/graduation/src/styles/content-styles.css
Normal file
@ -0,0 +1,756 @@
|
||||
/* 增强表格样式 */
|
||||
.prose table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
width: 100%;
|
||||
margin: 1.5em 0;
|
||||
border-radius: 0.75rem;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
border: 2px solid var(--color-secondary-500);
|
||||
}
|
||||
|
||||
/* 确保表格边框在所有浏览器中都能正确显示 */
|
||||
.prose table * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.prose thead {
|
||||
background-color: var(--color-primary-50);
|
||||
}
|
||||
|
||||
.prose thead th {
|
||||
padding: 1rem 1.25rem;
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
color: var(--color-primary-900);
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.5rem;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
border-bottom: 2px solid var(--color-secondary-500);
|
||||
border-right: 2px solid var(--color-secondary-500);
|
||||
}
|
||||
|
||||
.prose thead th:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.prose tbody tr {
|
||||
border-bottom: 2px solid var(--color-secondary-500);
|
||||
}
|
||||
|
||||
.prose tbody tr:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.prose tbody tr:hover {
|
||||
background-color: var(--color-secondary-50);
|
||||
}
|
||||
|
||||
.prose tbody td {
|
||||
padding: 0.875rem 1.25rem;
|
||||
color: var(--color-secondary-800);
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.5rem;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
border-right: 2px solid var(--color-secondary-500);
|
||||
border-bottom: 2px solid var(--color-secondary-500);
|
||||
}
|
||||
|
||||
.prose tbody td:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.prose tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.prose tbody tr:nth-child(even) {
|
||||
background-color: var(--color-secondary-50/80);
|
||||
}
|
||||
|
||||
.prose tbody tr:nth-child(even):hover {
|
||||
background-color: var(--color-secondary-50);
|
||||
}
|
||||
|
||||
/* 表格内容对齐样式 */
|
||||
.prose th[align="center"],
|
||||
.prose td[align="center"] {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.prose th[align="right"],
|
||||
.prose td[align="right"] {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.prose th[align="left"],
|
||||
.prose td[align="left"] {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* 表格内容样式增强 */
|
||||
.prose td code {
|
||||
background-color: var(--color-secondary-100);
|
||||
padding: 0.2em 0.4em;
|
||||
border-radius: 0.25em;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose td code {
|
||||
background-color: var(--color-secondary-800);
|
||||
}
|
||||
|
||||
/* 表格内的链接样式 */
|
||||
.prose td a {
|
||||
color: var(--color-primary-600);
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid var(--color-primary-300);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.prose td a:hover {
|
||||
color: var(--color-primary-700);
|
||||
border-bottom-color: var(--color-primary-500);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose td a {
|
||||
color: var(--color-primary-400);
|
||||
border-bottom-color: var(--color-primary-700);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose td a:hover {
|
||||
color: var(--color-primary-300);
|
||||
border-bottom-color: var(--color-primary-500);
|
||||
}
|
||||
|
||||
/* 表格内复选框样式 */
|
||||
.prose td input[type="checkbox"] {
|
||||
width: 1.25em;
|
||||
height: 1.25em;
|
||||
margin: 0;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
accent-color: var(--color-primary-500);
|
||||
}
|
||||
|
||||
/* 表格内图标样式 */
|
||||
.prose td svg,
|
||||
.prose td img:not(.emoji) {
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
height: 1.25em;
|
||||
margin: 0 0.25em;
|
||||
}
|
||||
|
||||
/* 表格内的状态标记 */
|
||||
.prose td .status {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.25em 0.75em;
|
||||
border-radius: 9999px;
|
||||
font-size: 0.75em;
|
||||
font-weight: 500;
|
||||
line-height: 1.5;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.prose td .status-success {
|
||||
background-color: rgba(16, 185, 129, 0.1);
|
||||
color: rgb(6, 95, 70);
|
||||
}
|
||||
|
||||
.prose td .status-warning {
|
||||
background-color: rgba(245, 158, 11, 0.1);
|
||||
color: rgb(146, 64, 14);
|
||||
}
|
||||
|
||||
.prose td .status-error {
|
||||
background-color: rgba(239, 68, 68, 0.1);
|
||||
color: rgb(153, 27, 27);
|
||||
}
|
||||
|
||||
.prose td .status-info {
|
||||
background-color: rgba(59, 130, 246, 0.1);
|
||||
color: rgb(30, 64, 175);
|
||||
}
|
||||
|
||||
/* 增强列表样式 */
|
||||
.prose ul {
|
||||
list-style-type: disc;
|
||||
margin-top: 1.25em;
|
||||
margin-bottom: 1.25em;
|
||||
padding-left: 1.625em;
|
||||
}
|
||||
|
||||
.prose ul li {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
padding-left: 0.375em;
|
||||
}
|
||||
|
||||
.prose ul li::marker {
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.prose ul li ul {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.prose ol {
|
||||
list-style-type: decimal;
|
||||
margin-top: 1.25em;
|
||||
margin-bottom: 1.25em;
|
||||
padding-left: 1.625em;
|
||||
}
|
||||
|
||||
.prose ol li {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
padding-left: 0.375em;
|
||||
}
|
||||
|
||||
.prose ol li::marker {
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
/* 增强代码块样式 */
|
||||
.prose pre {
|
||||
margin: 1.5em 0;
|
||||
padding: 1em;
|
||||
border-radius: 0.375rem;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.prose :not(pre) > code {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
padding: 0.2em 0.4em;
|
||||
border-radius: 0.25em;
|
||||
font-weight: 400;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 移除 Tailwind Typography 添加的引号 */
|
||||
.prose code::before,
|
||||
.prose code::after {
|
||||
content: none !important;
|
||||
}
|
||||
|
||||
/* 表情符号样式 */
|
||||
.prose img.emoji {
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
margin: 0 0.05em 0 0.1em;
|
||||
vertical-align: -0.1em;
|
||||
display: inline-block;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* 标题样式 */
|
||||
.prose h1 {
|
||||
font-size: 2.25rem;
|
||||
font-weight: 700;
|
||||
margin-top: 2.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
color: var(--color-secondary-900);
|
||||
border-bottom: 1px solid var(--color-secondary-200);
|
||||
padding-bottom: 0.5rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.prose h1::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: -1px;
|
||||
left: 0;
|
||||
width: 100px;
|
||||
height: 3px;
|
||||
background: linear-gradient(to right, var(--color-primary-600), var(--color-primary-400));
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.prose h2 {
|
||||
font-size: 1.875rem;
|
||||
font-weight: 700;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1.25rem;
|
||||
color: var(--color-secondary-900);
|
||||
border-bottom: 1px solid var(--color-secondary-200);
|
||||
padding-bottom: 0.25rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.prose h2::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: -1px;
|
||||
left: 0;
|
||||
width: 75px;
|
||||
height: 2px;
|
||||
background: linear-gradient(to right, var(--color-primary-500), var(--color-primary-300));
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.prose h3 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
margin-top: 1.75rem;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--color-secondary-900);
|
||||
position: relative;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
.prose h3::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0.25em;
|
||||
height: 1em;
|
||||
width: 4px;
|
||||
background: linear-gradient(to bottom, var(--color-primary-500), var(--color-primary-300));
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.prose h4 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
color: var(--color-secondary-900);
|
||||
}
|
||||
|
||||
.prose h5 {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
margin-top: 1.25rem;
|
||||
margin-bottom: 0.75rem;
|
||||
color: var(--color-secondary-900);
|
||||
}
|
||||
|
||||
.prose h6 {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
margin-top: 1.25rem;
|
||||
margin-bottom: 0.75rem;
|
||||
color: var(--color-secondary-700);
|
||||
}
|
||||
|
||||
/* 标题锚点样式 */
|
||||
.prose h1 .anchor,
|
||||
.prose h2 .anchor,
|
||||
.prose h3 .anchor,
|
||||
.prose h4 .anchor,
|
||||
.prose h5 .anchor,
|
||||
.prose h6 .anchor {
|
||||
visibility: hidden;
|
||||
margin-left: 0.5rem;
|
||||
color: #a0aec0;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.prose h1:hover .anchor,
|
||||
.prose h2:hover .anchor,
|
||||
.prose h3:hover .anchor,
|
||||
.prose h4:hover .anchor,
|
||||
.prose h5:hover .anchor,
|
||||
.prose h6:hover .anchor {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* 暗色模式 */
|
||||
[data-theme="dark"] .prose {
|
||||
color: var(--color-secondary-300);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose h1,
|
||||
[data-theme="dark"] .prose h2,
|
||||
[data-theme="dark"] .prose h3,
|
||||
[data-theme="dark"] .prose h4,
|
||||
[data-theme="dark"] .prose h5 {
|
||||
color: var(--color-secondary-100);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose h6 {
|
||||
color: var(--color-secondary-300);
|
||||
}
|
||||
|
||||
/* 引用样式 */
|
||||
.prose blockquote {
|
||||
margin: 1.5em 0;
|
||||
padding: 1em 1.5em;
|
||||
border-left: 4px solid var(--color-primary-500);
|
||||
background-color: var(--color-gray-100);
|
||||
border-radius: 0.5rem;
|
||||
font-style: italic;
|
||||
color: var(--color-secondary-700);
|
||||
}
|
||||
|
||||
.prose blockquote p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.prose blockquote p + p {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
/* 链接样式 */
|
||||
.prose a {
|
||||
color: var(--color-primary-600);
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid var(--color-primary-300);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.prose a:hover {
|
||||
color: var(--color-primary-800);
|
||||
border-bottom-color: var(--color-primary-600);
|
||||
}
|
||||
|
||||
/* 暗色模式适配 */
|
||||
[data-theme="dark"] .prose blockquote {
|
||||
background-color: var(--color-dark-surface);
|
||||
border-left-color: var(--color-primary-400);
|
||||
color: var(--color-secondary-300);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose a {
|
||||
color: var(--color-primary-400);
|
||||
border-bottom-color: var(--color-primary-600);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose a:hover {
|
||||
color: var(--color-primary-300);
|
||||
border-bottom-color: var(--color-primary-400);
|
||||
}
|
||||
|
||||
/* 响应式表格样式 */
|
||||
@media (max-width: 640px) {
|
||||
.prose table {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.prose thead th {
|
||||
white-space: nowrap;
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
.prose tbody td {
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 表格内容溢出处理 */
|
||||
.prose td p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.prose td > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.prose td > *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.prose td.truncate {
|
||||
max-width: 20rem;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* 确保表格边框在所有情况下都能正确显示 */
|
||||
.prose table tr td:last-child {
|
||||
border-right: none !important;
|
||||
}
|
||||
|
||||
.prose table tr th:last-child {
|
||||
border-right: none !important;
|
||||
}
|
||||
|
||||
.prose table tr:last-child td {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
/* 暗色模式下的边框颜色 */
|
||||
[data-theme="dark"] .prose table {
|
||||
--table-border-color: var(--color-dark-border);
|
||||
}
|
||||
|
||||
/* 增强列表样式 */
|
||||
.prose ul {
|
||||
list-style-type: disc;
|
||||
margin-top: 1.25em;
|
||||
margin-bottom: 1.25em;
|
||||
padding-left: 1.625em;
|
||||
}
|
||||
|
||||
.prose ul li {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
padding-left: 0.375em;
|
||||
}
|
||||
|
||||
.prose ul li::marker {
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.prose ul li ul {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.prose ol {
|
||||
list-style-type: decimal;
|
||||
margin-top: 1.25em;
|
||||
margin-bottom: 1.25em;
|
||||
padding-left: 1.625em;
|
||||
}
|
||||
|
||||
.prose ol li {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
padding-left: 0.375em;
|
||||
}
|
||||
|
||||
.prose ol li::marker {
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
/* 添加明确的表格边框样式 */
|
||||
.prose table {
|
||||
border: 2px solid var(--color-secondary-500) !important;
|
||||
}
|
||||
|
||||
.prose th {
|
||||
border-right: 2px solid var(--color-secondary-500) !important;
|
||||
border-bottom: 2px solid var(--color-secondary-500) !important;
|
||||
}
|
||||
|
||||
.prose td {
|
||||
border-right: 2px solid var(--color-secondary-500) !important;
|
||||
border-bottom: 2px solid var(--color-secondary-500) !important;
|
||||
}
|
||||
|
||||
.prose th:last-child,
|
||||
.prose td:last-child {
|
||||
border-right: none !important;
|
||||
}
|
||||
|
||||
.prose tr:last-child td {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose th,
|
||||
[data-theme="dark"] .prose td {
|
||||
border-color: var(--color-dark-border) !important;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose table {
|
||||
border-color: var(--color-dark-border) !important;
|
||||
}
|
||||
|
||||
/* 暗色模式表格样式 */
|
||||
[data-theme="dark"] .prose table {
|
||||
border-color: var(--color-dark-border);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
|
||||
border-radius: 0.75rem;
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose thead {
|
||||
background-color: var(--color-dark-surface);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose thead th {
|
||||
color: var(--color-primary-300);
|
||||
border-bottom: 2px solid var(--color-dark-border);
|
||||
border-right: 2px solid var(--color-dark-border);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose thead th:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose tbody tr {
|
||||
border-bottom: 2px solid var(--color-dark-border);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose tbody tr:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose tbody td {
|
||||
color: var(--color-secondary-200);
|
||||
border-right: 2px solid var(--color-dark-border);
|
||||
border-bottom: 2px solid var(--color-dark-border);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose tbody td:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose tbody tr:hover {
|
||||
background-color: var(--color-dark-surface/60);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose tbody tr:nth-child(even) {
|
||||
background-color: var(--color-dark-surface/40);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose tbody tr:nth-child(even):hover {
|
||||
background-color: var(--color-dark-surface/60);
|
||||
}
|
||||
|
||||
/* 暗色模式下的状态标记样式 */
|
||||
[data-theme="dark"] .prose td .status-success {
|
||||
background-color: rgba(16, 185, 129, 0.2);
|
||||
color: rgb(110, 231, 183);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose td .status-warning {
|
||||
background-color: rgba(245, 158, 11, 0.2);
|
||||
color: rgb(253, 186, 116);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose td .status-error {
|
||||
background-color: rgba(239, 68, 68, 0.2);
|
||||
color: rgb(252, 165, 165);
|
||||
}
|
||||
|
||||
/* 收纳内容样式 */
|
||||
.details-content {
|
||||
margin-left: 1.5em;
|
||||
padding: 1em;
|
||||
background-color: var(--color-gray-100);
|
||||
border-left: 4px solid var(--color-primary-500);
|
||||
margin-bottom: 1em;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
[data-theme="dark"] .details-content {
|
||||
background-color: var(--color-dark-surface);
|
||||
border-left-color: var(--color-primary-400);
|
||||
}
|
||||
|
||||
/* 收纳标题样式 */
|
||||
.prose details {
|
||||
margin: 1.5em 0;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid var(--color-secondary-200);
|
||||
background-color: var(--color-gray-50);
|
||||
transition: all 0.2s ease;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.prose details summary {
|
||||
padding: 1em;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
font-weight: 500;
|
||||
color: var(--color-secondary-900);
|
||||
list-style: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75em;
|
||||
transition: all 0.2s ease;
|
||||
background: linear-gradient(to right, var(--color-primary-50), var(--color-gray-50));
|
||||
border-left: 4px solid var(--color-primary-100);
|
||||
}
|
||||
|
||||
.prose details summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.prose details summary::before {
|
||||
content: "";
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%234b6bff'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 5l7 7-7 7'%3E%3C/path%3E%3C/svg%3E");
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
transition: transform 0.3s ease;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.prose details[open] summary {
|
||||
border-left: 4px solid var(--color-primary-500);
|
||||
background: linear-gradient(to right, var(--color-primary-100), var(--color-gray-50));
|
||||
border-bottom: 1px solid var(--color-secondary-200);
|
||||
}
|
||||
|
||||
.prose details[open] summary::before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.prose details summary:hover {
|
||||
background: linear-gradient(to right, var(--color-primary-100), var(--color-gray-100));
|
||||
color: var(--color-primary-700);
|
||||
}
|
||||
|
||||
.prose details > blockquote {
|
||||
margin: 0;
|
||||
padding: 1.5em;
|
||||
border-radius: 0;
|
||||
border-left: 4px solid var(--color-primary-500);
|
||||
background: linear-gradient(to right, var(--color-primary-50/50), var(--color-gray-50));
|
||||
}
|
||||
|
||||
.prose details > blockquote p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.prose details > blockquote p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* 暗色模式适配 */
|
||||
[data-theme="dark"] .prose details {
|
||||
border-color: var(--color-dark-border);
|
||||
background-color: var(--color-dark-surface);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose details summary {
|
||||
color: var(--color-secondary-100);
|
||||
background: linear-gradient(to right, var(--color-dark-surface), var(--color-dark-card));
|
||||
border-left-color: var(--color-primary-800);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose details[open] summary {
|
||||
border-bottom-color: var(--color-dark-border);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose details summary::before {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%23839dff'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 5l7 7-7 7'%3E%3C/path%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose details[open] summary {
|
||||
background: linear-gradient(to right, var(--color-dark-card), var(--color-dark-surface));
|
||||
border-left-color: var(--color-primary-400);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose details summary:hover {
|
||||
background: linear-gradient(to right, var(--color-primary-900/30), var(--color-dark-card));
|
||||
color: var(--color-primary-400);
|
||||
}
|
||||
|
||||
[data-theme="dark"] .prose details > blockquote {
|
||||
background: linear-gradient(to right, var(--color-primary-900/10), var(--color-dark-surface));
|
||||
border-left-color: var(--color-primary-400);
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
@import "tailwindcss";
|
||||
@import "./content-styles.css";
|
||||
|
||||
/* 定义深色模式选择器 */
|
||||
@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
|
||||
@ -64,15 +65,17 @@
|
||||
--color-dark-text: #f1ece4;
|
||||
--color-dark-text-secondary: #c4b9aa;
|
||||
|
||||
/* 特殊主题背景 */
|
||||
--color-paper-light: #f8f5e8;
|
||||
--color-paper-dark: #2d2822;
|
||||
--color-recipe-light: #fdf7ed;
|
||||
--color-recipe-dark: #302a23;
|
||||
--color-scroll-light: #f5f1e6;
|
||||
--color-scroll-dark: #2b2720;
|
||||
--color-travel-light: #fef8e8;
|
||||
--color-travel-dark: #2e2921;
|
||||
/* 特殊主题背景 - 统一亮色和暗色变量 */
|
||||
--color-paper: #f8f5e8;
|
||||
--color-recipe: #fdf7ed;
|
||||
--color-scroll: #f5f1e6;
|
||||
--color-travel: #fef8e8;
|
||||
|
||||
/* 黑暗模式中的特殊主题背景 */
|
||||
--color-dark-paper: #2d2822;
|
||||
--color-dark-recipe: #302a23;
|
||||
--color-dark-scroll: #2b2720;
|
||||
--color-dark-travel: #2e2921;
|
||||
|
||||
/* 黑暗模式中的强调色 */
|
||||
--color-dark-primary-50: #362713;
|
||||
@ -102,11 +105,11 @@
|
||||
--theme-primary-bg: var(--color-primary-50);
|
||||
--theme-primary-bg-hover: var(--color-primary-100);
|
||||
|
||||
/* 页面特殊背景 */
|
||||
--bg-paper: var(--color-paper-light);
|
||||
--bg-recipe: var(--color-recipe-light);
|
||||
--bg-scroll: var(--color-scroll-light);
|
||||
--bg-travel: var(--color-travel-light);
|
||||
/* 页面特殊背景 - 使用统一的变量 */
|
||||
--bg-paper: var(--color-paper);
|
||||
--bg-recipe: var(--color-recipe);
|
||||
--bg-scroll: var(--color-scroll);
|
||||
--bg-travel: var(--color-travel);
|
||||
|
||||
background-color: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
@ -129,13 +132,101 @@
|
||||
--theme-primary-bg-hover: var(--color-dark-primary-200);
|
||||
|
||||
/* 页面特殊背景 */
|
||||
--bg-paper: var(--color-paper-dark);
|
||||
--bg-recipe: var(--color-recipe-dark);
|
||||
--bg-scroll: var(--color-scroll-dark);
|
||||
--bg-travel: var(--color-travel-dark);
|
||||
|
||||
background-color: var(--bg-primary);
|
||||
color: var(--text-primary);
|
||||
--bg-paper: var(--color-dark-paper);
|
||||
--bg-recipe: var(--color-dark-recipe);
|
||||
--bg-scroll: var(--color-dark-scroll);
|
||||
--bg-travel: var(--color-dark-travel);
|
||||
|
||||
/* 元素背景色覆盖 */
|
||||
.bg-white {
|
||||
background-color: var(--color-dark-card);
|
||||
}
|
||||
|
||||
/* 文本颜色覆盖 */
|
||||
.text-gray-900 {
|
||||
color: var(--color-dark-text);
|
||||
}
|
||||
|
||||
.text-gray-700,
|
||||
.text-gray-600 {
|
||||
color: var(--color-dark-text-secondary);
|
||||
}
|
||||
|
||||
/* 对卡片背景色的改进 */
|
||||
.ancient-card,
|
||||
.spotlight-card,
|
||||
.bg-gray-900\/95,
|
||||
[class*="bg-gray-900"] {
|
||||
background-color: var(--color-dark-card);
|
||||
}
|
||||
|
||||
/* 对话框和弹出层背景 */
|
||||
.bg-gray-800 {
|
||||
background-color: var(--color-dark-surface);
|
||||
}
|
||||
|
||||
/* 琥珀色/棕色兼容性覆盖 */
|
||||
.text-amber-300,
|
||||
.text-amber-400,
|
||||
.text-brown-300 {
|
||||
color: var(--color-dark-primary-600);
|
||||
}
|
||||
|
||||
.bg-amber-900,
|
||||
.bg-slate-900 {
|
||||
background-color: var(--color-dark-bg);
|
||||
}
|
||||
|
||||
/* 表单元素适配 */
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
background-color: var(--color-dark-card);
|
||||
border-color: var(--color-dark-border);
|
||||
color: var(--color-dark-text);
|
||||
}
|
||||
|
||||
/* 链接颜色调整 */
|
||||
a:not([class]) {
|
||||
color: var(--theme-primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--theme-primary-light);
|
||||
}
|
||||
}
|
||||
|
||||
/* 阴影调整 */
|
||||
.shadow-md,
|
||||
.shadow-lg {
|
||||
--tw-shadow-color: rgba(0, 0, 0, 0.4);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
/* 渐变背景调整 */
|
||||
.bg-gradient-to-r {
|
||||
background-image: linear-gradient(to right, var(--color-dark-primary-200), var(--color-dark-primary-300));
|
||||
}
|
||||
}
|
||||
|
||||
/* 亮色模式特定覆盖 */
|
||||
[data-theme='light'] {
|
||||
.text-amber-700,
|
||||
.text-amber-800,
|
||||
.text-brown-700 {
|
||||
color: var(--color-primary-700);
|
||||
}
|
||||
|
||||
.bg-amber-50,
|
||||
.bg-amber-100 {
|
||||
background-color: var(--color-primary-50);
|
||||
}
|
||||
}
|
||||
|
||||
/* 背景渐变动画 */
|
||||
@keyframes gradient-shift {
|
||||
0% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
100% { background-position: 0% 50%; }
|
||||
}
|
||||
|
||||
/* 统一颜色类 */
|
||||
@ -152,78 +243,7 @@
|
||||
.border-theme-primary-light { border-color: var(--theme-primary-light); }
|
||||
.border-theme-primary-dark { border-color: var(--theme-primary-dark); }
|
||||
|
||||
/* 主题特殊背景 */
|
||||
/* 主题特殊背景 - 使用统一命名并移除重复定义 */
|
||||
.bg-scroll-bg { background-color: var(--bg-scroll); }
|
||||
.bg-scroll-bg-dark { background-color: var(--bg-scroll); }
|
||||
.bg-recipe-paper-light { background-color: var(--bg-recipe); }
|
||||
.bg-recipe-paper-dark { background-color: var(--bg-recipe); }
|
||||
.bg-ancient-paper { background-color: var(--bg-paper); }
|
||||
.bg-ancient-paper-dark { background-color: var(--bg-paper); }
|
||||
|
||||
/* 黑暗模式下的卡片样式覆盖 */
|
||||
[data-theme='dark'] .bg-white {
|
||||
background-color: var(--color-dark-card);
|
||||
}
|
||||
|
||||
/* 黑暗模式下的文本颜色覆盖 */
|
||||
[data-theme='dark'] .text-gray-900 {
|
||||
color: var(--color-dark-text);
|
||||
}
|
||||
|
||||
[data-theme='dark'] .text-gray-700,
|
||||
[data-theme='dark'] .text-gray-600 {
|
||||
color: var(--color-dark-text-secondary);
|
||||
}
|
||||
|
||||
/* 兼容性覆盖:琥珀色/棕色 */
|
||||
[data-theme='light'] .text-amber-700,
|
||||
[data-theme='light'] .text-amber-800,
|
||||
[data-theme='light'] .text-brown-700 {
|
||||
color: var(--color-primary-700);
|
||||
}
|
||||
|
||||
[data-theme='dark'] .text-amber-300,
|
||||
[data-theme='dark'] .text-amber-400,
|
||||
[data-theme='dark'] .text-brown-300 {
|
||||
color: var(--color-dark-primary-600);
|
||||
}
|
||||
|
||||
[data-theme='light'] .bg-amber-50,
|
||||
[data-theme='light'] .bg-amber-100 {
|
||||
background-color: var(--color-primary-50);
|
||||
}
|
||||
|
||||
[data-theme='dark'] .bg-amber-900,
|
||||
[data-theme='dark'] .bg-slate-900 {
|
||||
background-color: var(--color-dark-bg);
|
||||
}
|
||||
|
||||
/* 表单元素在黑暗模式下的适配 */
|
||||
[data-theme='dark'] input,
|
||||
[data-theme='dark'] select,
|
||||
[data-theme='dark'] textarea {
|
||||
background-color: var(--color-dark-card);
|
||||
border-color: var(--color-dark-border);
|
||||
color: var(--color-dark-text);
|
||||
}
|
||||
|
||||
/* 文本和链接颜色在黑暗模式下的调整 */
|
||||
[data-theme='dark'] a:not([class]) {
|
||||
color: var(--theme-primary);
|
||||
}
|
||||
|
||||
[data-theme='dark'] a:not([class]):hover {
|
||||
color: var(--theme-primary-light);
|
||||
}
|
||||
|
||||
/* 黑暗模式下的阴影调整 */
|
||||
[data-theme='dark'] .shadow-md,
|
||||
[data-theme='dark'] .shadow-lg {
|
||||
--tw-shadow-color: rgba(0, 0, 0, 0.4);
|
||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||
}
|
||||
|
||||
/* 黑暗模式下的渐变背景调整 */
|
||||
[data-theme='dark'] .bg-gradient-to-r {
|
||||
background-image: linear-gradient(to right, var(--color-dark-primary-200), var(--color-dark-primary-300));
|
||||
}
|
||||
.bg-recipe-paper { background-color: var(--bg-recipe); }
|
||||
.bg-ancient-paper { background-color: var(--bg-paper); }
|
Loading…
Reference in New Issue
Block a user