From 4cf7c97dc4ef25f5e4be0248deade0ae6888b065 Mon Sep 17 00:00:00 2001 From: JOYCEQL <1449239013@qq.com> Date: Fri, 7 Mar 2025 13:41:02 +0800 Subject: [PATCH] feat: add changelog feature with localized support and update navigation links --- .../(public)/[locale]/changelog/layout.tsx | 38 ++++++ src/app/(public)/[locale]/changelog/page.tsx | 49 +++++++ src/components/home/LandingHeader.tsx | 21 ++- src/components/home/client/MobileMenu.tsx | 39 +++++- src/components/shared/ChangelogTimeline.tsx | 121 ++++++++++++++++++ src/i18n/locales/en.json | 1 + src/i18n/locales/zh.json | 1 + src/lib/getChangelog.ts | 25 ++++ 8 files changed, 285 insertions(+), 10 deletions(-) create mode 100644 src/app/(public)/[locale]/changelog/layout.tsx create mode 100644 src/app/(public)/[locale]/changelog/page.tsx create mode 100644 src/components/shared/ChangelogTimeline.tsx create mode 100644 src/lib/getChangelog.ts diff --git a/src/app/(public)/[locale]/changelog/layout.tsx b/src/app/(public)/[locale]/changelog/layout.tsx new file mode 100644 index 0000000..2e13e30 --- /dev/null +++ b/src/app/(public)/[locale]/changelog/layout.tsx @@ -0,0 +1,38 @@ +import { ReactNode } from "react"; +import { Metadata } from "next"; +import { NextIntlClientProvider } from "next-intl"; +import { getMessages, getTranslations } from "next-intl/server"; +import LandingHeader from "@/components/home/LandingHeader"; +import Footer from "@/components/home/Footer"; + +type Props = { + children: ReactNode; + params: { locale: string }; +}; + +export async function generateMetadata({ + params: { locale }, +}: Props): Promise { + const t = await getTranslations({ locale }); + + return { + title: t("home.changelog") + " - " + t("common.title"), + }; +} + +export default async function ChangelogLayout({ + children, + params: { locale }, +}: Props) { + const messages = await getMessages(); + + return ( + +
+ +
{children}
+
+
+
+ ); +} diff --git a/src/app/(public)/[locale]/changelog/page.tsx b/src/app/(public)/[locale]/changelog/page.tsx new file mode 100644 index 0000000..de75e50 --- /dev/null +++ b/src/app/(public)/[locale]/changelog/page.tsx @@ -0,0 +1,49 @@ +"use client"; + +import React from "react"; +import { useTranslations } from "next-intl"; +import { ArrowLeft } from "lucide-react"; +import { useRouter, usePathname } from "next/navigation"; +import ChangelogTimeline from "@/components/shared/ChangelogTimeline"; +import { getChangelog } from "@/lib/getChangelog"; +import { cn } from "@/lib/utils"; + +export default function ChangelogPage() { + const t = useTranslations("home"); + const changelogEntries = getChangelog(); + const router = useRouter(); + const pathname = usePathname(); + const locale = pathname.split("/")[1]; + + return ( +
+
+ + +

+ {t("changelog")} +

+
+
+ +
+
+ +
+
+
+ ); +} diff --git a/src/components/home/LandingHeader.tsx b/src/components/home/LandingHeader.tsx index 415e3e1..6e81123 100644 --- a/src/components/home/LandingHeader.tsx +++ b/src/components/home/LandingHeader.tsx @@ -2,8 +2,9 @@ import { useState } from "react"; import Link from "next/link"; +import { usePathname } from "next/navigation"; import { useTranslations } from "next-intl"; -import { Menu, Moon, Sun, X } from "lucide-react"; +import { FileText, Menu, Moon, Sun, X } from "lucide-react"; import { Button } from "@/components/ui/button"; import Logo from "@/components/shared/Logo"; @@ -16,6 +17,8 @@ import GoDashboard from "./GoDashboard"; export default function LandingHeader() { const t = useTranslations("home"); + const pathname = usePathname(); + const locale = pathname.split("/")[1]; // 从路径中获取语言代码 const [isMenuOpen, setIsMenuOpen] = useState(false); return ( @@ -23,12 +26,14 @@ export default function LandingHeader() {
-
+
(window.location.href = `/${locale}/`)} + > {t("header.title")}
- {/* Desktop Navigation */}
@@ -39,6 +44,14 @@ export default function LandingHeader() { + + + {t("changelog") || "更新日志"} + +
- {/* Mobile Menu Button */}
- {/* Mobile Navigation */} setIsMenuOpen(false)} diff --git a/src/components/home/client/MobileMenu.tsx b/src/components/home/client/MobileMenu.tsx index 975374d..233f43d 100644 --- a/src/components/home/client/MobileMenu.tsx +++ b/src/components/home/client/MobileMenu.tsx @@ -1,9 +1,9 @@ "use client"; import { motion } from "framer-motion"; +import { useTranslations, useLocale } from "next-intl"; import Link from "next/link"; -import { useTranslations } from "next-intl"; -import { Sun, Moon } from "lucide-react"; +import { Sun, Moon, FileText } from "lucide-react"; import { Button } from "@/components/ui/button"; import ThemeToggle from "@/components/shared/ThemeToggle"; import LanguageSwitch from "@/components/shared/LanguageSwitch"; @@ -13,9 +13,22 @@ interface MobileMenuProps { isOpen: boolean; onClose: () => void; buttonText: string; + extraItems?: Array<{ + icon: React.ReactNode; + label: string; + component: React.ReactNode; + }>; } -export default function MobileMenu({ isOpen, onClose, buttonText }: MobileMenuProps) { +export default function MobileMenu({ + isOpen, + onClose, + buttonText, + extraItems = [], +}: MobileMenuProps) { + const t = useTranslations("home"); + const locale = useLocale(); + if (!isOpen) return null; return ( @@ -27,7 +40,6 @@ export default function MobileMenu({ isOpen, onClose, buttonText }: MobileMenuPr >