diff --git a/web/graduation/src/components/DarkModeTransition.astro b/web/graduation/src/components/DarkModeTransition.astro index b0d5900..88293c6 100644 --- a/web/graduation/src/components/DarkModeTransition.astro +++ b/web/graduation/src/components/DarkModeTransition.astro @@ -15,7 +15,18 @@ body * { transition: background-color var(--transition-duration) ease, color var(--transition-duration) ease, - box-shadow var(--transition-duration) ease; + box-shadow var(--transition-duration) ease, + border-color var(--transition-duration) ease, + opacity var(--transition-duration) ease, + transform var(--transition-duration) ease, + filter var(--transition-duration) ease; + } + + /* 特别处理渐变背景过渡 */ + [class*="bg-gradient"] { + transition: background-image var(--transition-duration) ease, + background-color var(--transition-duration) ease, + opacity var(--transition-duration) ease; } /* 防止某些元素过渡 */ diff --git a/web/graduation/src/components/aceternity/AnimatedGallery.astro b/web/graduation/src/components/aceternity/AnimatedGallery.astro deleted file mode 100644 index 98ace07..0000000 --- a/web/graduation/src/components/aceternity/AnimatedGallery.astro +++ /dev/null @@ -1,109 +0,0 @@ ---- -interface Image { - src: string; - alt: string; - width?: number; - height?: number; -} - -interface Props { - images: Image[]; - className?: string; - gap?: number; - direction?: 'left' | 'right'; - speed?: 'slow' | 'normal' | 'fast'; -} - -const { - images, - className = "", - gap = 16, - direction = 'left', - speed = 'normal' -} = Astro.props; - -// 计算速度 -const getSpeed = () => { - switch(speed) { - case 'slow': return '60s'; - case 'fast': return '20s'; - default: return '40s'; - } -}; - -const speedValue = getSpeed(); ---- - - - - - - \ No newline at end of file diff --git a/web/graduation/src/components/aceternity/FlipCard.astro b/web/graduation/src/components/aceternity/FlipCard.astro deleted file mode 100644 index dcf9b62..0000000 --- a/web/graduation/src/components/aceternity/FlipCard.astro +++ /dev/null @@ -1,63 +0,0 @@ ---- -interface Props { - frontTitle?: string; - backTitle?: string; - className?: string; -} - -const { - frontTitle = "正面", - backTitle = "背面", - className = "" -} = Astro.props; ---- - -
-
-
-

{frontTitle}

-
- -
-
-
-

{backTitle}

