diff --git a/frontend/app/(main)/settings/notifications/page.tsx b/frontend/app/(main)/settings/notifications/page.tsx new file mode 100644 index 00000000..f074147d --- /dev/null +++ b/frontend/app/(main)/settings/notifications/page.tsx @@ -0,0 +1,5 @@ +import { NotificationsMain } from "@/components/common/settings/notifications" + +export default function NotificationsPage() { + return +} diff --git a/frontend/app/globals.css b/frontend/app/globals.css index 5b192e7d..33d51423 100644 --- a/frontend/app/globals.css +++ b/frontend/app/globals.css @@ -174,4 +174,23 @@ 0% { transform: translateY(0) scale(1); opacity: 1; } 100% { transform: translateY(-100px) scale(0); opacity: 0; } } + + /* + * 铃铛响铃动画配置 + * 使用微妙的摆动效果,优雅且不过度 + */ + --animate-bell-ring: bell-ring 0.6s cubic-bezier(0.36, 0.07, 0.19, 0.97); + + @keyframes bell-ring { + 0% { transform: rotate(0deg); } + 10% { transform: rotate(14deg); } + 20% { transform: rotate(-12deg); } + 30% { transform: rotate(10deg); } + 40% { transform: rotate(-8deg); } + 50% { transform: rotate(6deg); } + 60% { transform: rotate(-4deg); } + 70% { transform: rotate(2deg); } + 80% { transform: rotate(-1deg); } + 100% { transform: rotate(0deg); } + } } \ No newline at end of file diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx index 88a5e337..f2f2f369 100644 --- a/frontend/app/layout.tsx +++ b/frontend/app/layout.tsx @@ -3,6 +3,8 @@ import { Inter, Noto_Sans_SC, Geist_Mono } from 'next/font/google'; import { Toaster } from "@/components/ui/sonner"; import { ThemeProvider } from "@/components/layout/theme-provider"; import { CustomThemeProvider } from "@/lib/theme"; +import { BellRingProvider } from "@/contexts/bell-ring-context"; +import { NotificationSettingsProvider } from "@/contexts/notification-settings-context"; import "./globals.css"; const inter = Inter({ @@ -49,8 +51,12 @@ export default function RootLayout({ disableTransitionOnChange > - {children} - + + + {children} + + + diff --git a/frontend/components/common/settings/notifications.tsx b/frontend/components/common/settings/notifications.tsx new file mode 100644 index 00000000..6dca9fc6 --- /dev/null +++ b/frontend/components/common/settings/notifications.tsx @@ -0,0 +1,60 @@ +"use client" + +import Link from "next/link" +import { Bell } from "lucide-react" +import { Switch } from "@/components/ui/switch" +import { Label } from "@/components/ui/label" +import { useNotificationSettings } from "@/contexts/notification-settings-context" +import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "@/components/ui/breadcrumb" + +export function NotificationsMain() { + const { showBell, setShowBell } = useNotificationSettings() + + return ( +
+
+ + + + + 设置 + + + + + 通知设置 + + + +
+ +
+
+

通知显示

+

+ 设置通知相关的显示选项 +

+
+ +
+
+ +
+ +

+ 在顶部导航栏中显示通知铃铛图标 +

+
+
+ +
+
+
+ ) +} diff --git a/frontend/components/layout/header.tsx b/frontend/components/layout/header.tsx index 859f3ab3..f6f3f797 100644 --- a/frontend/components/layout/header.tsx +++ b/frontend/components/layout/header.tsx @@ -1,16 +1,51 @@ "use client" -import { useState, useEffect } from "react" +import { useState, useEffect, memo } from "react" import { AnimatePresence, motion } from "motion/react" import { Button } from "@/components/ui/button" import { Bell, Plus, Settings, Search, Moon, Sun, Maximize2, Minimize2 } from "lucide-react" import { useUser } from "@/contexts/user-context" +import { useBellRing } from "@/contexts/bell-ring-context" +import { useNotificationSettings } from "@/contexts/notification-settings-context" import { SidebarTrigger } from "@/components/ui/sidebar" import { useTheme } from "next-themes" import { useRouter } from "next/navigation" import { SearchDialog } from "@/components/layout/search-dialog" +/** + * 铃铛按钮组件 + */ +const BellButton = memo(function BellButton() { + const { isRinging } = useBellRing() + const { showBell, isMounted } = useNotificationSettings() + const [isClickAnimating, setIsClickAnimating] = useState(false) + + if (!isMounted) return null + if (!showBell) return null + + const handleClick = () => { + setIsClickAnimating(true) + setTimeout(() => setIsClickAnimating(false), 600) + } + + return ( + + ) +}) + + /** * 站点头部组件 * 用于显示站点头部 @@ -52,10 +87,7 @@ export function SiteHeader({ isFullWidth = false, onToggleFullWidth }: { isFullW 搜索 - + +