diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx
index b46910cd65..4cd7703869 100644
--- a/src/renderer/src/App.tsx
+++ b/src/renderer/src/App.tsx
@@ -1,5 +1,6 @@
import '@renderer/databases'
+import NotesPage from '@renderer/pages/notes/NotesPage'
import store, { persistor } from '@renderer/store'
import { Provider } from 'react-redux'
import { HashRouter, Route, Routes } from 'react-router-dom'
@@ -43,6 +44,7 @@ function App(): React.ReactElement {
} />
} />
} />
+ } />
} />
diff --git a/src/renderer/src/components/app/Sidebar.tsx b/src/renderer/src/components/app/Sidebar.tsx
index 4e03cee5ff..95f2509183 100644
--- a/src/renderer/src/components/app/Sidebar.tsx
+++ b/src/renderer/src/components/app/Sidebar.tsx
@@ -22,6 +22,7 @@ import {
LayoutGrid,
MessageSquare,
Moon,
+ NotepadText,
Palette,
Settings,
Sparkle,
@@ -155,7 +156,8 @@ const MainMenus: FC = () => {
translate: ,
minapp: ,
knowledge: ,
- files:
+ files: ,
+ notes:
}
const pathMap = {
@@ -165,7 +167,8 @@ const MainMenus: FC = () => {
translate: '/translate',
minapp: '/apps',
knowledge: '/knowledge',
- files: '/files'
+ files: '/files',
+ notes: '/notes'
}
return sidebarIcons.visible.map((icon) => {
diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json
index f520aee3d7..1d1fe0242b 100644
--- a/src/renderer/src/i18n/locales/zh-cn.json
+++ b/src/renderer/src/i18n/locales/zh-cn.json
@@ -2558,6 +2558,9 @@
"select_embedding_model_placeholder": "选择嵌入模型",
"embedding_dimensions": "嵌入维度",
"stored_memories": "已存储记忆"
+ },
+ "notes": {
+ "title": "笔记"
}
}
}
diff --git a/src/renderer/src/pages/notes/NotesPage.tsx b/src/renderer/src/pages/notes/NotesPage.tsx
new file mode 100644
index 0000000000..075c1be69d
--- /dev/null
+++ b/src/renderer/src/pages/notes/NotesPage.tsx
@@ -0,0 +1,30 @@
+import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar'
+import { FC } from 'react'
+import styled from 'styled-components'
+
+const NotesPage: FC = () => {
+ return (
+
+
+ 笔记
+
+
+ 笔记页面
+ 这里是笔记功能的内容区域。
+
+
+ )
+}
+
+const Container = styled.div`
+ flex: 1;
+`
+
+const ContentContainer = styled.div`
+ height: calc(100vh - var(--navbar-height));
+ display: flex;
+ flex-direction: column;
+ padding: 20px;
+`
+
+export default NotesPage
diff --git a/src/renderer/src/pages/settings/DisplaySettings/SidebarIconsManager.tsx b/src/renderer/src/pages/settings/DisplaySettings/SidebarIconsManager.tsx
index 89aa11ca4b..b87fe13506 100644
--- a/src/renderer/src/pages/settings/DisplaySettings/SidebarIconsManager.tsx
+++ b/src/renderer/src/pages/settings/DisplaySettings/SidebarIconsManager.tsx
@@ -10,7 +10,16 @@ import {
import { useAppDispatch } from '@renderer/store'
import { setSidebarIcons } from '@renderer/store/settings'
import { message } from 'antd'
-import { FileSearch, Folder, Languages, LayoutGrid, MessageSquareQuote, Palette, Sparkle } from 'lucide-react'
+import {
+ FileSearch,
+ Folder,
+ Languages,
+ LayoutGrid,
+ MessageSquareQuote,
+ NotepadText,
+ Palette,
+ Sparkle
+} from 'lucide-react'
import { FC, useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
@@ -115,7 +124,8 @@ const SidebarIconsManager: FC = ({
translate: ,
minapp: ,
knowledge: ,
- files:
+ files: ,
+ notes:
}),
[]
)
@@ -213,7 +223,7 @@ const IconList = styled.div`
border: 1px solid var(--color-border);
display: flex;
flex-direction: column;
- overflow-y: hidden;
+ overflow-y: auto;
`
const IconItem = styled.div`
diff --git a/src/renderer/src/store/index.ts b/src/renderer/src/store/index.ts
index bbb2c7378d..5f8c1d84eb 100644
--- a/src/renderer/src/store/index.ts
+++ b/src/renderer/src/store/index.ts
@@ -56,7 +56,7 @@ const persistedReducer = persistReducer(
{
key: 'cherry-studio',
storage,
- version: 121,
+ version: 122,
blacklist: ['runtime', 'messages', 'messageBlocks'],
migrate
},
diff --git a/src/renderer/src/store/migrate.ts b/src/renderer/src/store/migrate.ts
index 71990b05b5..76668c547a 100644
--- a/src/renderer/src/store/migrate.ts
+++ b/src/renderer/src/store/migrate.ts
@@ -1812,6 +1812,15 @@ const migrateConfig = {
} catch (error) {
return state
}
+ },
+ '122': (state: RootState) => {
+ if (state.settings && state.settings.sidebarIcons) {
+ // Check if 'notes' is not already in visible icons
+ if (!state.settings.sidebarIcons.visible.includes('notes' as any)) {
+ state.settings.sidebarIcons.visible = [...state.settings.sidebarIcons.visible, 'notes' as any]
+ }
+ }
+ return state
}
}
diff --git a/src/renderer/src/store/settings.ts b/src/renderer/src/store/settings.ts
index 1d30d9d9fa..607a83ca43 100644
--- a/src/renderer/src/store/settings.ts
+++ b/src/renderer/src/store/settings.ts
@@ -19,7 +19,15 @@ import { RemoteSyncState } from './backup'
export type SendMessageShortcut = 'Enter' | 'Shift+Enter' | 'Ctrl+Enter' | 'Command+Enter' | 'Alt+Enter'
-export type SidebarIcon = 'assistants' | 'agents' | 'paintings' | 'translate' | 'minapp' | 'knowledge' | 'files'
+export type SidebarIcon =
+ | 'assistants'
+ | 'agents'
+ | 'paintings'
+ | 'translate'
+ | 'minapp'
+ | 'knowledge'
+ | 'files'
+ | 'notes'
export const DEFAULT_SIDEBAR_ICONS: SidebarIcon[] = [
'assistants',
@@ -28,7 +36,8 @@ export const DEFAULT_SIDEBAR_ICONS: SidebarIcon[] = [
'translate',
'minapp',
'knowledge',
- 'files'
+ 'files',
+ 'notes'
]
export interface NutstoreSyncRuntime extends RemoteSyncState {}
diff --git a/src/renderer/src/types/index.ts b/src/renderer/src/types/index.ts
index 633a17dd1d..9783a5a184 100644
--- a/src/renderer/src/types/index.ts
+++ b/src/renderer/src/types/index.ts
@@ -525,7 +525,15 @@ export interface TranslateHistory {
createdAt: string
}
-export type SidebarIcon = 'assistants' | 'agents' | 'paintings' | 'translate' | 'minapp' | 'knowledge' | 'files'
+export type SidebarIcon =
+ | 'assistants'
+ | 'agents'
+ | 'paintings'
+ | 'translate'
+ | 'minapp'
+ | 'knowledge'
+ | 'files'
+ | 'notes'
export type ExternalToolResult = {
mcpTools?: MCPTool[]
diff --git a/src/renderer/src/types/note.ts b/src/renderer/src/types/note.ts
new file mode 100644
index 0000000000..54c75f1571
--- /dev/null
+++ b/src/renderer/src/types/note.ts
@@ -0,0 +1,93 @@
+export type NoteType = 'note' | 'folder'
+
+export interface Note {
+ id: string
+ title: string
+ content: string
+ type: NoteType
+ parentId?: string // For folder hierarchy
+ tags?: string[]
+ created_at: number
+ updated_at: number
+ isStarred?: boolean
+ isArchived?: boolean
+ wordCount?: number
+ readingTime?: number // in minutes
+ metadata?: {
+ lastCursorPosition?: number
+ isFullscreen?: boolean
+ fontSize?: number
+ theme?: string
+ }
+}
+
+export interface NoteFolder {
+ id: string
+ name: string
+ type: 'folder'
+ parentId?: string
+ created_at: number
+ updated_at: number
+ isExpanded?: boolean
+ color?: string
+}
+
+export interface NoteFilter {
+ search?: string
+ tags?: string[]
+ isStarred?: boolean
+ isArchived?: boolean
+ parentId?: string
+ dateRange?: {
+ start: number
+ end: number
+ }
+}
+
+export interface NoteSortOption {
+ field: 'title' | 'created_at' | 'updated_at' | 'wordCount'
+ order: 'asc' | 'desc'
+}
+
+export interface NoteExportOptions {
+ format: 'markdown' | 'html' | 'pdf' | 'json'
+ includeMetadata?: boolean
+ includeTags?: boolean
+ includeArchived?: boolean
+}
+
+export interface NoteImportOptions {
+ format: 'markdown' | 'html' | 'json'
+ targetFolderId?: string
+ preserveStructure?: boolean
+ mergeTags?: boolean
+}
+
+export interface NoteStats {
+ totalNotes: number
+ totalFolders: number
+ totalWords: number
+ totalReadingTime: number
+ recentActivity: {
+ date: string
+ count: number
+ }[]
+}
+
+export interface NoteEditorConfig {
+ theme: 'light' | 'dark' | 'auto'
+ fontSize: number
+ fontFamily: string
+ lineHeight: number
+ tabSize: number
+ wordWrap: boolean
+ showLineNumbers: boolean
+ enableVim: boolean
+ enableEmmet: boolean
+ autoSave: boolean
+ autoSaveInterval: number // in milliseconds
+ spellCheck: boolean
+ typewriterMode: boolean
+ focusMode: boolean
+ previewMode: 'split' | 'preview' | 'source'
+}
\ No newline at end of file