diff --git a/.dev.err.log b/.dev.err.log new file mode 100644 index 0000000..ad19159 --- /dev/null +++ b/.dev.err.log @@ -0,0 +1,2 @@ +⚠ Cross origin request detected from 127.0.0.1 to /_next/* resource. In a future major version of Next.js, you will need to explicitly configure "allowedDevOrigins" in next.config to allow this. +Read more: https://nextjs.org/docs/app/api-reference/config/next-config-js/allowedDevOrigins diff --git a/.dev.log b/.dev.log new file mode 100644 index 0000000..100a218 --- /dev/null +++ b/.dev.log @@ -0,0 +1,72 @@ + +> note-ai@1.0.0105 dev +> next dev -p 3001 + +▲ Next.js 16.1.1 (Turbopack) +- Local: http://localhost:3001 +- Network: http://198.18.0.1:3001 +- Environments: .env + +✓ Starting... +✓ Ready in 1339ms + GET / 200 in 2.5s (compile: 1896ms, proxy.ts: 145ms, render: 479ms) +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 164ms (compile: 104ms, proxy.ts: 9ms, render: 51ms) +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 32ms (compile: 3ms, proxy.ts: 6ms, render: 22ms) +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 29ms (compile: 3ms, proxy.ts: 4ms, render: 21ms) +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 29ms (compile: 3ms, proxy.ts: 5ms, render: 21ms) +prisma:query SELECT `main`.`Page`.`id` FROM `main`.`Page` WHERE (`main`.`Page`.`id` = ? AND 1=1) LIMIT ? OFFSET ? +prisma:query UPDATE `main`.`Page` SET `content` = ?, `updatedAt` = ? WHERE (`main`.`Page`.`id` = ? AND 1=1) RETURNING `id` AS `id`, `title` AS `title`, `content` AS `content`, `tags` AS `tags`, `icon` AS `icon`, `type` AS `type`, `parentId` AS `parentId`, `createdAt` AS `createdAt`, `updatedAt` AS `updatedAt`, `order` AS `order`, `isLocked` AS `isLocked` + PUT /api/pages/d039b54a-ab1c-4341-a14a-70b1b1786118 200 in 898ms (compile: 865ms, proxy.ts: 8ms, render: 25ms) + GET /settings 200 in 208ms (compile: 182ms, proxy.ts: 5ms, render: 21ms) +prisma:query SELECT 1 +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 42ms (compile: 7ms, proxy.ts: 14ms, render: 21ms) +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 31ms (compile: 4ms, proxy.ts: 10ms, render: 17ms) +✓ Compiled in 180ms + GET /settings 200 in 116ms (compile: 64ms, proxy.ts: 5ms, render: 47ms) + GET /settings 200 in 38ms (compile: 4ms, proxy.ts: 5ms, render: 29ms) +✓ Compiled in 135ms + GET /settings 200 in 200ms (compile: 61ms, proxy.ts: 4ms, render: 135ms) +prisma:query SELECT 1 +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 38ms (compile: 4ms, proxy.ts: 8ms, render: 25ms) +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 23ms (compile: 3ms, proxy.ts: 9ms, render: 11ms) +✓ Compiled in 100ms +prisma:query SELECT 1 +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 20ms (compile: 3ms, proxy.ts: 5ms, render: 12ms) + GET /settings 200 in 92ms (compile: 69ms, proxy.ts: 6ms, render: 17ms) + GET / 200 in 129ms (compile: 101ms, proxy.ts: 6ms, render: 22ms) +prisma:query SELECT 1 +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 36ms (compile: 10ms, proxy.ts: 13ms, render: 14ms) +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 28ms (compile: 7ms, proxy.ts: 11ms, render: 10ms) +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 25ms (compile: 5ms, proxy.ts: 9ms, render: 11ms) +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 18ms (compile: 3ms, proxy.ts: 7ms, render: 8ms) +✓ Compiled in 455ms +✓ Compiled in 121ms +✓ Compiled in 87ms + GET /settings 200 in 76ms (compile: 57ms, proxy.ts: 5ms, render: 15ms) +prisma:query SELECT 1 +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 40ms (compile: 4ms, proxy.ts: 11ms, render: 26ms) +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 38ms (compile: 5ms, proxy.ts: 8ms, render: 25ms) + GET / 200 in 93ms (compile: 73ms, proxy.ts: 4ms, render: 17ms) +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 22ms (compile: 3ms, proxy.ts: 7ms, render: 12ms) +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 20ms (compile: 6ms, proxy.ts: 6ms, render: 8ms) +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 29ms (compile: 1969µs, proxy.ts: 4ms, render: 22ms) +prisma:query SELECT `main`.`Page`.`id`, `main`.`Page`.`title`, `main`.`Page`.`content`, `main`.`Page`.`tags`, `main`.`Page`.`icon`, `main`.`Page`.`type`, `main`.`Page`.`parentId`, `main`.`Page`.`createdAt`, `main`.`Page`.`updatedAt`, `main`.`Page`.`order`, `main`.`Page`.`isLocked` FROM `main`.`Page` WHERE 1=1 ORDER BY `main`.`Page`.`order` ASC, `main`.`Page`.`createdAt` DESC LIMIT ? OFFSET ? + GET /api/pages 200 in 28ms (compile: 1741µs, proxy.ts: 4ms, render: 22ms) diff --git a/prisma/dev.db b/prisma/dev.db index 9c2ae12..1c28709 100644 Binary files a/prisma/dev.db and b/prisma/dev.db differ diff --git a/src/app/globals.css b/src/app/globals.css index 18a69b1..67f0062 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -66,11 +66,95 @@ body { background-color: hsl(var(--background)); color: hsl(var(--foreground)); + background-image: + radial-gradient(circle at 10% 10%, hsl(var(--primary) / 0.05), transparent 35%), + radial-gradient(circle at 90% 0%, hsl(var(--accent-foreground) / 0.04), transparent 25%); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } } +@layer components { + .ui-card { + @apply rounded-2xl border border-border/70 bg-card/95 shadow-sm backdrop-blur-sm; + } + + .ui-input { + @apply w-full rounded-xl border border-input bg-background/75 px-3 py-2 text-sm outline-none transition-colors placeholder:text-muted-foreground focus:border-ring focus:ring-2 focus:ring-ring/20; + } + + .ui-select { + @apply w-full rounded-xl border border-input bg-background/75 px-3 py-2 text-sm outline-none transition-colors focus:border-ring focus:ring-2 focus:ring-ring/20; + } + + .ui-btn { + @apply inline-flex items-center justify-center gap-2 rounded-xl px-4 py-2 text-sm font-medium transition-all active:scale-[0.98]; + } + + .ui-btn-primary { + @apply ui-btn bg-primary text-primary-foreground hover:opacity-90 shadow-sm; + } + + .ui-btn-secondary { + @apply ui-btn bg-secondary text-secondary-foreground hover:bg-secondary/80; + } + + .ui-btn-danger { + @apply ui-btn bg-destructive text-destructive-foreground hover:opacity-90; + } + + .ui-icon-btn { + @apply inline-flex h-9 w-9 items-center justify-center rounded-lg border border-transparent text-muted-foreground transition-colors hover:border-border hover:bg-muted/60 hover:text-foreground; + } + + .ui-kbd { + @apply inline-flex h-5 select-none items-center gap-1 rounded border border-border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground; + } + + .ui-enter { + animation: ui-enter 220ms ease-out both; + } + + .ui-enter-delayed { + animation: ui-enter 300ms ease-out both; + } + + .ui-float { + animation: ui-float 4s ease-in-out infinite; + } +} + +@keyframes ui-enter { + from { + opacity: 0; + transform: translateY(6px) scale(0.99); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } +} + +@keyframes ui-float { + 0%, + 100% { + transform: translateY(0); + } + 50% { + transform: translateY(-4px); + } +} + +@media (prefers-reduced-motion: reduce) { + .ui-enter, + .ui-enter-delayed, + .ui-float, + .animate-in { + animation: none !important; + transition: none !important; + } +} + /* Editor Specific Styles for Notion-like feel */ .ProseMirror { outline: none; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index a7bb326..2ac2944 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,4 +1,4 @@ -import type { Metadata } from "next"; +import type { Metadata } from "next"; import { Inter } from "next/font/google"; import "./globals.css"; import { ThemeProvider } from "@/components/theme-provider"; @@ -7,8 +7,8 @@ import { ConfirmProvider } from "@/components/confirm-provider"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { - title: "NoteAI - 轻量级个人笔记网站", - description: "基于 Next.js 的 AI 驱动笔记应用", + title: "NoteAI - 轻量级个人笔记应用", + description: "基于 Next.js 的 AI 驱动笔记工具", }; export default function RootLayout({ @@ -19,12 +19,7 @@ export default function RootLayout({ return ( - + {children} diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index 8406200..eee5d14 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -39,9 +39,9 @@ export default function LoginPage() { return (
-
+
-
+

欢迎回来

@@ -57,7 +57,7 @@ export default function LoginPage() { placeholder="访问密码" value={password} onChange={(e) => setPassword(e.target.value)} - className="w-full pl-10 pr-4 py-3 bg-muted/50 border rounded-xl focus:ring-2 focus:ring-primary outline-none transition-all" + className="ui-input pl-10 pr-4 py-3" required />
@@ -79,7 +79,7 @@ export default function LoginPage() { updatePage(activePage.id, { title: e.target.value })} placeholder="无标题" disabled={activePage.isLocked} className={cn( - "w-full text-3xl font-bold bg-transparent border-none outline-none placeholder:text-muted-foreground/20 text-foreground transition-colors", - activePage.isLocked && "opacity-80 cursor-not-allowed select-none" + "w-full border-none bg-transparent text-3xl font-bold text-foreground outline-none placeholder:text-muted-foreground/30", + activePage.isLocked && "cursor-not-allowed select-none opacity-80" )} />
- - {/* Last Updated Info moved */} - -
- {/* Buttons moved to Editors Toolbar */} -
- {/* Tags Section */} -
+
{activePage.tags?.map((tag) => { const colors = getTagColor(tag); return ( @@ -119,151 +120,127 @@ export default function Home() { key={tag} onClick={() => openSearchWithTag(tag)} className={cn( - "inline-flex items-center gap-1 px-2.5 py-1 rounded-[3px] text-[11px] font-medium transition-colors border shadow-sm", - colors.bg, colors.text, colors.border - )}> + "group/tag inline-flex items-center gap-1 rounded-[4px] border px-2.5 py-1 text-[11px] font-medium shadow-sm", + colors.bg, + colors.text, + colors.border + )} + > {tag} ); })} -
- {isAddingTag ? ( - setTagInput(e.target.value)} - onBlur={() => { - if (tagInput.trim()) { - const newTags = [...(activePage.tags || []), tagInput.trim()]; - updatePage(activePage.id, { tags: Array.from(new Set(newTags)) }); - } + + {isAddingTag ? ( + setTagInput(e.target.value)} + onBlur={addTag} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.preventDefault(); + addTag(); + } + if (e.key === "Escape") { setTagInput(""); setIsAddingTag(false); - }} - onKeyDown={(e) => { - if (e.key === 'Enter') { - e.preventDefault(); - if (tagInput.trim()) { - const newTags = [...(activePage.tags || []), tagInput.trim()]; - updatePage(activePage.id, { tags: Array.from(new Set(newTags)) }); - } - setTagInput(""); - setIsAddingTag(false); - } - if (e.key === 'Escape') { - setTagInput(""); - setIsAddingTag(false); - } - }} - className="w-24 px-2 py-0.5 text-xs bg-transparent border border-primary rounded-sm outline-none animate-in fade-in zoom-in-95 duration-200" - placeholder="输入标签..." - /> - ) : ( -
- + } + }} + className="w-28 rounded-md border border-primary/40 bg-background px-2 py-1 text-xs outline-none focus:ring-2 focus:ring-primary/20" + placeholder="输入标签" + /> + ) : ( + + )} - {/* Icon Picker */} -
+
+ + {isIconPickerOpen && ( +
+
+ {ICONS.map((icon) => ( + + ))} -
-
- {[ - "📄", "📝", "📁", "📂", "📊", "📈", "📉", "📅", "✅", "❌", "📌", "📍", "📎", "🗑️", "⚙️", "🔒", - "✨", "💡", "🔥", "🚀", "🎨", "🎯", "🏆", "💎", "❤️", "👍", "👋", "🎉", "🌟", "⭐", "🌈", "⚡", - "🤖", "🧠", "💻", "⌨️", "📱", "⌚", "📷", "🎥", "🎧", "🎮", "🕹️", "🎲", "🧩", "🎳", "🥋", "🥊", - "🚗", "✈️", "🛸", "🌍", "🪐", "☀️", "🌙", "☁️", "🌧️", "❄️", "🌊", "💧", "🌀", - "🏠", "🏢", "🏥", "🏫", "🏰", "🏯", "⛺", "🏕️", "🌲", "🌳", "🌴", "🌵", "🌷", "🌸", "🌹", "🌻", - "🐶", "🐱", "🐭", "🐹", "🐰", "🦊", "🐻", "🐼", "🐨", "🐯", "🦁", "🐮", "🐷", "🐸", "🐵", "🐔", - "🍎", "🍌", "🍇", "🍉", "🍊", "🍋", "🍍", "🥭", "🍓", "🍒", "🍑", "🥝", "🍅", "🥑", "🍆", "🥔", - "🍔", "🍟", "🍕", "🌭", "🥪", "🌮", "🌯", "🥗", "🥘", "🍝", "🍜", "🍲", "🍛", "🍣", "🍱", "🥟", - "🍺", "🍻", "🥂", "🍷", "🥃", "🍸", "🍹", "🍾", "☕", "🍵", "🥤", "🧃", "🧊", "🥄", "🍴", "🍽️" - ].map(icon => ( - - ))} - -
-
- - {/* Lock Button */} - - - {/* Last Updated Info */} - {activePage.updatedAt && ( -
- - {new Date(activePage.updatedAt).toLocaleString('zh-CN', { - timeZone: useSettingsStore.getState().timezone || 'Asia/Shanghai', - hour12: false - })} - -
- )}
)}
+ + + + {activePage.updatedAt && ( +
+ {new Date(activePage.updatedAt).toLocaleString("zh-CN", { + timeZone: timezone || "Asia/Shanghai", + hour12: false, + })} +
+ )}
- {/* Editor Area or Folder Placeholder */} - {activePage.type === 'folder' ? ( -
- {/* ... folder icon ... */} + {activePage.type === "folder" ? ( +
+
+ +
+

当前是文件夹

+

你可以在左侧新建文档,或把文档拖拽到此文件夹。

) : (
@@ -280,17 +257,18 @@ export default function Home() {
) : ( -
-
- 👋 +
+
+ 🧠
-
+

欢迎使用 NoteAI

-

在左侧选择一个页面,或创建一个新页面开始写作。

+

在左侧选择一个页面,或新建文档开始写作。

)} + setIsChatOpen(false)} />
diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx index 55f01c9..1e2108e 100644 --- a/src/app/settings/page.tsx +++ b/src/app/settings/page.tsx @@ -66,12 +66,12 @@ export default function SettingsPage() {
-
+

设置

管理外观、AI、安全与备份。

-
+

外观设置

@@ -83,7 +83,7 @@ export default function SettingsPage() { setTimezone(e.target.value)} - className="w-full rounded-lg border bg-muted/40 px-3 py-2" + className="ui-select" > {timezoneOptions.map((opt) => (
-
+

AI 配置

@@ -162,7 +162,7 @@ export default function SettingsPage() { type="text" value={aiConfig.baseURL} onChange={(e) => setAIConfig({ baseURL: e.target.value })} - className="w-full rounded-lg border bg-muted/40 px-3 py-2" + className="ui-input" placeholder="https://api.openai.com/v1" /> @@ -173,7 +173,7 @@ export default function SettingsPage() { type="password" value={aiConfig.apiKey} onChange={(e) => setAIConfig({ apiKey: e.target.value })} - className="w-full rounded-lg border bg-muted/40 px-3 py-2" + className="ui-input" placeholder="sk-..." /> @@ -184,18 +184,18 @@ export default function SettingsPage() { type="text" value={aiConfig.model} onChange={(e) => setAIConfig({ model: e.target.value })} - className="w-full rounded-lg border bg-muted/40 px-3 py-2" + className="ui-input" placeholder="gpt-4o-mini" />
-
+
-
+

安全设置

@@ -206,7 +206,7 @@ export default function SettingsPage() { type="password" value={currentPassword} onChange={(e) => setCurrentPassword(e.target.value)} - className="w-full rounded-lg border bg-muted/40 px-3 py-2" + className="ui-input" placeholder="当前密码" required /> @@ -214,7 +214,7 @@ export default function SettingsPage() { type="password" value={newPassword} onChange={(e) => setNewPassword(e.target.value)} - className="w-full rounded-lg border bg-muted/40 px-3 py-2" + className="ui-input" placeholder="新密码" required /> @@ -222,7 +222,7 @@ export default function SettingsPage() { type="password" value={confirmPassword} onChange={(e) => setConfirmPassword(e.target.value)} - className="w-full rounded-lg border bg-muted/40 px-3 py-2" + className="ui-input" placeholder="确认新密码" required /> @@ -235,7 +235,7 @@ export default function SettingsPage() {
-
+

备份与恢复

恢复会覆盖当前全部文档,请谨慎操作。

@@ -254,13 +254,13 @@ export default function SettingsPage() { const { exportAllPagesAsZip } = await import("@/lib/export"); await exportAllPagesAsZip(pages); }} - className="inline-flex items-center justify-center gap-2 rounded-lg bg-secondary px-4 py-2 text-sm font-medium text-secondary-foreground hover:bg-secondary/80" + className="ui-btn-secondary" > 下载备份 (Zip) -