Banner System Implementation
动态 Banner 系统的实现文档和移除指南
Banner System Implementation
本文档介绍了网站顶部 Banner 系统的完整实现,包括组件结构、状态管理和如何进行修改或移除。
系统架构
核心组件
- 状态管理 -
src/lib/stores/banner-store.ts
- 布局钩子 -
src/lib/hooks/use-banner-layout.ts
- Banner 组件 -
src/modules/shared/components/BetaBanner.tsx
- 动态布局包装器
src/app/(public)/[locale]/DynamicLayoutWrapper.tsx
src/app/(app)/DynamicAppWrapper.tsx
技术特性
- 状态持久化: 使用 Zustand + persist 中间件,用户关闭后状态保存在 localStorage
- 动态布局: 根据 Banner 显示状态自动调整 NavBar 位置和内容区域 padding
- 平滑过渡: 所有组件都有 200ms 的过渡动画效果
- 响应式设计: 适配不同布局(公共页面 vs 应用页面)
实现细节
1. 状态管理 (banner-store.ts)
interface BannerStore {
isBetaBannerVisible: boolean;
hideBetaBanner: () => void;
showBetaBanner: () => void;
}
使用 Zustand 管理 Banner 的显示状态,支持状态持久化。
2. 动态布局计算 (use-banner-layout.ts)
const styles = {
navbarTop: isBetaBannerVisible ? 'top-8' : 'top-0',
publicMainPadding: isBetaBannerVisible ? 'pt-20' : 'pt-16',
appMainPadding: isBetaBannerVisible ? 'pt-8' : 'pt-0',
};
根据 Banner 状态动态计算各组件的样式。Banner 高度为 32px(使用 py-1
样式)。
3. Banner 组件特性
- 固定定位在页面顶部 (
fixed top-0 z-[60]
) - 黑色背景白色文字的简洁设计
- 支持关闭功能,关闭后触发状态更新
- 使用 shadcn/ui 的官方 Banner 组件
4. 布局适配
公共页面布局 (有 NavBar):
- Banner 显示时:
pt-20
(Banner + NavBar 高度) - Banner 隐藏时:
pt-16
(仅 NavBar 高度)
应用页面布局 (无 NavBar):
- Banner 显示时:
pt-8
(仅 Banner 高度) - Banner 隐藏时:
pt-0
(无额外 padding)
如何移除 Banner 系统
如果需要完全移除 Banner 系统,请按以下步骤操作:
如何暂时关闭 Banner
如果只需要暂时关闭 Banner(比如在测试期间或特殊情况下),有以下几种方法:
方法 1: 修改默认状态(推荐)
编辑 src/lib/stores/banner-store.ts
,将默认显示状态改为 false:
export const useBannerStore = create<BannerStore>()(
persist(
(set) => ({
isBetaBannerVisible: false, // 改为 false 暂时关闭
hideBetaBanner: () => set({ isBetaBannerVisible: false }),
showBetaBanner: () => set({ isBetaBannerVisible: true }),
}),
{
name: 'banner-storage',
}
)
);
优点:
- 只需修改一行代码
- 保持了完整的功能逻辑
- 用户之前的关闭状态会被保留
- 将来重新开启只需要改回
true
方法 2: 在组件中直接返回 null
编辑 src/modules/shared/components/BetaBanner.tsx
:
export function BetaBanner() {
// 暂时关闭 Banner
return null;
// 以下代码暂时注释...
}
方法 3: 使用环境变量控制
在 .env.local
中添加:
NEXT_PUBLIC_SHOW_BETA_BANNER=false
然后在 BetaBanner 组件中:
export function BetaBanner() {
if (process.env.NEXT_PUBLIC_SHOW_BETA_BANNER === 'false') {
return null;
}
// 原有逻辑...
}
如何完全移除 Banner 系统
步骤 1: 移除核心文件
# 删除状态管理
rm src/lib/stores/banner-store.ts
# 删除布局钩子
rm src/lib/hooks/use-banner-layout.ts
# 删除 Banner 组件
rm src/modules/shared/components/BetaBanner.tsx
# 删除动态布局包装器
rm src/app/(public)/[locale]/DynamicLayoutWrapper.tsx
rm src/app/(app)/DynamicAppWrapper.tsx
步骤 2: 还原 NavBar 组件
编辑 src/modules/marketing/shared/components/NavBar.tsx
:
- import { useBannerLayout } from "@/lib/hooks/use-banner-layout";
export function NavBar() {
const t = useTranslations();
const { user } = useSession();
- const { navbarTop } = useBannerLayout();
// ... 其他代码保持不变
return (
<nav
className={cn(
- "fixed left-0 z-50 w-full transition-all duration-200",
- navbarTop,
+ "fixed top-0 left-0 z-50 w-full transition-shadow duration-200",
!isTop || isDocsPage || isHome1Page
? "bg-card/80 shadow-sm backdrop-blur-lg"
: "shadow-none",
)}
data-test="navigation"
>
步骤 3: 还原公共页面布局
编辑 src/app/(public)/[locale]/layout.tsx
:
- import { BetaBanner } from "@/components/shared/BetaBanner";
- import { DynamicLayoutWrapper } from "./DynamicLayoutWrapper";
// 在 JSX 中移除 Banner 和动态包装器
<NextIntlClientProvider locale={locale} messages={messages}>
<SessionProvider>
- <BetaBanner />
<NavBar />
- <DynamicLayoutWrapper>{children}</DynamicLayoutWrapper>
+ <main className="min-h-screen pt-16">{children}</main>
<ConditionalFooter locale={locale} />
<TabBar />
</SessionProvider>
</NextIntlClientProvider>
步骤 4: 还原应用页面布局
编辑 src/app/(app)/layout.tsx
:
- import { BetaBanner } from "@/components/shared/BetaBanner";
- import { DynamicAppWrapper } from "./DynamicAppWrapper";
return (
<Document locale={locale}>
<NextIntlClientProvider messages={messages}>
- <BetaBanner />
- <DynamicAppWrapper>{children}</DynamicAppWrapper>
+ {children}
</NextIntlClientProvider>
</Document>
);
步骤 5: 清理翻译文件
编辑 src/lib/i18n/translations/zh.json
和 en.json
:
{
- "beta": {
- "label": "BETA",
- "message": "本平台处于测试阶段,数据可能丢失",
- "close": "关闭"
- },
// ... 其他翻译保持不变
}
步骤 6: 清理依赖(可选)
如果项目中没有其他地方使用 Zustand,可以移除依赖:
bun remove zustand
修改 Banner 内容
如果只需要修改 Banner 的文字内容,编辑翻译文件:
中文 (src/lib/i18n/translations/zh.json
):
{
"beta": {
"label": "BETA",
"message": "你的新消息内容",
"close": "关闭"
}
}
英文 (src/lib/i18n/translations/en.json
):
{
"beta": {
"label": "BETA",
"message": "Your new message content",
"close": "Close"
}
}
修改 Banner 样式
如果需要修改 Banner 的外观,编辑 src/modules/shared/components/BetaBanner.tsx
中的 className:
<Banner className="bg-blue-600 text-white fixed top-0 left-0 w-full z-[60]">
注意事项
- 状态持久化: Banner 的显示状态会保存在用户的 localStorage 中,清除浏览器数据后会重新显示
- Z-index 层级: Banner 使用
z-[60]
,高于 NavBar 的z-50
- 过渡动画: 所有相关组件都有 200ms 的过渡效果,移除时注意保持一致性
- 响应式适配: 当前实现在移动端和桌面端都有良好的表现
- Banner 高度: 当前使用
py-1
样式,实际高度约 32px,布局计算基于此高度