-
- -
-
-
-
- - \ No newline at end of file diff --git a/web/graduation/src/components/aceternity/FloatingNavbar.astro b/web/graduation/src/components/aceternity/FloatingNavbar.astro deleted file mode 100644 index d9e6a91..0000000 --- a/web/graduation/src/components/aceternity/FloatingNavbar.astro +++ /dev/null @@ -1,54 +0,0 @@ ---- -interface Props { - links: Array<{ - label: string; - href: string; - isActive?: boolean; - }>; - className?: string; -} - -const { links, className = "" } = Astro.props; ---- - -
-
-
- -
-
- - \ No newline at end of file diff --git a/web/graduation/src/components/aceternity/GradientText.astro b/web/graduation/src/components/aceternity/GradientText.astro deleted file mode 100644 index 7fb5299..0000000 --- a/web/graduation/src/components/aceternity/GradientText.astro +++ /dev/null @@ -1,63 +0,0 @@ ---- -interface Props { - words: string[]; - baseText?: string; - className?: string; - duration?: number; // 每个词的显示时间(毫秒) -} - -const { - words, - baseText = "河北", - className = "", - duration = 2000 -} = Astro.props; - -const id = `gradient-text-${Math.random().toString(36).substring(2, 11)}`; ---- - -
-
- {baseText} -
- {words[0]} -
-
-
- - - - \ No newline at end of file diff --git a/web/graduation/src/components/aceternity/HoverGlow.astro b/web/graduation/src/components/aceternity/HoverGlow.astro deleted file mode 100644 index 17d4830..0000000 --- a/web/graduation/src/components/aceternity/HoverGlow.astro +++ /dev/null @@ -1,70 +0,0 @@ ---- -interface Props { - color?: string; - intensity?: 'subtle' | 'medium' | 'strong'; - className?: string; -} - -const { - color = "rgba(75, 107, 255, 0.5)", - intensity = 'medium', - className = "" -} = Astro.props; - -// 根据强度调整发光范围 -const getGlowSize = () => { - switch(intensity) { - case 'subtle': return '100px'; - case 'strong': return '180px'; - default: return '140px'; // medium - } -}; - -const glowSize = getGlowSize(); -const id = `hover-glow-${Math.random().toString(36).substring(2, 11)}`; ---- - -
-
- -
-
-
- - - - \ No newline at end of file diff --git a/web/graduation/src/components/aceternity/MagneticElement.astro b/web/graduation/src/components/aceternity/MagneticElement.astro deleted file mode 100644 index 3b33906..0000000 --- a/web/graduation/src/components/aceternity/MagneticElement.astro +++ /dev/null @@ -1,144 +0,0 @@ ---- -interface Props { - strength?: number; // 磁性强度,1-10之间 - className?: string; - radius?: number; // 影响半径(像素) - smoothing?: number; // 平滑程度 (0-1) -} - -const { - strength = 5, - className = "", - radius = 150, - smoothing = 0.15 -} = Astro.props; - -const magnetId = `magnetic-${Math.random().toString(36).substring(2, 11)}`; ---- - -
-
- -
-
- - - - \ No newline at end of file diff --git a/web/graduation/src/components/aceternity/NeonButton.astro b/web/graduation/src/components/aceternity/NeonButton.astro deleted file mode 100644 index 4160d92..0000000 --- a/web/graduation/src/components/aceternity/NeonButton.astro +++ /dev/null @@ -1,159 +0,0 @@ ---- -interface Props { - text?: string; - href?: string; - className?: string; - color?: string; - glowSize?: 'small' | 'medium' | 'large'; - glowIntensity?: 'low' | 'medium' | 'high'; - pulseAnimation?: boolean; -} - -const { - text = "霓虹按钮", - href, - className = "", - color = "rgb(101, 111, 247)", // 紫色 - glowSize = 'medium', - glowIntensity = 'medium', - pulseAnimation = true -} = Astro.props; - -// 计算发光尺寸 -const getGlowSizePx = (size: string) => { - switch (size) { - case 'small': return 10; - case 'large': return 30; - default: return 20; - } -}; - -// 计算发光强度值 -const getIntensityValue = (intensity: string) => { - switch (intensity) { - case 'low': return 0.6; - case 'high': return 1; - default: return 0.8; - } -}; - -const glowSizePx = getGlowSizePx(glowSize); -const intensityValue = getIntensityValue(glowIntensity); - -const buttonId = `neon-btn-${Math.random().toString(36).substring(2, 11)}`; ---- - -
- {href ? ( - - {text} - - ) : ( - - )} -
- - - - \ No newline at end of file diff --git a/web/graduation/src/components/aceternity/ParallaxCard.astro b/web/graduation/src/components/aceternity/ParallaxCard.astro deleted file mode 100644 index 9f0141d..0000000 --- a/web/graduation/src/components/aceternity/ParallaxCard.astro +++ /dev/null @@ -1,237 +0,0 @@ ---- -interface Props { - className?: string; - glareEnabled?: boolean; - maxGlare?: number; // 0-1 之间 - depth?: number; // 视差深度,1-10之间 - backgroundImage?: string; -} - -const { - className = "", - glareEnabled = true, - maxGlare = 0.5, - depth = 5, - backgroundImage -} = Astro.props; - -const cardId = `parallax-card-${Math.random().toString(36).substring(2, 11)}`; ---- - -
- {backgroundImage && ( -
- )} -
- -
- {glareEnabled &&
} -
- - - - \ No newline at end of file diff --git a/web/graduation/src/components/aceternity/ParallaxSection.astro b/web/graduation/src/components/aceternity/ParallaxSection.astro deleted file mode 100644 index c53b9ec..0000000 --- a/web/graduation/src/components/aceternity/ParallaxSection.astro +++ /dev/null @@ -1,91 +0,0 @@ ---- -interface Props { - images: Array<{ - src: string; - alt: string; - speed?: number; // 滚动速度因子,正数向下,负数向上 - }>; - heading: string; - subheading?: string; - className?: string; -} - -const { images, heading, subheading, className = "" } = Astro.props; ---- - -
- -
-
- { - images.map((image, index) => ( -
-
- {image.alt} -
-
- )) - } -
- - -
-
-

- {heading} -

- { - subheading && ( -

{subheading}

- ) - } - -
-
-
- - \ No newline at end of file diff --git a/web/graduation/src/components/aceternity/ParticleButton.astro b/web/graduation/src/components/aceternity/ParticleButton.astro deleted file mode 100644 index b101cea..0000000 --- a/web/graduation/src/components/aceternity/ParticleButton.astro +++ /dev/null @@ -1,129 +0,0 @@ ---- -interface Props { - text?: string; - href?: string; - className?: string; - color?: string; - particleCount?: number; -} - -const { - text = "点击我", - href, - className = "", - color = "#6366f1", - particleCount = 30 -} = Astro.props; - -const buttonId = `particle-btn-${Math.random().toString(36).substring(2, 11)}`; ---- - -
- {href ? ( - - {text} - - ) : ( - - )} -
-
- - - - \ No newline at end of file diff --git a/web/graduation/src/components/aceternity/ScrollReveal.astro b/web/graduation/src/components/aceternity/ScrollReveal.astro index d53350d..b5eb21c 100644 --- a/web/graduation/src/components/aceternity/ScrollReveal.astro +++ b/web/graduation/src/components/aceternity/ScrollReveal.astro @@ -59,6 +59,30 @@ const initialStyles = getInitialStyles(); document.addEventListener('DOMContentLoaded', () => { const revealElements = document.querySelectorAll('.scroll-reveal'); + // 检查是否为移动端设备 + const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); + + // 如果是移动端,直接显示所有元素,不使用动画 + if (isMobile) { + revealElements.forEach((element) => { + const el = element as HTMLElement; + el.style.opacity = '1'; + el.style.transform = 'none'; + }); + return; + } + + // 检查是否支持 IntersectionObserver + if (!('IntersectionObserver' in window)) { + // 如果不支持,也直接显示所有元素 + revealElements.forEach((element) => { + const el = element as HTMLElement; + el.style.opacity = '1'; + el.style.transform = 'none'; + }); + return; + } + const observerOptions = { root: null, // 使用视口作为根元素 rootMargin: '0px', @@ -116,6 +140,16 @@ const initialStyles = getInitialStyles(); }); }, observerOptions); + // 为每个元素添加超时保障,确保元素最终会显示 + revealElements.forEach((element) => { + const el = element as HTMLElement; + // 设置一个3秒的超时,确保即使IntersectionObserver失效,元素也会显示 + setTimeout(() => { + el.style.opacity = '1'; + el.style.transform = 'none'; + }, 3000); + }); + // 开始观察所有滚动显示元素 revealElements.forEach(element => { // 设置自定义阈值 diff --git a/web/graduation/src/components/aceternity/SpotlightCard.astro b/web/graduation/src/components/aceternity/SpotlightCard.astro deleted file mode 100644 index ea66342..0000000 --- a/web/graduation/src/components/aceternity/SpotlightCard.astro +++ /dev/null @@ -1,265 +0,0 @@ ---- -interface Props { - title: string; - description?: string; - image?: string; - link?: string; - className?: string; - color?: string; - spotlightSize?: 'small' | 'medium' | 'large'; - spotlightIntensity?: 'subtle' | 'medium' | 'strong'; -} - -const { - title, - description, - image, - link, - className = "", - color = "rgba(75, 107, 255, 0.3)", // 默认是蓝色光晕 - spotlightSize = 'medium', - spotlightIntensity = 'medium' -} = Astro.props; - -const id = `spotlight-card-${Math.random().toString(36).substring(2, 11)}`; - -// 计算光晕大小 -const sizeMap = { - small: '70%', - medium: '100%', - large: '130%' -}; - -// 计算光晕强度 -const intensityMap = { - subtle: '0.15', - medium: '0.25', - strong: '0.4' -}; - -const spotlightSizeValue = sizeMap[spotlightSize]; -const spotlightIntensityValue = intensityMap[spotlightIntensity]; ---- - -
-
-
-
- - {image && ( -
-
- {title} 图片 -
-
- )} - -

- {title} -

- - {description && ( -

- {description} -

- )} - - {link && ( - - 查看详情 → - - )} - - -
- - - - \ No newline at end of file diff --git a/web/graduation/src/components/common/CarouselCard.astro b/web/graduation/src/components/common/CarouselCard.astro deleted file mode 100644 index 9ccd3ee..0000000 --- a/web/graduation/src/components/common/CarouselCard.astro +++ /dev/null @@ -1,117 +0,0 @@ ---- -interface Props { - title: string; - description?: string; - image?: string; - imageAlt?: string; - link?: string; - linkText?: string; - tags?: string[]; - className?: string; -} - -const { - title, - description, - image, - imageAlt = "", - link, - linkText = "详细信息", - tags = [], - className = "" -} = Astro.props; ---- - -
- {image && ( -
-
- {imageAlt || title} -
-
-
- )} - -
-

{title}

- - {description && ( -

{description}

- )} - - {tags.length > 0 && ( -
- {tags.map(tag => ( - - {tag} - - ))} -
- )} - - - - {link && ( - - {linkText} → - - )} -
-
- - \ No newline at end of file diff --git a/web/graduation/src/components/common/ItemCard.astro b/web/graduation/src/components/common/ItemCard.astro deleted file mode 100644 index 713cbba..0000000 --- a/web/graduation/src/components/common/ItemCard.astro +++ /dev/null @@ -1,69 +0,0 @@ ---- -interface Props { - title: string; - description?: string; - image?: string; - imageAlt?: string; - link?: string; - linkText?: string; - tags?: string[]; - location?: string; - className?: string; -} - -const { - title, - description, - image, - imageAlt = "", - link, - linkText = "详细信息", - tags = [], - location, - className = "" -} = Astro.props; ---- - -
- {image && ( -
-
- {imageAlt || title} -
- {location && ( -
- {location} -
- )} -
- )} - -
-

{title}

- - {description && ( -

{description}

- )} - - {tags.length > 0 && ( -
- {tags.map(tag => ( - - {tag} - - ))} -
- )} - - - - {link && ( - - {linkText} → - - )} -
-
\ No newline at end of file diff --git a/web/graduation/src/components/common/PageHeader.astro b/web/graduation/src/components/common/PageHeader.astro index 9be8cfe..4c6f490 100644 --- a/web/graduation/src/components/common/PageHeader.astro +++ b/web/graduation/src/components/common/PageHeader.astro @@ -7,7 +7,7 @@ interface Props { const { title, subtitle } = Astro.props; --- -
+

{title}

diff --git a/web/graduation/src/components/common/SectionContainer.astro b/web/graduation/src/components/common/SectionContainer.astro deleted file mode 100644 index 248078f..0000000 --- a/web/graduation/src/components/common/SectionContainer.astro +++ /dev/null @@ -1,61 +0,0 @@ ---- -interface Props { - bgColor?: 'white' | 'gray' | 'primary' | 'none'; - padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl'; - maxWidth?: 'sm' | 'md' | 'lg' | 'xl' | 'full' | 'none'; - className?: string; -} - -const { - bgColor = 'white', - padding = 'lg', - maxWidth = 'lg', - className = "" -} = Astro.props; - -// 设置背景颜色 -const getBgColorClass = () => { - switch(bgColor) { - case 'white': return 'bg-white dark:bg-color-dark-bg'; - case 'gray': return 'bg-gray-100 dark:bg-color-dark-surface'; - case 'primary': return 'bg-color-primary-50 dark:bg-color-dark-primary-50'; - case 'none': return ''; - default: return 'bg-white dark:bg-color-dark-bg'; - } -}; - -// 设置内边距 -const getPaddingClass = () => { - switch(padding) { - case 'none': return ''; - case 'sm': return 'py-4 px-4'; - case 'md': return 'py-8 px-4 sm:px-6'; - case 'lg': return 'py-12 px-4 sm:px-6 lg:px-8'; - case 'xl': return 'py-16 px-4 sm:px-6 lg:px-8'; - default: return 'py-12 px-4 sm:px-6 lg:px-8'; - } -}; - -// 设置最大宽度 -const getMaxWidthClass = () => { - switch(maxWidth) { - case 'none': return ''; - case 'sm': return 'max-w-2xl mx-auto'; - case 'md': return 'max-w-4xl mx-auto'; - case 'lg': return 'max-w-7xl mx-auto'; - case 'xl': return 'max-w-screen-2xl mx-auto'; - case 'full': return 'w-full'; - default: return 'max-w-7xl mx-auto'; - } -}; - -const bgColorClass = getBgColorClass(); -const paddingClass = getPaddingClass(); -const maxWidthClass = getMaxWidthClass(); ---- - -
-
- -
-
\ No newline at end of file diff --git a/web/graduation/src/components/common/SectionHeading.astro b/web/graduation/src/components/common/SectionHeading.astro deleted file mode 100644 index 08c2c08..0000000 --- a/web/graduation/src/components/common/SectionHeading.astro +++ /dev/null @@ -1,39 +0,0 @@ ---- -interface Props { - title: string; - subtitle?: string; - alignment?: 'left' | 'center' | 'right'; - marginBottom?: string; - className?: string; -} - -const { - title, - subtitle, - alignment = 'center', - marginBottom = 'mb-8', - className = "" -} = Astro.props; - -// 设置对齐方式 -const getAlignmentClass = () => { - switch(alignment) { - case 'left': return 'text-left'; - case 'right': return 'text-right'; - case 'center': return 'text-center'; - default: return 'text-center'; - } -}; - -const alignmentClass = getAlignmentClass(); ---- - -
-

{title}

- {subtitle && ( -

- {subtitle} -

- )} - -
\ No newline at end of file diff --git a/web/graduation/src/components/common/SmoothCardCarousel.astro b/web/graduation/src/components/common/SmoothCardCarousel.astro deleted file mode 100644 index 066ace9..0000000 --- a/web/graduation/src/components/common/SmoothCardCarousel.astro +++ /dev/null @@ -1,331 +0,0 @@ ---- -interface Props { - autoplay?: boolean; - autoplaySpeed?: number; // 毫秒 - showArrows?: boolean; - showDots?: boolean; - cardGap?: number; // px - className?: string; -} - -const { - autoplay = true, - autoplaySpeed = 5000, - showArrows = true, - showDots = true, - cardGap = 16, - className = "" -} = Astro.props; - -const carouselId = `carousel-${Math.random().toString(36).substring(2, 11)}`; ---- - - - - - - \ No newline at end of file diff --git a/web/graduation/src/layouts/MainLayout.astro b/web/graduation/src/layouts/MainLayout.astro index b5ba99f..ab83ada 100644 --- a/web/graduation/src/layouts/MainLayout.astro +++ b/web/graduation/src/layouts/MainLayout.astro @@ -11,16 +11,11 @@ interface Props { const { title, description = "河北游礼宣传网站 - 探索河北的文化与魅力" } = Astro.props; -// 社交媒体数据 -const socialLinks = [ - { name: "微信", url: "#" }, - { name: "微博", url: "#" }, - { name: "抖音", url: "#" } -]; + --- - + @@ -29,94 +24,64 @@ const socialLinks = [ {title} + -
-
-
-
- - - - - - - -
- - - - -
+ +
+
+
+ + - - -
- + + + +
+
+ + +
- -
-
-
-
-

关于我们

-

河北游礼网站致力于宣传河北省的旅游资源、文化遗产和地方特色,为游客提供全面的河北旅游信息。

-
-
-

快速链接

- -
-
-

关注我们

-
- {socialLinks.map(({name, url}) => ( - - ))} -
-
-
-
-

© {new Date().getFullYear()} 河北游礼网站. 保留所有权利.

-
-
-
\ No newline at end of file diff --git a/web/graduation/src/pages/attractions/index.astro b/web/graduation/src/pages/attractions/index.astro index b9ffd31..8cf9c8d 100644 --- a/web/graduation/src/pages/attractions/index.astro +++ b/web/graduation/src/pages/attractions/index.astro @@ -64,20 +64,10 @@ sortedAttractions.forEach((attraction: CollectionEntry<"attractions">) => { // 按照城市出现次数排序 cities.sort((a, b) => b.count - a.count); -// 从URL获取查询参数 - 在静态站点中只用于预填充输入框 -const searchQuery = ''; // 对于静态生成的站点,我们在客户端处理搜索 -const tagQuery = ''; // 标签筛选参数 -const cityQuery = ''; // 城市筛选参数 - // 分页逻辑 const itemsPerPage = 9; const page = 1; // 对于静态生成的页面,我们默认显示第一页,客户端再处理分页 -// 搜索和筛选逻辑 - 在静态站点中,所有筛选都在客户端完成 -const selectedCategory = ''; -const selectedCity = ''; -const selectedTags: string[] = []; -const sortBy: 'date' | 'name' = 'date'; // 对于静态生成的页面,我们提供所有景点数据,客户端再进行筛选 let filteredAttractions = sortedAttractions; @@ -90,21 +80,16 @@ const getCategory = (attraction: CollectionEntry<"attractions">) => { return attraction.data.city && attraction.data.city.length > 0 ? attraction.data.city[0] : '其他景点'; }; -// 辅助函数,用于获取景点的城市(从city提取或默认值) -const getCity = (attraction: CollectionEntry<"attractions">) => { - return attraction.data.city && attraction.data.city.length > 0 ? - attraction.data.city[attraction.data.city.length - 1] : '其他地区'; -}; ---
-
+
-
+
@@ -151,7 +136,7 @@ const getCity = (attraction: CollectionEntry<"attractions">) => { -
+
@@ -180,11 +165,11 @@ const getCity = (attraction: CollectionEntry<"attractions">) => {
-
-
-
+
+
+

筛选

- - + - - + + + {categoryParam && } + {cityParam && } + {tagParam && } +
- +
@@ -206,7 +314,7 @@ const sortBy: 'date' | 'name' = 'date';
- +
@@ -218,14 +326,22 @@ const sortBy: 'date' | 'name' = 'date';
{categories.slice(0, 6).map((category) => ( - + ))}
- +

@@ -237,32 +353,22 @@ const sortBy: 'date' | 'name' = 'date';

{cities.slice(0, 6).map((city) => ( - + ))}
- - -
-

- - - - 历史朝代 -

-
- {periods.slice(0, 6).map((period) => ( -
- {period.name} - ({period.count}) -
- ))} -
-
- +

@@ -273,18 +379,26 @@ const sortBy: 'date' | 'name' = 'date';

{allTags.slice(0, 12).map((tag) => ( - + {tag.name} ({tag.count}) - + ))}
- +
-
@@ -303,14 +417,20 @@ const sortBy: 'date' | 'name' = 'date'; 典籍检索 - +
- + + {categoryParam && } + {cityParam && } + {tagParam && } +
- +

@@ -327,20 +447,30 @@ const sortBy: 'date' | 'name' = 'date'; 文化分类

- +
- +

@@ -350,42 +480,30 @@ const sortBy: 'date' | 'name' = 'date'; 地域分布

- + - - -
-

- - - - 历史朝代 -

- -
- {periods.map((period) => ( -
-
-
- {period.name} - ({period.count}) -
-
- ))} -
-
- +

@@ -394,46 +512,59 @@ const sortBy: 'date' | 'name' = 'date'; 特色标签

- +
- {allTags.map((tag) => ( - + {allTags.slice(0, 12).map((tag) => ( + {tag.name} - + ({tag.count}) + ))}
- +
{/* 内容分类标签部分 */}
- +
{currentPageCultures.map((culture, index) => ( -
-
+
tag.toLowerCase()))} + data-category={culture.data.category?.toLowerCase() || ''} + data-cities={JSON.stringify(culture.data.city?.map((city: string) => city.toLowerCase()) || [])} + > +
- +
{culture.data.title}
- + {index % 4 === 0 && (
)} - + {/* 文化类别标签 */} {culture.data.category && (
@@ -441,7 +572,7 @@ const sortBy: 'date' | 'name' = 'date';
)}
- +

@@ -453,14 +584,14 @@ const sortBy: 'date' | 'name' = 'date';

)}
- +

{culture.data.description}

- +
{culture.data.tags.slice(0, 3).map((tag: string) => ( - + {tag} ))} @@ -470,7 +601,7 @@ const sortBy: 'date' | 'name' = 'date'; )}
- + {/* 在卡片中添加城市信息显示 */}
{culture.data.city && culture.data.city.length > 0 && ( @@ -488,7 +619,7 @@ const sortBy: 'date' | 'name' = 'date';
)}
- +
查阅详情 @@ -501,7 +632,7 @@ const sortBy: 'date' | 'name' = 'date'; ))}
- +
- - + + {totalPages > 1 && (
- )} - +
- +
"文化是一个国家、一个民族的灵魂"
@@ -601,804 +750,27 @@ const sortBy: 'date' | 'name' = 'date'; // 同步黑暗模式与Tailwind的兼容代码 function syncDarkModeClasses() { const isDarkTheme = document.documentElement.getAttribute('data-theme') === 'dark'; - if (isDarkTheme) { document.documentElement.classList.add('dark'); } else { document.documentElement.classList.remove('dark'); } } - + // 初始同步一次 syncDarkModeClasses(); - + // 监听主题变更事件 window.addEventListener('theme-change', () => { syncDarkModeClasses(); }); - - // 初始化筛选和搜索功能 - const searchForm = document.getElementById('search-form') as HTMLFormElement; - const searchInput = document.querySelector('input[name="search"]') as HTMLInputElement; - const categoryItems = document.querySelectorAll('.font-ancient-body.max-h-48 .flex.items-center.group.cursor-pointer'); - const cultureCards = document.querySelectorAll('.ancient-card'); - const noResultsMessage = document.getElementById('no-results-message'); - const searchTermMessage = document.getElementById('search-term-message'); - const cultureGrid = document.querySelector('.grid.grid-cols-1.md\\:grid-cols-2.lg\\:grid-cols-3.gap-8'); - const tagItems = document.querySelectorAll('.tag-item'); - const resetFiltersBtn = document.getElementById('reset-filters-btn'); - const categoryTags = document.querySelectorAll('.category-tag'); - const cityTags = document.querySelectorAll('.city-tag'); - const periodTags = document.querySelectorAll('.period-tag'); - - // 客户端解析URL查询参数 - const urlParams = new URLSearchParams(window.location.search); - const searchParamFromUrl = urlParams.get('search') || ''; - const tagParam = urlParams.get('tag') || ''; - const categoryParam = urlParams.get('category') || ''; - const cityParam = urlParams.get('city') || ''; - const periodParam = urlParams.get('period') || ''; - const currentPage = Number(urlParams.get('page') || '1'); - - // 搜索和筛选状态变量 - let currentSearch = searchParamFromUrl; - let currentTag = tagParam; - let currentCategory = categoryParam; - let currentCity = cityParam; - let currentPeriod = periodParam; - - // 更新浏览器历史记录,不刷新页面 - function updateHistory() { - const params = new URLSearchParams(); - if (currentSearch) params.set('search', currentSearch); - if (currentTag) params.set('tag', currentTag); - if (currentCategory) params.set('category', currentCategory); - if (currentCity) params.set('city', currentCity); - if (currentPeriod) params.set('period', currentPeriod); - - const newUrl = `${window.location.pathname}${params.toString() ? '?' + params.toString() : ''}`; - window.history.pushState({ - search: currentSearch, - tag: currentTag, - category: currentCategory, - city: currentCity, - period: currentPeriod - }, '', newUrl); - } - - // 通用的选中项处理函数 - function handleItemSelection(items: NodeListOf, parentTitleMatch: string, paramValue: string | null, addClass: boolean) { - if (!paramValue) return; - - // 清理参数,移除可能的计数部分 "(数字)" - const cleanParam = paramValue.replace(/\s*\(\d+\)$/, '').toLowerCase(); - - items.forEach((item: Element) => { - const textElement = item.querySelector('.text-ancient-black, .dark\\:text-ancient-white span:first-child'); - if (!textElement) return; - - const itemText = textElement.textContent?.trim().toLowerCase() || ''; - // 获取父标题 - const parentSection = item.closest('.bg-ancient-paper-light, .dark\\:bg-ancient-paper-dark-light'); - const parentTitle = parentSection?.querySelector('h3')?.textContent?.trim() || ''; - - if (parentTitle.includes(parentTitleMatch) && itemText === cleanParam) { - // 选中此项 - const checkboxElement = item.querySelector('.w-4.h-4'); - if (checkboxElement && addClass) { - checkboxElement.classList.add('bg-ancient-accent/20', 'dark:bg-ancient-accent-dark/20'); - } - } - }); - } - - // 根据URL参数选中对应的筛选项 - handleItemSelection(categoryItems, '文化分类', categoryParam, true); - handleItemSelection(categoryItems, '地域分布', cityParam, true); - handleItemSelection(categoryItems, '历史朝代', periodParam, true); - - // 标签选择处理 - if (tagParam) { - // 选中对应的特色标签 - tagItems.forEach(tag => { - const tagValue = tag.getAttribute('data-tag-value')?.toLowerCase() || ''; - if (tagValue === tagParam.toLowerCase()) { - // 高亮选中的标签 - tag.classList.add('border-ancient-accent/70', 'dark:border-ancient-accent-dark/70'); - tag.classList.add('text-ancient-accent', 'dark:text-ancient-accent-dark'); - tag.classList.add('bg-ancient-accent/10', 'dark:bg-ancient-accent-dark/10'); - } - }); - } - - // 客户端筛选函数 - function filterCultures() { - // 获取当前搜索词 - const searchValue = currentSearch.toLowerCase(); - const filterTag = currentTag.toLowerCase(); - const filterCategory = currentCategory.toLowerCase(); - const filterCity = currentCity.toLowerCase(); - const filterPeriod = currentPeriod.toLowerCase(); - - let matchCount = 0; - - // 如果没有筛选条件,显示所有卡片 - if (!searchValue && !filterTag && !filterCategory && !filterCity && !filterPeriod) { - if (noResultsMessage) { - noResultsMessage.classList.add('hidden'); - } - if (cultureGrid) { - cultureGrid.classList.remove('hidden'); - } - - cultureCards.forEach((card) => { - const parentElement = card.parentElement; - if (parentElement && parentElement.parentElement) { - parentElement.parentElement.style.display = ''; - } - }); - - return cultureCards.length; - } - - // 遍历所有文化卡片进行筛选 - cultureCards.forEach((card) => { - const cardTitle = card.querySelector('.text-ancient-black\\/40, .dark\\:text-ancient-white\\/40')?.textContent?.toLowerCase() || ''; - const cardDesc = card.querySelector('p.text-ancient-black\\/80, .dark\\:text-ancient-white\\/80')?.textContent?.toLowerCase() || ''; - // 查找卡片中的所有标签元素 - const cardTagElements = card.querySelectorAll('.tag-item'); - const cardCategory = card.querySelector('.absolute.top-3.right-3.px-2.py-1')?.textContent?.toLowerCase() || ''; - - // 收集所有标签文本 - let tagsArray: string[] = []; - cardTagElements?.forEach(tagElement => { - const tagText = tagElement.textContent?.trim().toLowerCase() || ''; - if (tagText) { - tagsArray.push(tagText); - } - }); - - // 匹配搜索条件 - const matchesSearch = !searchValue || - cardTitle.includes(searchValue) || - cardDesc.includes(searchValue) || - tagsArray.some(tag => tag.includes(searchValue)); - - // 修改标签匹配逻辑,使用data-tag-value属性 - let matchesTag = !filterTag; - if (filterTag) { - // 在整个卡片中搜索标签,包括卡片上的和卡片中的 - const allTagElements = card.querySelectorAll('[data-tag-value]'); - if (allTagElements && allTagElements.length > 0) { - // 有标签元素,遍历检查是否匹配 - allTagElements.forEach(tagElem => { - const tagValue = tagElem.getAttribute('data-tag-value')?.toLowerCase() || ''; - if (tagValue === filterTag.toLowerCase()) { - matchesTag = true; - } - }); - } else { - // 如果没有标签元素,回退到文本搜索 - matchesTag = cardDesc.includes(filterTag) || cardTitle.includes(filterTag); - } - } - - // 对于分类筛选,使用data-category-value属性 - let matchesCategory = !filterCategory; - if (filterCategory) { - const categoryElements = card.querySelectorAll('[data-category-value]'); - if (categoryElements && categoryElements.length > 0) { - categoryElements.forEach(categoryElem => { - const categoryValue = categoryElem.getAttribute('data-category-value')?.toLowerCase() || ''; - if (categoryValue === filterCategory) { - matchesCategory = true; - } - }); - } else { - // 如果没有找到分类标签,从描述中搜索 - const cleanCardCategory = cardCategory.replace(/\s*\(\d+\)$/, ''); - matchesCategory = cleanCardCategory === filterCategory || - cardDesc.includes(filterCategory) || - cardTitle.includes(filterCategory); - } - } - - // 对于城市筛选,使用data-city-value属性 - let matchesCity = !filterCity; - if (filterCity) { - const cityElements = card.querySelectorAll('[data-city-value]'); - if (cityElements && cityElements.length > 0) { - cityElements.forEach(cityElem => { - const cityValue = cityElem.getAttribute('data-city-value')?.toLowerCase() || ''; - if (cityValue === filterCity.toLowerCase()) { - matchesCity = true; - } - }); - } else { - // 如果没有找到城市标签,从描述中搜索 - matchesCity = cardDesc.includes(filterCity); - } - } - - // 处理历史朝代筛选,使用data-period-value属性 - let matchesPeriod = !filterPeriod; - if (filterPeriod) { - const periodElements = card.querySelectorAll('[data-period-value]'); - if (periodElements && periodElements.length > 0) { - periodElements.forEach(periodElem => { - const periodValue = periodElem.getAttribute('data-period-value')?.toLowerCase() || ''; - if (periodValue === filterPeriod.toLowerCase()) { - matchesPeriod = true; - } - }); - } else { - // 如果没有找到朝代标签,从描述中搜索 - matchesPeriod = cardDesc.includes(filterPeriod); - } - } - - // 所有条件都匹配才显示 - const isMatch = matchesSearch && matchesTag && matchesCategory && matchesCity && matchesPeriod; - - const parentElement = card.parentElement; - if (parentElement && parentElement.parentElement) { - if (isMatch) { - matchCount++; - parentElement.parentElement.style.display = ''; - } else { - parentElement.parentElement.style.display = 'none'; - } - } - }); - - // 更新无结果提示显示 - if (matchCount === 0) { - if (noResultsMessage) { - noResultsMessage.classList.remove('hidden'); - - // 更新无结果消息中的搜索词 - if (searchTermMessage) { - if (currentSearch) { - searchTermMessage.textContent = `抱歉,未找到与 "${currentSearch}" 相关的文化内容。请尝试其他关键词或浏览所有内容。`; - } else if (currentTag) { - searchTermMessage.textContent = `抱歉,未找到标签为 "${currentTag}" 的文化内容。请尝试其他标签或浏览所有内容。`; - } else if (currentCategory) { - searchTermMessage.textContent = `抱歉,未找到分类为 "${currentCategory}" 的文化内容。请尝试其他分类或浏览所有内容。`; - } else if (currentCity) { - searchTermMessage.textContent = `抱歉,未找到地域为 "${currentCity}" 的文化内容。请尝试其他地域或浏览所有内容。`; - } else if (currentPeriod) { - searchTermMessage.textContent = `抱歉,未找到朝代为 "${currentPeriod}" 的文化内容。请尝试其他朝代或浏览所有内容。`; - } else { - searchTermMessage.textContent = `抱歉,未找到符合当前筛选条件的文化内容。请尝试调整筛选条件或浏览所有内容。`; - } - } - } - - // 隐藏文化网格 - if (cultureGrid) { - cultureGrid.classList.add('hidden'); - } - } else { - // 隐藏无结果提示 - if (noResultsMessage) { - noResultsMessage.classList.add('hidden'); - } - // 显示文化网格 - if (cultureGrid) { - cultureGrid.classList.remove('hidden'); - } - } - - return matchCount; - } - - // 如果URL中有搜索参数,设置到输入框中并执行筛选 - if (searchInput && searchParamFromUrl) { - searchInput.value = searchParamFromUrl; - // 触发筛选 - setTimeout(filterCultures, 100); - } else if (tagParam || categoryParam || cityParam || periodParam) { - // 有其他筛选参数时也执行筛选 - setTimeout(filterCultures, 100); - } - - // 为搜索输入框添加焦点样式 - if (searchInput) { - searchInput.addEventListener('focus', () => { - searchInput.classList.add('border-ancient-accent', 'dark:border-ancient-accent-dark'); - searchInput.classList.add('bg-ancient-paper-light/30', 'dark:bg-ancient-paper-dark-light/30'); - }); - - searchInput.addEventListener('blur', () => { - searchInput.classList.remove('border-ancient-accent', 'dark:border-ancient-accent-dark'); - searchInput.classList.remove('bg-ancient-paper-light/30', 'dark:bg-ancient-paper-dark-light/30'); - }); - } - - // 更新筛选状态UI,使用checkboxes更新勾选状态 - function updateFilterStatusUI() { - // 先清除所有选中状态 - categoryItems.forEach(item => { - const checkbox = item.querySelector('.w-4.h-4'); - if (checkbox) { - // 移除所有选中样式 - checkbox.classList.remove('checkbox-selected', 'bg-ancient-accent/20'); - checkbox.classList.add('checkbox-unselected', 'bg-transparent'); - - // 移除勾选标记 - const checkmark = checkbox.querySelector('.checkmark'); - if (checkmark) { - checkmark.remove(); - } - } - }); - - // 更新分类项样式 - categoryItems.forEach(item => { - const textElement = item.querySelector('.text-ancient-black, .dark\\:text-ancient-white span:first-child'); - if (!textElement) return; - - const itemText = textElement.textContent?.trim() || ''; - // 去除计数部分 - const cleanItemText = itemText.replace(/\s*\(\d+\)$/, ''); - - // 获取父容器标题确定此项是什么类型 - const parentSection = item.closest('.bg-ancient-paper-light, .dark\\:bg-ancient-paper-dark-light'); - const parentTitle = parentSection?.querySelector('h3')?.textContent?.trim() || ''; - - // 获取复选框 - const checkbox = item.querySelector('.w-4.h-4'); - if (!checkbox) return; - - // 根据分类类型和当前筛选条件设置复选框样式 - let isSelected = false; - - if (parentTitle.includes('文化分类') && cleanItemText.toLowerCase() === currentCategory.toLowerCase()) { - isSelected = true; - } else if (parentTitle.includes('地域分布') && cleanItemText.toLowerCase() === currentCity.toLowerCase()) { - isSelected = true; - } else if (parentTitle.includes('历史朝代') && cleanItemText.toLowerCase() === currentPeriod.toLowerCase()) { - isSelected = true; - } - - if (isSelected) { - // 添加样式类,确保复选框有正确的样式 - checkbox.classList.add('checkbox-container', 'checkbox-selected'); - checkbox.classList.remove('checkbox-unselected', 'bg-transparent'); - checkbox.classList.add('bg-ancient-accent/20'); - - // 创建勾选标记 - const checkmark = document.createElement('div'); - checkmark.className = 'checkmark checkmark-visible'; - checkmark.innerHTML = ''; - - // 添加勾选标记到复选框 - checkbox.appendChild(checkmark); - } - }); - - // 更新标签的UI状态 - if (currentTag) { - // 清除所有标签的选中样式 - tagItems.forEach(tag => { - tag.classList.remove('tag-selected'); - }); - - // 查找匹配当前标签的元素并添加选中样式 - tagItems.forEach(tag => { - const tagText = tag.textContent?.trim().replace(/\s*\(\d+\)$/, '') || ''; - if (tagText.toLowerCase() === currentTag.toLowerCase()) { - tag.classList.add('tag-selected'); - } - }); - } else { - // 当没有选中标签时,清除所有标签的选中样式 - tagItems.forEach(tag => { - tag.classList.remove('tag-selected'); - }); - } - - // 城市标签状态更新 - cityTags.forEach(city => { - const cityText = city.getAttribute('data-city-value') || city.textContent?.trim().replace(/\s*\(\d+\)$/, '') || ''; - - if (currentCity.toLowerCase() === cityText.toLowerCase()) { - city.classList.add('tag-selected'); - } else { - city.classList.remove('tag-selected'); - } - }); - - // 时期标签状态更新 - periodTags.forEach(period => { - const periodText = period.getAttribute('data-period-value') || period.textContent?.trim().replace(/\s*时期$/, '').replace(/\s*\(\d+\)$/, '') || ''; - - if (currentPeriod.toLowerCase() === periodText.toLowerCase()) { - period.classList.add('tag-selected', 'border-ancient-accent/90', 'bg-ancient-accent/20', 'shadow-md'); - } else { - period.classList.remove('tag-selected', 'border-ancient-accent/90', 'bg-ancient-accent/20', 'shadow-md'); - } - }); - - // 移除所有状态指示器 - document.querySelectorAll('.state-indicator').forEach(indicator => { - indicator.remove(); - }); - } - - // 为卡片中的分类标签添加点击事件 - categoryTags.forEach(category => { - category.addEventListener('click', (e) => { - e.preventDefault(); - e.stopPropagation(); - - // 优先使用data-category-value属性 - let categoryText = category.getAttribute('data-category-value') || category.textContent?.trim() || ''; - if (categoryText) { - // 去除可能的计数部分 - categoryText = categoryText.replace(/\s*\(\d+\)$/, ''); - - // 切换选中状态 - if (currentCategory.toLowerCase() === categoryText.toLowerCase()) { - currentCategory = ''; // 取消选择 - } else { - currentCategory = categoryText; // 选择新的分类 - } - // 重置其他筛选条件 - currentTag = ''; - currentCity = ''; - currentPeriod = ''; - - // 更新UI状态 - updateFilterStatusUI(); - - // 执行筛选并更新浏览器历史 - filterCultures(); - updateHistory(); - } - }); - }); - - // 为卡片中的城市标签添加点击事件 - cityTags.forEach(city => { - city.addEventListener('click', (e) => { - e.preventDefault(); - e.stopPropagation(); - - // 优先使用data-city-value属性 - let cityText = city.getAttribute('data-city-value') || city.textContent?.trim() || ''; - if (cityText) { - // 去除可能的计数部分 - cityText = cityText.replace(/\s*\(\d+\)$/, ''); - - // 清除所有其他城市标签的选中样式 - cityTags.forEach(otherCity => { - otherCity.classList.remove('tag-selected', 'border-ancient-accent/90', 'bg-ancient-accent/20', 'shadow-md'); - }); - - // 切换选中状态 - if (currentCity.toLowerCase() === cityText.toLowerCase()) { - currentCity = ''; // 取消选择 - } else { - currentCity = cityText; // 选择新的城市 - // 立即添加选中样式 - city.classList.add('tag-selected', 'border-ancient-accent/90', 'bg-ancient-accent/20', 'shadow-md'); - } - - // 重置其他筛选条件 - currentTag = ''; - currentCategory = ''; - currentPeriod = ''; - - // 更新UI状态 - updateFilterStatusUI(); - - // 执行筛选并更新浏览器历史 - filterCultures(); - updateHistory(); - } - }); - }); - - // 为卡片中的朝代标签添加点击事件 - periodTags.forEach(period => { - period.addEventListener('click', (e) => { - e.preventDefault(); - e.stopPropagation(); - - // 优先使用data-period-value属性 - let periodText = period.getAttribute('data-period-value') || period.textContent?.trim().replace(/\s*时期$/, '') || ''; - if (periodText) { - // 去除可能的计数部分 - periodText = periodText.replace(/\s*\(\d+\)$/, ''); - - // 清除所有其他时期标签的选中样式 - periodTags.forEach(otherPeriod => { - otherPeriod.classList.remove('tag-selected', 'border-ancient-accent/90', 'bg-ancient-accent/20', 'shadow-md'); - }); - - // 切换选中状态 - if (currentPeriod.toLowerCase() === periodText.toLowerCase()) { - currentPeriod = ''; // 取消选择 - } else { - currentPeriod = periodText; // 选择新的时期 - // 立即添加选中样式 - period.classList.add('tag-selected', 'border-ancient-accent/90', 'bg-ancient-accent/20', 'shadow-md'); - } - - // 重置其他筛选条件 - currentTag = ''; - currentCategory = ''; - currentCity = ''; - - // 更新UI状态 - updateFilterStatusUI(); - - // 执行筛选并更新浏览器历史 - filterCultures(); - updateHistory(); - } - }); - }); - - // 为特色标签添加点击事件 - tagItems.forEach((tag) => { - tag.addEventListener('click', (e) => { - // 对于卡片内的标签,需要阻止冒泡 - const isInCard = tag.closest('.ancient-card'); - if (isInCard) { - e.preventDefault(); - e.stopPropagation(); - } - - // 优先使用data-tag-value属性 - const tagValue = tag.getAttribute('data-tag-value') || tag.textContent?.trim() || ''; - if (tagValue) { - // 切换选中状态 - if (currentTag.toLowerCase() === tagValue.toLowerCase()) { - currentTag = ''; // 取消选择 - } else { - currentTag = tagValue; // 选择新的标签 - } - // 重置其他筛选条件 - currentCategory = ''; - currentCity = ''; - currentPeriod = ''; - - // 立即更新UI状态以确保视觉反馈 - updateFilterStatusUI(); - - // 执行筛选并更新浏览器历史 - filterCultures(); - updateHistory(); - } - }); - }); - - // 添加古籍翻页动画效果 - cultureCards.forEach((card, index) => { - // 设置初始状态 - (card as HTMLElement).style.opacity = '0'; - (card as HTMLElement).style.transform = 'translateY(20px) rotateY(5deg)'; - (card as HTMLElement).style.transition = 'all 0.5s ease-out'; - }); - - // 添加进场动画 - setTimeout(() => { - cultureCards.forEach((card, index) => { - setTimeout(() => { - (card as HTMLElement).style.opacity = '1'; - (card as HTMLElement).style.transform = 'translateY(0) rotateY(0)'; - }, 100 + (index * 80)); - }); - }, 300); - - // 分类项目点击处理 - categoryItems.forEach((item) => { - item.addEventListener('click', () => { - // 获取分类内容 - const textElement = item.querySelector('.text-ancient-black, .dark\\:text-ancient-white'); - if (!textElement) return; - - const itemText = textElement.textContent?.trim() || ''; - if (!itemText) return; - - // 去除数量计数部分 "(数字)" - const cleanItemText = itemText.replace(/\s*\(\d+\)$/, ''); - - // 确定此类别是哪种类型的筛选 - const parentSection = item.closest('.bg-ancient-paper-light, .dark\\:bg-ancient-paper-dark-light'); - const parentTitle = parentSection?.querySelector('h3')?.textContent?.trim() || ''; - - // 获取复选框元素 - const checkbox = item.querySelector('.w-4.h-4'); - if (!checkbox) return; - - // 设置当前筛选状态 - let isSelected = false; - - if (parentTitle.includes('文化分类')) { - // 检查是否已经选中,如果是则取消选择 - if (currentCategory.toLowerCase() === cleanItemText.toLowerCase()) { - currentCategory = ''; - } else { - currentCategory = cleanItemText; - isSelected = true; - // 重置其他值 - currentCity = ''; - currentPeriod = ''; - currentTag = ''; - } - } else if (parentTitle.includes('地域分布')) { - // 检查是否已经选中,如果是则取消选择 - if (currentCity.toLowerCase() === cleanItemText.toLowerCase()) { - currentCity = ''; - } else { - currentCity = cleanItemText; - isSelected = true; - // 重置其他值 - currentCategory = ''; - currentPeriod = ''; - currentTag = ''; - } - } else if (parentTitle.includes('历史朝代')) { - // 检查是否已经选中,如果是则取消选择 - if (currentPeriod.toLowerCase() === cleanItemText.toLowerCase()) { - currentPeriod = ''; - } else { - currentPeriod = cleanItemText; - isSelected = true; - // 重置其他值 - currentCategory = ''; - currentCity = ''; - currentTag = ''; - } - } - - // 立即为当前项设置样式(为了立即反馈效果) - if (isSelected) { - // 添加样式类,确保复选框有正确的样式 - checkbox.classList.add('checkbox-container', 'checkbox-selected'); - checkbox.classList.remove('checkbox-unselected', 'bg-transparent'); - checkbox.classList.add('bg-ancient-accent/20'); - - // 查找或创建勾选标记 - let checkmark = checkbox.querySelector('.checkmark'); - if (!checkmark) { - checkmark = document.createElement('div'); - checkmark.className = 'checkmark'; - checkmark.innerHTML = ''; - checkbox.appendChild(checkmark); - } - - checkmark.classList.add('checkmark-visible'); - } else { - // 移除选中样式 - checkbox.classList.remove('checkbox-selected', 'checkbox-container', 'bg-ancient-accent/20'); - checkbox.classList.add('checkbox-unselected', 'bg-transparent'); - - // 移除勾选标记 - const checkmark = checkbox.querySelector('.checkmark'); - if (checkmark) { - checkmark.classList.remove('checkmark-visible'); - } - } - - // 清除其他同类型项目的选中状态 - categoryItems.forEach(otherItem => { - if (otherItem !== item) { - const otherTextElement = otherItem.querySelector('.text-ancient-black, .dark\\:text-ancient-white'); - if (!otherTextElement) return; - - const otherParentSection = otherItem.closest('.bg-ancient-paper-light, .dark\\:bg-ancient-paper-dark-light'); - const otherParentTitle = otherParentSection?.querySelector('h3')?.textContent?.trim() || ''; - - // 只清除同类别的其他项目 - const isSameType = - (parentTitle.includes('文化分类') && otherParentTitle.includes('文化分类')) || - (parentTitle.includes('地域分布') && otherParentTitle.includes('地域分布')) || - (parentTitle.includes('历史朝代') && otherParentTitle.includes('历史朝代')); - - if (isSameType) { - const otherCheckbox = otherItem.querySelector('.w-4.h-4'); - if (otherCheckbox) { - otherCheckbox.classList.remove('checkbox-selected', 'checkbox-container', 'bg-ancient-accent/20'); - otherCheckbox.classList.add('checkbox-unselected'); - - // 移除勾选标记 - const otherCheckmark = otherCheckbox.querySelector('.checkmark'); - if (otherCheckmark) { - otherCheckmark.remove(); - } - } - } - } - }); - - // 完全更新UI - setTimeout(() => { - updateFilterStatusUI(); - filterCultures(); - updateHistory(); - }, 10); - }); - }); - - // 根据URL参数选中对应的筛选项 - function initializeCheckboxesFromUrl() { - // 设置当前筛选条件变量 - currentSearch = searchParamFromUrl || ''; - currentTag = tagParam || ''; - currentCategory = categoryParam || ''; - currentCity = cityParam || ''; - currentPeriod = periodParam || ''; - - // 通过初始调用updateFilterStatusUI来设置勾选框状态 - updateFilterStatusUI(); - } - - // 在页面加载时初始化 - setTimeout(initializeCheckboxesFromUrl, 100); - - // 页面加载时,如果有URL参数,执行对应的筛选 - if (searchInput && searchParamFromUrl) { - searchInput.value = searchParamFromUrl; - // 触发筛选 - setTimeout(filterCultures, 200); - } else if (tagParam || categoryParam || cityParam || periodParam) { - // 有其他筛选参数时也执行筛选 - setTimeout(filterCultures, 200); - } - // 页面加载后自动运行初始化 - document.addEventListener('DOMContentLoaded', () => { - // 移除所有已存在的状态指示器 - document.querySelectorAll('.state-indicator').forEach(indicator => { - indicator.remove(); - }); - - // 延迟一小段时间确保DOM已完全加载 - setTimeout(() => { - try { - // 已经在上面调用了初始化函数,不需要再调用initFromUrlParams - - // 添加古籍翻页动画效果 - cultureCards.forEach((card, index) => { - // 设置初始状态 - (card as HTMLElement).style.opacity = '0'; - (card as HTMLElement).style.transform = 'translateY(20px) rotateY(5deg)'; - (card as HTMLElement).style.transition = 'all 0.5s ease-out'; - }); - - // 添加进场动画 - setTimeout(() => { - cultureCards.forEach((card, index) => { - setTimeout(() => { - (card as HTMLElement).style.opacity = '1'; - (card as HTMLElement).style.transform = 'translateY(0) rotateY(0)'; - }, 100 + (index * 80)); - }); - }, 300); - } catch (error) { - console.error('初始化过程中发生错误:', error); - } - }, 100); - }); - - // 移动端筛选元素 - const searchFormMobile = document.getElementById('search-form-mobile'); - const searchInputMobile = document.querySelector('#search-form-mobile input[name="search"]') as HTMLInputElement; + // 移动端筛选抽屉 const mobileFilterToggle = document.getElementById('mobile-filter-toggle'); const mobileFilterDrawer = document.getElementById('mobile-filter-drawer'); const mobileFilterBackdrop = document.getElementById('mobile-filter-backdrop'); const mobileFilterClose = document.getElementById('mobile-filter-close'); - const mobileFilterApply = document.getElementById('mobile-filter-apply'); - const mobileCategoryItems = document.querySelectorAll('.mobile-category-item'); - const mobileCityItems = document.querySelectorAll('.mobile-city-item'); - const mobilePeriodItems = document.querySelectorAll('.mobile-period-item'); - const mobileTagItems = document.querySelectorAll('.mobile-tag-item'); - - // 移动端抽屉控制函数 + // 打开移动端筛选抽屉 if (mobileFilterToggle && mobileFilterDrawer) { mobileFilterToggle.addEventListener('click', () => { @@ -1406,254 +778,339 @@ const sortBy: 'date' | 'name' = 'date'; document.body.classList.add('overflow-hidden'); // 防止背景滚动 }); } - - // 关闭移动端筛选抽屉 + + // 关闭抽屉函数 const closeFilterDrawer = () => { if (mobileFilterDrawer) { mobileFilterDrawer.classList.add('translate-x-full'); document.body.classList.remove('overflow-hidden'); } }; - + // 点击背景关闭抽屉 if (mobileFilterBackdrop) { mobileFilterBackdrop.addEventListener('click', closeFilterDrawer); } - + // 点击关闭按钮关闭抽屉 if (mobileFilterClose) { mobileFilterClose.addEventListener('click', closeFilterDrawer); } + + // 获取所有筛选链接 + const filterLinks = document.querySelectorAll('a[href*="?category"], a[href*="?city"], a[href*="?taste"], a[href*="?tag"], a[href*="?ingredient"]'); - // 点击应用按钮关闭抽屉并应用筛选 - if (mobileFilterApply) { - mobileFilterApply.addEventListener('click', () => { - closeFilterDrawer(); - // 筛选逻辑已经在点击各筛选项时处理 + // 为每个筛选链接添加点击事件监听器 + filterLinks.forEach(link => { + link.addEventListener('click', (e) => { + e.preventDefault(); // 阻止默认行为 + + const href = (link as HTMLAnchorElement).href; + const url = new URL(href); + + // 获取当前的筛选参数 + const params = new URLSearchParams(window.location.search); + const clickedParam = Array.from(url.searchParams.entries())[0]; + + if (clickedParam) { + const [paramName, paramValue] = clickedParam; + + // 如果当前参数值与点击的值相同,则移除该参数 + if (params.get(paramName) === paramValue) { + params.delete(paramName); + } else { + // 否则设置新的参数值 + params.set(paramName, paramValue); + } + + // 更新 URL,但不刷新页面 + const newUrl = `${window.location.pathname}${params.toString() ? '?' + params.toString() : ''}`; + window.history.pushState({}, '', newUrl); + + // 应用筛选 + applyFilters(); + } }); - } - - // 同步桌面端和移动端的搜索内容 - const syncSearchInputs = (from: HTMLInputElement, to: HTMLInputElement) => { - if (from && to) { - to.value = from.value; + }); + + // 应用筛选函数 + function applyFilters() { + const params = new URLSearchParams(window.location.search); + const category = params.get('category')?.toLowerCase(); + const city = params.get('city')?.toLowerCase(); + const tag = params.get('tag')?.toLowerCase(); + const search = params.get('search')?.toLowerCase(); + + // 获取所有文化卡片 + const cards = document.querySelectorAll('.ancient-card'); + let visibleCount = 0; + + cards.forEach(card => { + let shouldShow = true; + + // 检查分类 + if (category && shouldShow) { + const cardCategory = card.getAttribute('data-category'); + if (cardCategory !== category) { + shouldShow = false; + } + } + + // 检查城市 + if (city && shouldShow) { + try { + const cardCities = JSON.parse(card.getAttribute('data-cities') || '[]'); + if (!cardCities.includes(city)) { + shouldShow = false; + } + } catch (e) { + shouldShow = false; + } + } + + // 检查标签 + if (tag && shouldShow) { + try { + const cardTags = JSON.parse(card.getAttribute('data-tags') || '[]'); + if (!cardTags.includes(tag)) { + shouldShow = false; + } + } catch (e) { + shouldShow = false; + } + } + + // 检查搜索关键词 + if (search && shouldShow) { + const title = card.querySelector('h3')?.textContent?.toLowerCase() || ''; + const description = card.querySelector('p.line-clamp-2')?.textContent?.toLowerCase() || ''; + const tags = JSON.parse(card.getAttribute('data-tags') || '[]').join(' ').toLowerCase(); + const cities = JSON.parse(card.getAttribute('data-cities') || '[]').join(' ').toLowerCase(); + + if (!title.includes(search) && + !description.includes(search) && + !tags.includes(search) && + !cities.includes(search)) { + shouldShow = false; + } + } + + // 更新卡片显示状态 + const cardContainer = card.closest('a')?.parentElement; + if (cardContainer) { + if (shouldShow) { + cardContainer.style.display = ''; + visibleCount++; + } else { + cardContainer.style.display = 'none'; + } + } + }); + + // 更新 UI 显示 + updateFilterUI(); + + // 处理无结果情况 + const noResultsMessage = document.getElementById('no-results-message'); + const searchTermMessage = document.getElementById('search-term-message'); + const gridContainer = document.querySelector('.grid.grid-cols-1.md\\:grid-cols-2.lg\\:grid-cols-3') as HTMLElement; + + if (visibleCount === 0) { + if (gridContainer) gridContainer.style.display = 'none'; + if (noResultsMessage) { + noResultsMessage.style.display = 'block'; + if (searchTermMessage) { + let message = '抱歉,未找到相关文化内容。'; + if (search) { + message += `没有找到包含"${search}"的内容。`; + } + if (category) { + message += `没有找到分类为"${category}"的内容。`; + } + if (city) { + message += `没有找到位于"${city}"的内容。`; + } + if (tag) { + message += `没有找到标签为"${tag}"的内容。`; + } + searchTermMessage.textContent = message; + } + } + } else { + if (gridContainer) gridContainer.style.display = 'grid'; + if (noResultsMessage) noResultsMessage.style.display = 'none'; } - }; - - // 添加移动端搜索表单处理 - if (searchFormMobile && searchInputMobile) { - searchFormMobile.addEventListener('submit', (e) => { + } + + // 更新筛选 UI + function updateFilterUI() { + const params = new URLSearchParams(window.location.search); + const currentCategory = params.get('category'); + const currentCity = params.get('city'); + const currentTag = params.get('tag'); + const currentSearch = params.get('search'); + + // 更新分类选中状态 + document.querySelectorAll('a[href*="?category"]').forEach(link => { + try { + const url = new URL((link as HTMLAnchorElement).href); + const linkCategory = url.searchParams.get('category'); + + // 检查是否选中 + const isSelected = currentCategory === linkCategory; + + // 处理带复选框的分类项(桌面端左侧栏) + const checkbox = link.querySelector('div.w-4.h-4'); + if (checkbox) { + if (isSelected) { + checkbox.className = 'w-4 h-4 border border-ancient-accent/50 dark:border-ancient-accent-dark/50 mr-2 flex-shrink-0 w-full h-full bg-ancient-accent/60 dark:bg-ancient-accent-dark/60'; + // 同时更新父元素背景 + link.classList.add('bg-ancient-accent/10', 'dark:bg-ancient-accent-dark/10'); + } else { + checkbox.className = 'w-4 h-4 border border-ancient-accent/50 dark:border-ancient-accent-dark/50 mr-2 flex-shrink-0 group-hover:bg-ancient-accent/20 dark:group-hover:bg-ancient-accent-dark/20 transition-colors'; + link.classList.remove('bg-ancient-accent/10', 'dark:bg-ancient-accent-dark/10'); + } + } + // 处理移动端分类标签样式(移动端筛选抽屉) + else if (link.classList.contains('px-3')) { + if (isSelected) { + link.classList.add('border-ancient-accent', 'dark:border-ancient-accent-dark', 'text-ancient-accent', 'dark:text-ancient-accent-dark', 'font-medium', 'bg-ancient-accent/10', 'dark:bg-ancient-accent-dark/10'); + link.classList.remove('border-ancient-accent/30', 'dark:border-ancient-accent-dark/30'); + } else { + link.classList.remove('border-ancient-accent', 'dark:border-ancient-accent-dark', 'text-ancient-accent', 'dark:text-ancient-accent-dark', 'font-medium', 'bg-ancient-accent/10', 'dark:bg-ancient-accent-dark/10'); + link.classList.add('border-ancient-accent/30', 'dark:border-ancient-accent-dark/30'); + } + } + } catch (e) { + console.error('Error updating category UI:', e); + } + }); + + // 更新城市选中状态 + document.querySelectorAll('a[href*="?city"]').forEach(link => { + try { + const url = new URL((link as HTMLAnchorElement).href); + const linkCity = url.searchParams.get('city'); + + // 检查是否选中 + const isSelected = currentCity === linkCity; + + // 处理带复选框的城市项(桌面端左侧栏) + const checkbox = link.querySelector('div.w-4.h-4'); + if (checkbox) { + if (isSelected) { + checkbox.className = 'w-4 h-4 border border-amber-300/50 dark:border-amber-700/50 mr-2 flex-shrink-0 w-full h-full bg-amber-400/60 dark:bg-amber-600/60'; + // 同时更新父元素背景 + link.classList.add('bg-amber-100/50', 'dark:bg-amber-800/20'); + } else { + checkbox.className = 'w-4 h-4 border border-amber-300/50 dark:border-amber-700/50 mr-2 flex-shrink-0 group-hover:bg-amber-200/40 dark:group-hover:bg-amber-700/30 transition-colors'; + link.classList.remove('bg-amber-100/50', 'dark:bg-amber-800/20'); + } + } + // 处理移动端城市标签样式(移动端筛选抽屉) + else if (link.classList.contains('px-3')) { + if (isSelected) { + link.classList.add('bg-amber-100', 'dark:bg-amber-800/50', 'border-amber-300', 'dark:border-amber-600', 'text-amber-800', 'dark:text-amber-200', 'font-medium', 'shadow-sm'); + link.classList.remove('bg-amber-100/50', 'dark:bg-amber-800/30', 'border-amber-200/50', 'dark:border-amber-700/30'); + } else { + link.classList.remove('bg-amber-100', 'dark:bg-amber-800/50', 'border-amber-300', 'dark:border-amber-600', 'text-amber-800', 'dark:text-amber-200', 'font-medium', 'shadow-sm'); + link.classList.add('bg-amber-100/50', 'dark:bg-amber-800/30', 'border-amber-200/50', 'dark:border-amber-700/30'); + } + } + } catch (e) { + console.error('Error updating city UI:', e); + } + }); + + // 更新标签选中状态 + document.querySelectorAll('a[href*="?tag"]').forEach(link => { + try { + const url = new URL((link as HTMLAnchorElement).href); + const linkTag = url.searchParams.get('tag'); + + // 检查是否选中 + const isSelected = currentTag === linkTag; + + // 标签可能有多种不同的样式结构,需要针对不同结构进行处理 + // 处理带有类名px-3的标签(桌面端和移动端通用标签样式) + if (link.classList.contains('px-3')) { + if (isSelected) { + link.classList.add('border-ancient-accent', 'dark:border-ancient-accent-dark', 'text-ancient-accent', 'dark:text-ancient-accent-dark', 'font-medium', 'bg-ancient-accent/10', 'dark:bg-ancient-accent-dark/10', 'shadow-sm'); + link.classList.remove('border-ancient-accent/30', 'dark:border-ancient-accent-dark/30'); + } else { + link.classList.remove('border-ancient-accent', 'dark:border-ancient-accent-dark', 'text-ancient-accent', 'dark:text-ancient-accent-dark', 'font-medium', 'bg-ancient-accent/10', 'dark:bg-ancient-accent-dark/10', 'shadow-sm'); + link.classList.add('border-ancient-accent/30', 'dark:border-ancient-accent-dark/30'); + } + } + } catch (e) { + console.error('Error updating tag UI:', e); + } + }); + + // 高亮显示当前筛选条件摘要(顶部筛选状态栏) + if (currentCategory || currentCity || currentTag || currentSearch) { + const filterSummary = document.querySelector('.flex.flex-wrap.gap-2.items-center'); + if (filterSummary) { + filterSummary.classList.add('animate-pulse-once'); + setTimeout(() => { + filterSummary.classList.remove('animate-pulse-once'); + }, 500); + } + } + } + + // 初始化:如果 URL 中有筛选参数,应用筛选 + if (window.location.search) { + applyFilters(); + } + + // 处理搜索表单提交 + const searchForm = document.getElementById('search-form'); + const searchFormMobile = document.getElementById('search-form-mobile'); + + function handleSearch(e: Event) { e.preventDefault(); - const query = searchInputMobile.value.trim(); - if (query) { - currentSearch = query; - // 同步到桌面端搜索框 - if (searchInput) searchInput.value = query; - - // 重置其他筛选条件 - currentTag = ''; - currentCategory = ''; - currentCity = ''; - currentPeriod = ''; - - // 执行筛选并更新UI - updateFilterStatusUI(); - filterCultures(); - updateHistory(); - - // 如果筛选抽屉是打开的,则关闭它 - closeFilterDrawer(); - } + const form = e.target as HTMLFormElement; + const searchInput = form.querySelector('input[name="search"]') as HTMLInputElement; + + // 获取当前的筛选参数 + const params = new URLSearchParams(window.location.search); + + // 更新或删除搜索参数 + if (searchInput.value.trim()) { + params.set('search', searchInput.value.trim()); + } else { + params.delete('search'); + } + + // 更新 URL,但不刷新页面 + const newUrl = `${window.location.pathname}${params.toString() ? '?' + params.toString() : ''}`; + window.history.pushState({}, '', newUrl); + + // 应用筛选 + applyFilters(); + } + + // 为搜索表单添加提交事件监听器 + if (searchForm) { + searchForm.addEventListener('submit', handleSearch); + } + if (searchFormMobile) { + searchFormMobile.addEventListener('submit', handleSearch); + } + + // 重置筛选按钮 + const resetFiltersBtn = document.getElementById('reset-filters-btn'); + if (resetFiltersBtn) { + resetFiltersBtn.addEventListener('click', () => { + window.location.href = '/culture'; }); } - - // 为移动端分类项添加点击事件 - mobileCategoryItems.forEach(item => { - item.addEventListener('click', () => { - const categoryValue = item.getAttribute('data-category-value') || ''; - - // 切换选中状态 - if (currentCategory === categoryValue) { - currentCategory = ''; // 取消选择 - item.classList.remove('mobile-selected'); - } else { - // 先清除其他选中状态 - mobileCategoryItems.forEach(otherItem => { - otherItem.classList.remove('mobile-selected'); - }); - - currentCategory = categoryValue; // 选择新的分类 - item.classList.add('mobile-selected'); - } - - // 重置其他筛选条件 - currentTag = ''; - currentCity = ''; - currentPeriod = ''; - - // 不立即更新,等待用户点击应用按钮 - }); - }); - - // 为移动端城市项添加点击事件 - mobileCityItems.forEach(item => { - item.addEventListener('click', () => { - const cityValue = item.getAttribute('data-city-value') || ''; - - // 切换选中状态 - if (currentCity === cityValue) { - currentCity = ''; // 取消选择 - item.classList.remove('mobile-selected'); - } else { - // 先清除其他选中状态 - mobileCityItems.forEach(otherItem => { - otherItem.classList.remove('mobile-selected'); - }); - - currentCity = cityValue; // 选择新的城市 - item.classList.add('mobile-selected'); - } - - // 重置其他筛选条件 - currentTag = ''; - currentCategory = ''; - currentPeriod = ''; - - // 不立即更新,等待用户点击应用按钮 - }); - }); - - // 为移动端朝代项添加点击事件 - mobilePeriodItems.forEach(item => { - item.addEventListener('click', () => { - const periodValue = item.getAttribute('data-period-value') || ''; - - // 切换选中状态 - if (currentPeriod === periodValue) { - currentPeriod = ''; // 取消选择 - item.classList.remove('mobile-selected'); - } else { - // 先清除其他选中状态 - mobilePeriodItems.forEach(otherItem => { - otherItem.classList.remove('mobile-selected'); - }); - - currentPeriod = periodValue; // 选择新的朝代 - item.classList.add('mobile-selected'); - } - - // 重置其他筛选条件 - currentTag = ''; - currentCategory = ''; - currentCity = ''; - - // 不立即更新,等待用户点击应用按钮 - }); - }); - - // 为移动端标签项添加点击事件 - mobileTagItems.forEach(item => { - item.addEventListener('click', () => { - const tagValue = item.getAttribute('data-tag-value') || ''; - - // 切换选中状态 - if (currentTag === tagValue) { - currentTag = ''; // 取消选择 - item.classList.remove('mobile-selected'); - } else { - // 先清除其他选中状态 - mobileTagItems.forEach(otherItem => { - otherItem.classList.remove('mobile-selected'); - }); - - currentTag = tagValue; // 选择新的标签 - item.classList.add('mobile-selected'); - } - - // 重置其他筛选条件 - currentCategory = ''; - currentCity = ''; - currentPeriod = ''; - - // 不立即更新,等待用户点击应用按钮 - }); - }); - - // 应用按钮点击事件,统一更新UI和执行筛选 - if (mobileFilterApply) { - mobileFilterApply.addEventListener('click', () => { - // 更新UI状态 - updateFilterStatusUI(); - // 执行筛选 - filterCultures(); - // 更新浏览器历史 - updateHistory(); - // 关闭抽屉 - closeFilterDrawer(); - }); - } - - // 文档加载完成后,同步初始化桌面端和移动端的选中状态 - document.addEventListener('DOMContentLoaded', () => { - // 初始化搜索框 - if (searchInput && searchParamFromUrl) { - (searchInput as HTMLInputElement).value = searchParamFromUrl; - } - if (searchInputMobile && searchParamFromUrl) { - searchInputMobile.value = searchParamFromUrl; - } - - // 更新移动端分类项状态 - if (currentCategory) { - mobileCategoryItems.forEach(item => { - const value = item.getAttribute('data-category-value') || ''; - if (value === currentCategory) { - item.classList.add('mobile-selected'); - } - }); - } - - // 更新移动端城市项状态 - if (currentCity) { - mobileCityItems.forEach(item => { - const value = item.getAttribute('data-city-value') || ''; - if (value === currentCity) { - item.classList.add('mobile-selected'); - } - }); - } - - // 更新移动端朝代项状态 - if (currentPeriod) { - mobilePeriodItems.forEach(item => { - const value = item.getAttribute('data-period-value') || ''; - if (value === currentPeriod) { - item.classList.add('mobile-selected'); - } - }); - } - - // 更新移动端标签项状态 - if (currentTag) { - mobileTagItems.forEach(item => { - const value = item.getAttribute('data-tag-value') || ''; - if (value === currentTag) { - item.classList.add('mobile-selected'); - } - }); - } - - // 执行初始筛选 - if (searchParamFromUrl || tagParam || categoryParam || cityParam || periodParam) { - // 触发筛选 - setTimeout(filterCultures, 100); - } - }); }); diff --git a/web/graduation/src/pages/hover-effects-new.astro b/web/graduation/src/pages/hover-effects-new.astro deleted file mode 100644 index 91d5a7a..0000000 --- a/web/graduation/src/pages/hover-effects-new.astro +++ /dev/null @@ -1,227 +0,0 @@ ---- -import MainLayout from "../layouts/MainLayout.astro"; -import FlipCard from "../components/aceternity/FlipCard.astro"; -import ParticleButton from "../components/aceternity/ParticleButton.astro"; -import MagneticElement from "../components/aceternity/MagneticElement.astro"; -import ParallaxCard from "../components/aceternity/ParallaxCard.astro"; -import NeonButton from "../components/aceternity/NeonButton.astro"; -import SpotlightCard from "../components/aceternity/SpotlightCard.astro"; -import HoverGlow from "../components/aceternity/HoverGlow.astro"; -import ScrollReveal from "../components/aceternity/ScrollReveal.astro"; ---- - - -
-
-
-

酷炫交互效果展示

-

探索我们网站上使用的各种交互和悬停效果

-
- - -
- - -
-

3D翻转卡片

-
- -
- 长城 -

中国最具代表性的文化象征

-
-
-

河北拥有全国最长的长城线,包括八达岭、金山岭等著名景点。

- 了解更多 -
-
- - -
- 蔚县剪纸 -

传统民间艺术

-
-
-

蔚县剪纸以其独特的造型和鲜明的色彩闻名,展现了浓郁的民俗风情。

- 了解更多 -
-
- - -
- 保定莲花酥 -

清代宫廷点心

-
-
-

酥脆可口,形如莲花,是保定地区传统的伴手礼。

- 了解更多 -
-
-
-
- - -
-

粒子特效按钮

-
- - - - - -
-
- - -
-

磁性吸附效果

-
- -
- 弱吸附效果 -
-
- - -
- 中吸附效果 -
-
- - -
- 强吸附效果 -
-
-
-
- - -
-

3D视差卡片

-
- -

承德避暑山庄

-

中国清代皇家园林,世界文化遗产

- 了解更多 -
- - -

秦皇岛海滨

-

碧海蓝天,金色沙滩

- 了解更多 -
-
-
- - -
-

霓虹灯按钮

-
- - - - - -
-
- - -
-

聚光灯卡片

-
- -
-
- 旅游景点类型: - 历史文化 - 古建筑 - 名城古镇 -
-
- 了解更多 → -
-
-
- - -
-

悬停发光效果

-
- -
-

内画鼻烟壶

-

河北衡水传统工艺品,在小小的鼻烟壶内壁上绘制精美图案。

-
-
- - -
-

曲阳石雕

-

历史悠久的传统工艺,技艺精湛,形态逼真。

-
-
- - -
-

景泰蓝

-

一种金属胎掐丝珐琅工艺品,色彩华丽绚烂。

-
-
-
-
-
-
-
-
\ No newline at end of file diff --git a/web/graduation/src/pages/travel/index.astro b/web/graduation/src/pages/travel/index.astro index 6a271c0..0429e13 100644 --- a/web/graduation/src/pages/travel/index.astro +++ b/web/graduation/src/pages/travel/index.astro @@ -89,9 +89,9 @@ const visibleTravels = sortedTravels.slice( -
+
-
+
@@ -349,7 +349,14 @@ const visibleTravels = sortedTravels.slice( href={`/travel/${travel.slug}`} class="block group" > -
+
@@ -1178,7 +1185,7 @@ const visibleTravels = sortedTravels.slice( 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 travelCards = document.querySelectorAll('#travel-list div[data-tags]'); const noResultsMessage = document.getElementById('no-results-message'); const searchTermMessage = document.getElementById('search-term-message'); const travelList = document.getElementById('travel-list'); @@ -1603,166 +1610,90 @@ const visibleTravels = sortedTravels.slice( let matchCount = 0; - // 如果没有筛选条件,显示所有卡片 - if (!searchValue && selectedSeasons.length === 0 && selectedTypes.length === 0 && selectedCities.length === 0 && selectedTags.length === 0) { - 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 = ''; - let cardTagsList: string[] = []; - - 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 => { - const tagText = tag.textContent?.toLowerCase().replace('#', '').trim() || ''; - if (tagText) { - tagsText += tagText + ' '; - cardTagsList.push(tagText); - } - }); - - // 寻找城市信息 - 从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)) - ); + const cardContainer = card.closest('a')?.parentElement; + if (!cardContainer) return; + + try { + // 直接从card获取数据属性 + const cardData = { + title: card.getAttribute('data-title')?.toLowerCase() || '', + description: card.getAttribute('data-description')?.toLowerCase() || '', + tags: JSON.parse(card.getAttribute('data-tags') || '[]').map((tag: string) => tag.toLowerCase()), + season: card.getAttribute('data-season')?.toLowerCase() || '', + type: card.getAttribute('data-type')?.toLowerCase() || '', + cities: JSON.parse(card.getAttribute('data-cities') || '[]').map((city: string) => city.toLowerCase()) + }; + + // 匹配搜索词 + const matchesSearch = !searchValue || + cardData.title.includes(searchValue) || + cardData.description.includes(searchValue) || + cardData.tags.some((tag: string) => tag.includes(searchValue)) || + cardData.cities.some((city: string) => city.includes(searchValue)); + + // 匹配季节 + const matchesSeasons = selectedSeasons.length === 0 || + selectedSeasons.some(season => cardData.season.includes(season)); + + // 匹配类型 + const matchesTypes = selectedTypes.length === 0 || + selectedTypes.some(type => cardData.type.includes(type)); + + // 匹配城市 + const matchesCities = selectedCities.length === 0 || + selectedCities.some(city => cardData.cities.some((cardCity: string) => cardCity.includes(city))); + + // 匹配标签 + const matchesTags = selectedTags.length === 0 || + selectedTags.some(tag => cardData.tags.some((cardTag: string) => cardTag.includes(tag))); + + // 所有条件都匹配才显示 + const isMatch = matchesSearch && matchesSeasons && matchesTypes && matchesCities && matchesTags; + + if (isMatch) { + matchCount++; + cardContainer.style.display = ''; } else { - // 如果没有找到城市标签,尝试在标题和描述中寻找 - matchesCities = selectedCities.some(city => - cardTitle.includes(city) || cardDesc.includes(city) - ); + cardContainer.style.display = 'none'; } - } - - // 标签匹配:如果有选中的标签,检查卡片标签中是否包含它们中的任何一个 - const matchesTags = selectedTags.length === 0 || selectedTags.some(tag => - cardTagsList.some(cardTag => cardTag.includes(tag)) - ); - - // 所有条件都匹配才显示 - const isMatch = matchesSearch && matchesSeasons && matchesTypes && matchesCities && matchesTags; - - if (isMatch) { - matchCount++; - card.classList.remove('hidden'); - } else { - card.classList.add('hidden'); + } catch (error) { + console.error('Error filtering card:', error); + cardContainer.style.display = 'none'; } }); - + // 更新无结果提示显示 if (matchCount === 0) { + if (travelList) travelList.classList.add('hidden'); if (noResultsMessage) { noResultsMessage.classList.remove('hidden'); - - // 更新无结果消息中的搜索词 if (searchTermMessage) { + let message = '抱歉,未找到相关旅行笔记。'; if (searchValue) { - searchTermMessage.textContent = `抱歉,未找到与 "${searchValue}" 相关的旅行笔记。请尝试其他关键词或浏览所有旅行记录。`; - } else if (selectedSeasons.length > 0 || selectedTypes.length > 0 || selectedCities.length > 0 || selectedTags.length > 0) { - searchTermMessage.textContent = `抱歉,未找到符合当前筛选条件的旅行笔记。请尝试调整筛选条件或浏览所有旅行记录。`; - } else { - searchTermMessage.textContent = `抱歉,未找到相关旅行笔记。请尝试其他关键词或浏览所有旅行记录。`; + message += `没有找到包含"${searchValue}"的内容。`; } + if (selectedSeasons.length > 0) { + message += `没有找到${selectedSeasons.join('、')}季节的内容。`; + } + if (selectedTypes.length > 0) { + message += `没有找到${selectedTypes.join('、')}类型的内容。`; + } + if (selectedCities.length > 0) { + message += `没有找到位于${selectedCities.join('、')}的内容。`; + } + if (selectedTags.length > 0) { + message += `没有找到标签为${selectedTags.join('、')}的内容。`; + } + searchTermMessage.textContent = message; } } - - // 隐藏旅行列表 - if (travelList) { - travelList.classList.add('hidden'); - } } else { - // 隐藏无结果提示 - if (noResultsMessage) { - noResultsMessage.classList.add('hidden'); - } - // 显示旅行列表 - if (travelList) { - travelList.classList.remove('hidden'); - } + if (travelList) travelList.classList.remove('hidden'); + if (noResultsMessage) noResultsMessage.classList.add('hidden'); } - + return matchCount; } diff --git a/web/graduation/src/styles/global.css b/web/graduation/src/styles/global.css index a1f693f..443217b 100644 --- a/web/graduation/src/styles/global.css +++ b/web/graduation/src/styles/global.css @@ -90,6 +90,19 @@ --color-dark-primary-900: #faefdb; } +/* 确保在无JavaScript环境下,ScrollReveal元素仍然可见 */ +.no-js .scroll-reveal { + opacity: 1 !important; + transform: none !important; +} + +/* 当JS加载完成时,移除no-js类 */ +html { + &.no-js { + opacity: 1; + } +} + :root { /* 基础色调 */ --bg-primary: var(--color-gray-50); @@ -176,6 +189,37 @@ .bg-slate-900 { background-color: var(--color-dark-bg); } + + /* 处理颜色命名不一致的问题 */ + .text-color-primary-600, + .text-primary-600 { + color: var(--color-dark-primary-600); + } + + .text-color-primary-400, + .text-primary-400 { + color: var(--color-dark-primary-400); + } + + .bg-color-primary-600, + .bg-primary-600 { + background-color: var(--color-dark-primary-600); + } + + .bg-color-primary-400, + .bg-primary-400 { + background-color: var(--color-dark-primary-400); + } + + .border-color-primary-600, + .border-primary-600 { + border-color: var(--color-dark-primary-600); + } + + .border-color-primary-400, + .border-primary-400 { + border-color: var(--color-dark-primary-400); + } /* 表单元素适配 */ input, @@ -220,6 +264,37 @@ .bg-amber-100 { background-color: var(--color-primary-50); } + + /* 处理颜色命名不一致的问题 */ + .text-color-primary-600, + .text-primary-600 { + color: var(--color-primary-600); + } + + .text-color-primary-400, + .text-primary-400 { + color: var(--color-primary-400); + } + + .bg-color-primary-600, + .bg-primary-600 { + background-color: var(--color-primary-600); + } + + .bg-color-primary-400, + .bg-primary-400 { + background-color: var(--color-primary-400); + } + + .border-color-primary-600, + .border-primary-600 { + border-color: var(--color-primary-600); + } + + .border-color-primary-400, + .border-primary-400 { + border-color: var(--color-primary-400); + } } /* 背景渐变动画 */ @@ -243,6 +318,25 @@ .border-theme-primary-light { border-color: var(--theme-primary-light); } .border-theme-primary-dark { border-color: var(--theme-primary-dark); } +/* 添加color-primary和primary颜色类的统一映射 */ +.text-primary-500, .text-color-primary-500 { color: var(--theme-primary); } +.text-primary-400, .text-color-primary-400 { color: var(--theme-primary-light); } +.text-primary-600, .text-color-primary-600 { color: var(--theme-primary-dark); } +.text-primary-300, .text-color-primary-300 { color: var(--color-primary-300); } +.text-primary-700, .text-color-primary-700 { color: var(--color-primary-700); } + +.bg-primary-500, .bg-color-primary-500 { background-color: var(--theme-primary); } +.bg-primary-400, .bg-color-primary-400 { background-color: var(--theme-primary-light); } +.bg-primary-600, .bg-color-primary-600 { background-color: var(--theme-primary-dark); } +.bg-primary-50, .bg-color-primary-50 { background-color: var(--theme-primary-bg); } +.bg-primary-100, .bg-color-primary-100 { background-color: var(--theme-primary-bg-hover); } + +.border-primary-500, .border-color-primary-500 { border-color: var(--theme-primary); } +.border-primary-400, .border-color-primary-400 { border-color: var(--theme-primary-light); } +.border-primary-600, .border-color-primary-600 { border-color: var(--theme-primary-dark); } +.border-primary-300, .border-color-primary-300 { border-color: var(--color-primary-300); } +.border-primary-700, .border-color-primary-700 { border-color: var(--color-primary-700); } + /* 主题特殊背景 - 使用统一命名并移除重复定义 */ .bg-scroll-bg { background-color: var(--bg-scroll); } .bg-recipe-paper { background-color: var(--bg-recipe); }