diff --git a/src/App.tsx b/src/App.tsx
index 7f80d5a..75f021c 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -2,7 +2,7 @@ import { useEffect } from 'react'
import { Sidebar } from './components/sidebar/Sidebar'
import { Editor } from './components/editor/Editor'
import { useAppStore } from './stores/appStore'
-import { seedIfEmpty } from './db'
+import { seedIfEmpty, deduplicateDB } from './db'
export default function App() {
const { loadAll, theme } = useAppStore()
@@ -12,7 +12,9 @@ export default function App() {
}, [theme])
useEffect(() => {
- seedIfEmpty().then(() => loadAll())
+ seedIfEmpty()
+ .then(() => deduplicateDB())
+ .then(() => loadAll())
}, [])
return (
diff --git a/src/components/editor/Editor.tsx b/src/components/editor/Editor.tsx
index 10cd16e..5ed3902 100644
--- a/src/components/editor/Editor.tsx
+++ b/src/components/editor/Editor.tsx
@@ -8,6 +8,7 @@ import TaskList from '@tiptap/extension-task-list'
import TaskItem from '@tiptap/extension-task-item'
import { Table } from '@tiptap/extension-table'
import TableRow from '@tiptap/extension-table-row'
+import { WelcomeView } from './WelcomeView'
import TableCell from '@tiptap/extension-table-cell'
import TableHeader from '@tiptap/extension-table-header'
import CharacterCount from '@tiptap/extension-character-count'
@@ -19,7 +20,7 @@ import {
Bold, Italic, Underline as UnderlineIcon, Strikethrough, Code,
Highlighter, List, ListOrdered, Quote,
Heading1, Heading2, Heading3, Minus, CheckSquare, Table as TableIcon,
- Type,
+ Type, Star,
} from 'lucide-react'
import { useAppStore } from '../../stores/appStore'
import { countWords } from '../../lib/utils'
@@ -66,7 +67,7 @@ function SlashMenu({ items, selectedIndex, onSelect }: {
}
export function Editor() {
- const { activeNoteId, notes, updateNote } = useAppStore()
+ const { activeNoteId, notes, updateNote, toggleStar } = useAppStore()
const activeNote = notes.find(n => n.id === activeNoteId)
const [title, setTitle] = useState(activeNote?.title ?? '')
@@ -219,28 +220,35 @@ export function Editor() {
}, 500)
}
- if (!activeNote) {
- return (
-
{/* Title */}
{/* Floating bubble menu rendered via portal */}
diff --git a/src/components/editor/WelcomeView.tsx b/src/components/editor/WelcomeView.tsx
new file mode 100644
index 0000000..f9c2975
--- /dev/null
+++ b/src/components/editor/WelcomeView.tsx
@@ -0,0 +1,176 @@
+import {
+ FileText, Folder, Slash, MousePointer, Save,
+ Search, Moon, Plus, Hash,
+} from 'lucide-react'
+import { useAppStore } from '../../stores/appStore'
+
+const FEATURES = [
+ {
+ icon:
,
+ title: '富文本编辑',
+ desc: '标题、列表、引用、代码块、表格、任务清单,应有尽有',
+ },
+ {
+ icon:
,
+ title: '斜杠命令',
+ desc: '输入 / 唤出命令菜单,用键盘快速插入任意内容块',
+ },
+ {
+ icon:
,
+ title: '浮动工具栏',
+ desc: '选中文字后浮现格式工具栏,点击即可加粗、高亮、转标题',
+ },
+ {
+ icon:
,
+ title: '自动保存',
+ desc: '停止输入 1 秒后自动写入本地 IndexedDB,无需手动保存',
+ },
+ {
+ icon:
,
+ title: '文件夹管理',
+ desc: '创建多级文件夹,右键可重命名或删除,拖拽随意整理',
+ },
+ {
+ icon:
,
+ title: '全文搜索',
+ desc: '侧边栏搜索框实时过滤笔记标题和标签',
+ },
+ {
+ icon:
,
+ title: '标签系统',
+ desc: '为笔记添加多个标签,跨文件夹快速定位相关内容',
+ },
+ {
+ icon:
,
+ title: '深色模式',
+ desc: '点击左上角图标一键切换亮色 / 暗色主题',
+ },
+]
+
+const SHORTCUTS = [
+ { keys: ['⌘', 'B'], desc: '粗体' },
+ { keys: ['⌘', 'I'], desc: '斜体' },
+ { keys: ['⌘', 'U'], desc: '下划线' },
+ { keys: ['⌘', 'Z'], desc: '撤销' },
+ { keys: ['/'], desc: '命令菜单' },
+]
+
+export function WelcomeView() {
+ const { createNote } = useAppStore()
+
+ return (
+
+
+
+ {/* Hero */}
+
+
+ ✏️
+
+
+ 欢迎使用笔记
+
+
+ 一款基于 Vite + React + TipTap 构建的现代笔记应用。
+
+ 点击左侧笔记开始阅读,或新建一篇属于你的笔记。
+
+
+
+
+ {/* Divider */}
+
+
+ {/* Features */}
+
+ 功能一览
+
+
+ {FEATURES.map(f => (
+
+
+ {f.icon}
+
+
{f.title}
+
{f.desc}
+
+ ))}
+
+
+ {/* Shortcuts */}
+
+ 常用快捷键
+
+
+ {SHORTCUTS.map((s, i) => (
+
0 ? '1px solid var(--border)' : 'none',
+ background: 'var(--bg-subtle)',
+ }}
+ >
+
{s.desc}
+
+ {s.keys.map(k => (
+
+ {k}
+
+ ))}
+
+
+ ))}
+
+
+
+
+ )
+}
diff --git a/src/components/sidebar/Sidebar.tsx b/src/components/sidebar/Sidebar.tsx
index f108a04..24e0690 100644
--- a/src/components/sidebar/Sidebar.tsx
+++ b/src/components/sidebar/Sidebar.tsx
@@ -2,18 +2,18 @@ import { useState, useRef, useEffect } from 'react'
import {
Search, Plus, Star, FileText, Folder, FolderOpen,
ChevronRight, ChevronDown,
- Trash2, Edit2, Moon, Sun, FolderPlus, Hash,
+ Trash2, Edit2, Moon, Sun, FolderPlus, Hash, BookOpen,
} from 'lucide-react'
import { useAppStore } from '../../stores/appStore'
import { formatDate } from '../../lib/utils'
-import type { Folder as FolderType } from '../../db'
+import type { Folder as FolderType, Note } from '../../db'
export function Sidebar() {
const {
notes, folders, activeNoteId, activeFolderId, searchQuery,
theme, createNote, createFolder, deleteNote, deleteFolder,
updateFolder, setActiveNote, setActiveFolder, setSearch,
- toggleTheme, filteredNotes,
+ toggleTheme, toggleStar, filteredNotes,
} = useAppStore()
const [expandedFolders, setExpandedFolders] = useState
>(new Set())
@@ -117,8 +117,9 @@ export function Sidebar() {
{/* Nav shortcuts */}
{/* Folders section */}
@@ -190,38 +191,18 @@ export function Sidebar() {
)}
{displayed.map(note => (
-