refactor(fishpond, tags): 引入 PageHeroHeader 和 PageHeroGrid 组件,优化页面布局

- 在 FishpondPage 和 TagsPageClient 中添加了 PageHeroHeader 和 PageHeroGrid 组件,提升页面结构和可读性。
- 更新了 FishpondPage 的背景样式,简化了布局。
- 调整了 VirtualizedTagList 的样式,确保一致的间距和视觉效果。
This commit is contained in:
刘宇阳
2026-07-07 15:14:55 +08:00
parent 5f9793e02a
commit 896acd7e90
5 changed files with 91 additions and 16 deletions

View File

@@ -13,7 +13,7 @@ import { dayFormat } from '@/utils';
// 引入图标
import { HiOutlineClock, HiOutlineHashtag, HiOutlineArrowTopRightOnSquare } from 'react-icons/hi2';
import { TbRipple } from 'react-icons/tb';
import PageHeroHeader, { PageHeroGrid } from '@/components/PageHeroHeader';
// 瀑布流断点配置
const breakpointColumnsObj = {
@@ -75,17 +75,13 @@ export default function FishpondPage() {
<title>🐟 | Rss Feed</title>
<meta name="description" content="汇聚好友与订阅的动态鱼塘" />
<div className="min-h-screen bg-[linear-gradient(110deg,#fbfbfc_0%,#f7f8fa_58%,#fbfbfc_100%)] dark:bg-[linear-gradient(to_right,#232931_0%,#232931_100%)] pt-24 pb-12 px-4 sm:px-6 lg:px-8">
<div className="w-full max-w-[1920px] mx-auto">
<div className="relative mb-14 flex flex-col items-center select-none pt-6 md:pt-12">
<div className="inline-flex items-center justify-center gap-3 mb-4">
<TbRipple className="text-4xl text-blue-500 animate-pulse" />
<h2 className="text-4xl md:text-5xl font-extrabold tracking-tight text-[#161a22] dark:text-slate-100"> </h2>
</div>
<p className="text-[#788190] dark:text-slate-400 text-sm md:text-base"></p>
</div>
<div className="relative min-h-screen bg-[linear-gradient(110deg,#fbfbfc_0%,#f7f8fa_58%,#fbfbfc_100%)] dark:bg-[linear-gradient(to_right,#232931_0%,#232931_100%)] pb-12 px-4 sm:px-6 lg:px-8">
<PageHeroGrid />
<div className="mt-10">
<div className="relative w-full max-w-[1920px] mx-auto">
<PageHeroHeader title="鱼塘" subtitle="潜入信息的海洋,捕获最新鲜的动态" className="mb-8" />
<div className="relative z-10">
{rssData && rssData.length > 0 ? (
<Masonry breakpointCols={breakpointColumnsObj} className="flex w-auto -ml-5" columnClassName="pl-5 bg-clip-padding flex flex-col gap-5">
{rssData.map((item, index) => {

View File

@@ -3,6 +3,7 @@
import React, { useMemo } from 'react';
import { Tag } from '@/types/app/tag';
import TagCloudBackground from '@/app/tags/components/TagCloudBackground';
import PageHeroHeader, { PageHeroGrid } from '@/components/PageHeroHeader';
import VirtualizedTagList from './VirtualizedTagList';
interface TagsPageClientProps {
@@ -16,11 +17,11 @@ export default function TagsPageClient({ tags }: TagsPageClientProps) {
}, [tags]);
return (
<div className="py-[50px] mt-[60px] min-h-screen relative hide_sliding">
<h1 className="relative z-20 text-4xl font-bold text-center mb-5"></h1>
<div className="relative min-h-screen hide_sliding">
<PageHeroGrid />
<PageHeroHeader title="标签墙" subtitle="拾取标签,发现更多感兴趣的内容" className="z-20" />
{/* 标签列表 */}
<div className="relative z-20 w-11/12 mx-auto">
<div className="relative z-20 w-11/12 mx-auto mt-4">
<VirtualizedTagList tags={tags} initialBatchSize={30} batchSize={30} />
</div>

View File

@@ -124,7 +124,7 @@ const VirtualizedTagList: React.FC<VirtualizedTagListProps> = ({
className="w-full"
>
<div
className="flex flex-wrap justify-center w-full py-10 px-0 sm:px-10"
className="flex flex-wrap justify-center w-full pb-10 px-0 sm:px-10"
style={{
contain: 'layout', // 隔离布局影响
}}

View File

@@ -0,0 +1,21 @@
@keyframes wall-shimmer {
0%,
100% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
}
@keyframes wall-float-dot {
0%,
100% {
transform: translateY(0);
opacity: 0.6;
}
50% {
transform: translateY(-14px);
opacity: 1;
}
}

View File

@@ -0,0 +1,57 @@
'use client';
import { ZCOOL_KuaiLe } from 'next/font/google';
import './hero.css';
const zcoolKuaiLe = ZCOOL_KuaiLe({ weight: '400', subsets: ['latin'] });
const floatDots = [
{ size: 'w-2 h-2', color: 'bg-rose-400/70', delay: '0s' },
{ size: 'w-1.5 h-1.5', color: 'bg-amber-400/70', delay: '0.5s' },
{ size: 'w-2.5 h-2.5', color: 'bg-violet-400/70', delay: '1s' },
{ size: 'w-1.5 h-1.5', color: 'bg-cyan-400/70', delay: '1.5s' },
{ size: 'w-2 h-2', color: 'bg-emerald-400/70', delay: '2s' },
];
interface PageHeroHeaderProps {
title: string;
subtitle: string;
className?: string;
}
export function PageHeroGrid() {
return (
<div className="pointer-events-none fixed inset-0 overflow-hidden" aria-hidden="true">
<div className="absolute inset-0 bg-[linear-gradient(rgba(148,163,184,0.06)_1px,transparent_1px),linear-gradient(90deg,rgba(148,163,184,0.06)_1px,transparent_1px)] bg-size-[64px_64px]" />
</div>
);
}
export default function PageHeroHeader({ title, subtitle, className = '' }: PageHeroHeaderProps) {
return (
<header className={`relative z-10 pt-20 pb-4 mt-10 text-center select-none ${className}`}>
<div className="flex justify-center gap-3 mb-6">
{floatDots.map((dot, i) => (
<span
key={i}
className={`animate-[wall-float-dot_3s_ease-in-out_infinite] rounded-full ${dot.size} ${dot.color}`}
style={{ animationDelay: dot.delay }}
/>
))}
</div>
<h1 className={`text-6xl sm:text-7xl font-bold tracking-tight mb-5 ${zcoolKuaiLe.className}`}>
<span className="bg-size-[200%_auto] bg-linear-to-r from-amber-500 via-rose-500 to-violet-500 bg-clip-text text-transparent animate-[wall-shimmer_5s_ease_infinite] dark:from-amber-300 dark:via-rose-300 dark:to-violet-400">
{title}
</span>
</h1>
<p className="text-neutral-500 dark:text-neutral-400 text-base sm:text-lg tracking-[0.2em] font-light">{subtitle}</p>
<div className="mt-8 flex items-center justify-center gap-3">
<div className="w-20 h-px bg-linear-to-r from-transparent to-neutral-300 dark:to-neutral-700" />
<div className="w-2 h-2 rounded-full bg-amber-400/80 shadow-lg shadow-amber-400/20" />
<div className="w-20 h-px bg-linear-to-l from-transparent to-neutral-300 dark:to-neutral-700" />
</div>
</header>
);
}