frontend: rebuild bookmark page with drag-and-drop, search, and theme system

- bookmark management with dnd-kit reordering, bulk edit, search,
  category filter/rename, and meta auto-fetch
- migrate /bookmarks → /dashboard/bookmarks under (main) layout
- homepage redesign with category grid, /-key search, dock tooltips
- theme toggle + use-theme, sonner toasts, alert-dialog/skeleton,
  visual refresh of auth pages

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
root
2026-05-02 22:53:17 +00:00
parent 832512469a
commit 694b02e848
26 changed files with 2377 additions and 561 deletions

View File

@@ -1,5 +1,6 @@
import type { Metadata } from "next";
import type { Metadata, Viewport } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import { Toaster } from "sonner";
import "./globals.css";
const geistSans = Geist({
@@ -13,10 +14,36 @@ const geistMono = Geist_Mono({
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
title: {
default: "EvanPage",
template: "%s · EvanPage",
},
description: "个人主页与导航",
icons: {
icon: "/favicon.ico",
},
};
export const viewport: Viewport = {
width: "device-width",
initialScale: 1,
themeColor: [
{ media: "(prefers-color-scheme: light)", color: "#fafbff" },
{ media: "(prefers-color-scheme: dark)", color: "#0e1117" },
],
};
const themeInitScript = `
(function() {
try {
var stored = localStorage.getItem('theme');
var prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
var resolved = stored === 'dark' || stored === 'light' ? stored : (prefersDark ? 'dark' : 'light');
if (resolved === 'dark') document.documentElement.classList.add('dark');
} catch (e) {}
})();
`;
export default function RootLayout({
children,
}: Readonly<{
@@ -24,10 +51,17 @@ export default function RootLayout({
}>) {
return (
<html
lang="en"
lang="zh-CN"
className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`}
suppressHydrationWarning
>
<body className="min-h-full flex flex-col">{children}</body>
<head>
<script dangerouslySetInnerHTML={{ __html: themeInitScript }} />
</head>
<body className="min-h-full flex flex-col bg-background text-foreground">
{children}
<Toaster richColors position="top-right" />
</body>
</html>
);
}