feat: 添加顶部公告栏跳转链接和关闭按钮功能
- 新增 AnnouncementBar 客户端组件支持点击跳转 - 添加关闭按钮,状态保存至 localStorage - 刷新页面后记住用户关闭状态 - 支持 i18n 配置公告内容和链接 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+51
-26
@@ -1,7 +1,9 @@
|
||||
import { notFound } from "next/navigation"
|
||||
import { setRequestLocale } from 'next-intl/server'
|
||||
import { setRequestLocale, getTranslations } from 'next-intl/server'
|
||||
import Link from "next/link"
|
||||
import { LocaleSwitcher } from "@/components/locale/LocaleSwitcher"
|
||||
import { AnnouncementBar } from "@/components/layout/AnnouncementBar"
|
||||
import type { Metadata } from "next"
|
||||
|
||||
const locales = ['zh', 'en']
|
||||
|
||||
@@ -9,6 +11,20 @@ export async function generateStaticParams() {
|
||||
return locales.map((locale) => ({ locale }))
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params
|
||||
}: {
|
||||
params: Promise<{ locale: string }>
|
||||
}): Promise<Metadata> {
|
||||
const { locale } = await params
|
||||
const t = await getTranslations('home')
|
||||
|
||||
return {
|
||||
title: t('metaTitle'),
|
||||
description: t('metaDescription'),
|
||||
}
|
||||
}
|
||||
|
||||
export default async function LocaleLayout({
|
||||
children,
|
||||
params
|
||||
@@ -23,13 +39,15 @@ export default async function LocaleLayout({
|
||||
|
||||
setRequestLocale(locale)
|
||||
|
||||
// Get translations
|
||||
const t = await getTranslations('layout')
|
||||
const tNav = await getTranslations('navigation')
|
||||
const tHome = await getTranslations('home')
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col">
|
||||
{/* Top announcement bar */}
|
||||
<div className="bg-primary w-full py-2 px-4 border-b-2 border-black dark:border-gray-600 flex justify-center items-center text-xs font-bold font-display tracking-wide text-black">
|
||||
<span>DISCOVER THE FUTURE OF AI AGENTS</span>
|
||||
<span className="material-icons text-sm align-middle ml-1">arrow_forward</span>
|
||||
</div>
|
||||
<AnnouncementBar text={t('announcement')} href={t('announcementHref')} locale={locale} />
|
||||
|
||||
{/* Navigation */}
|
||||
<header className="w-full border-b-2 border-black dark:border-gray-600 bg-background-light dark:bg-background-dark sticky top-0 z-50">
|
||||
@@ -49,36 +67,39 @@ export default async function LocaleLayout({
|
||||
className="font-display text-sm font-bold hover:text-secondary dark:hover:text-primary transition-colors"
|
||||
href={`/${locale}`}
|
||||
>
|
||||
HOME
|
||||
{tNav('home')}
|
||||
</Link>
|
||||
<Link
|
||||
className="font-display text-sm font-bold hover:text-secondary dark:hover:text-primary transition-colors"
|
||||
href={`/${locale}/projects`}
|
||||
>
|
||||
PROJECTS
|
||||
{tNav('projects')}
|
||||
</Link>
|
||||
<Link
|
||||
className="font-display text-sm font-bold hover:text-secondary dark:hover:text-primary transition-colors"
|
||||
href="#"
|
||||
>
|
||||
BLOG
|
||||
{tNav('blog')}
|
||||
</Link>
|
||||
<Link
|
||||
className="font-display text-sm font-bold hover:text-secondary dark:hover:text-primary transition-colors"
|
||||
href="#"
|
||||
>
|
||||
ABOUT
|
||||
{tNav('about')}
|
||||
</Link>
|
||||
</nav>
|
||||
|
||||
{/* Right side */}
|
||||
<div className="hidden md:flex items-center space-x-4">
|
||||
<LocaleSwitcher currentLocale={locale} />
|
||||
<LocaleSwitcher
|
||||
currentLocale={locale}
|
||||
switchUrl={`/${locale === 'zh' ? 'en' : 'zh'}`}
|
||||
/>
|
||||
<Link
|
||||
className="bg-white dark:bg-surface-dark border-2 border-black dark:border-white px-4 py-2 font-display text-sm font-bold shadow-neo-sm hover:shadow-none hover:translate-x-[2px] hover:translate-y-[2px] transition-all"
|
||||
href="#"
|
||||
>
|
||||
SUBMIT PROJECT
|
||||
{tNav('submitProject')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -98,27 +119,31 @@ export default async function LocaleLayout({
|
||||
<section className="border-t-2 border-black dark:border-gray-600">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2">
|
||||
<div className="bg-primary dark:bg-yellow-600 p-12 md:p-20 border-b-2 md:border-b-0 md:border-r-2 border-black dark:border-gray-600 flex flex-col justify-center">
|
||||
<h2 className="font-display text-4xl font-bold text-black mb-4">STAY UPDATED</h2>
|
||||
<h2 className="font-display text-4xl font-bold text-black mb-4">{t('stayUpdated')}</h2>
|
||||
<p className="font-sans text-black mb-8 max-w-md">
|
||||
Get the latest AI tools and trends delivered straight to your inbox. No spam, just intelligence.
|
||||
{t('stayUpdatedDesc')}
|
||||
</p>
|
||||
<form className="space-y-4 max-w-md">
|
||||
<input
|
||||
className="w-full bg-background-light border-2 border-black p-3 font-display text-sm placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-black"
|
||||
placeholder="E-mail"
|
||||
placeholder={t('email')}
|
||||
type="email"
|
||||
id="newsletter-email"
|
||||
name="email"
|
||||
autoComplete="email"
|
||||
required
|
||||
/>
|
||||
<div className="flex items-center gap-2">
|
||||
<input className="w-4 h-4 border-2 border-black text-black focus:ring-0" id="consent" type="checkbox" />
|
||||
<input className="w-4 h-4 border-2 border-black text-black focus:ring-0" id="consent" name="consent" type="checkbox" required />
|
||||
<label className="text-xs font-bold font-display text-black" htmlFor="consent">
|
||||
Subscribe to Agent Park updates
|
||||
{t('subscribeConsent')}
|
||||
</label>
|
||||
</div>
|
||||
<button
|
||||
className="bg-white text-black font-display font-bold py-3 px-8 border-2 border-black shadow-neo hover:shadow-none hover:translate-x-[2px] hover:translate-y-[2px] transition-all"
|
||||
type="submit"
|
||||
>
|
||||
SUBSCRIBE
|
||||
{t('subscribe')}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
@@ -144,26 +169,26 @@ export default async function LocaleLayout({
|
||||
<span className="font-display font-bold text-lg tracking-tight">Agent Park</span>
|
||||
</Link>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
Discover and explore high-quality AI projects from across the web. Curated for developers and enthusiasts.
|
||||
{t('footerDesc')}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-display font-bold text-lg mb-4">Resources</h4>
|
||||
<h4 className="font-display font-bold text-lg mb-4">{t('resources')}</h4>
|
||||
<ul className="space-y-2 text-sm font-sans text-gray-600 dark:text-gray-400">
|
||||
<li><Link className="hover:text-black dark:hover:text-white" href="#">Blog</Link></li>
|
||||
<li><Link className="hover:text-black dark:hover:text-white" href="#">{tNav('blog')}</Link></li>
|
||||
<li><Link className="hover:text-black dark:hover:text-white" href="#">Newsletter</Link></li>
|
||||
<li><Link className="hover:text-black dark:hover:text-white" href="#">Documentation</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-display font-bold text-lg mb-4">Legal</h4>
|
||||
<h4 className="font-display font-bold text-lg mb-4">{t('legal')}</h4>
|
||||
<ul className="space-y-2 text-sm font-sans text-gray-600 dark:text-gray-400">
|
||||
<li><Link className="hover:text-black dark:hover:text-white" href="#">Privacy Policy</Link></li>
|
||||
<li><Link className="hover:text-black dark:hover:text-white" href="#">Terms of Service</Link></li>
|
||||
<li><Link className="hover:text-black dark:hover:text-white" href="#">{t('privacyPolicy')}</Link></li>
|
||||
<li><Link className="hover:text-black dark:hover:text-white" href="#">{t('termsOfService')}</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-display font-bold text-lg mb-4">Follow Us</h4>
|
||||
<h4 className="font-display font-bold text-lg mb-4">{t('followUs')}</h4>
|
||||
<div className="flex space-x-4">
|
||||
<Link className="w-10 h-10 border-2 border-black dark:border-gray-500 flex items-center justify-center hover:bg-primary hover:text-black transition-colors font-display font-bold" href="#">X</Link>
|
||||
<Link className="w-10 h-10 border-2 border-black dark:border-gray-500 flex items-center justify-center hover:bg-primary hover:text-black transition-colors font-display font-bold" href="#">Li</Link>
|
||||
@@ -172,9 +197,9 @@ export default async function LocaleLayout({
|
||||
</div>
|
||||
</div>
|
||||
<div className="border-t border-black dark:border-gray-700 pt-8 flex flex-col md:flex-row justify-between items-center">
|
||||
<p className="text-sm text-gray-500 font-display">© 2025 Agent Park. All rights reserved.</p>
|
||||
<p className="text-sm text-gray-500 font-display">{t('copyright')}</p>
|
||||
<div className="mt-4 md:mt-0 font-display text-sm font-bold">
|
||||
DESIGNED FOR AI BUILDERS
|
||||
{t('designedFor')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user