mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-29 05:51:26 +08:00
feat: add notes feature with sidebar integration
Introduces a new Notes page and integrates it into the sidebar and routing. Updates sidebar icon types, default icons, and migration logic to support the new 'notes' icon. Adds initial types for notes and folders, and provides a basic NotesPage component. Also updates Chinese locale for notes.
This commit is contained in:
parent
6bdb157af3
commit
e2d3d7357d
@ -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 {
|
||||
<Route path="/files" element={<FilesPage />} />
|
||||
<Route path="/knowledge" element={<KnowledgePage />} />
|
||||
<Route path="/apps" element={<AppsPage />} />
|
||||
<Route path="/notes" element={<NotesPage />} />
|
||||
<Route path="/settings/*" element={<SettingsPage />} />
|
||||
</Routes>
|
||||
</HashRouter>
|
||||
|
||||
@ -22,6 +22,7 @@ import {
|
||||
LayoutGrid,
|
||||
MessageSquare,
|
||||
Moon,
|
||||
NotepadText,
|
||||
Palette,
|
||||
Settings,
|
||||
Sparkle,
|
||||
@ -155,7 +156,8 @@ const MainMenus: FC = () => {
|
||||
translate: <Languages size={18} className="icon" />,
|
||||
minapp: <LayoutGrid size={18} className="icon" />,
|
||||
knowledge: <FileSearch size={18} className="icon" />,
|
||||
files: <Folder size={17} className="icon" />
|
||||
files: <Folder size={18} className="icon" />,
|
||||
notes: <NotepadText size={18} className="icon" />
|
||||
}
|
||||
|
||||
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) => {
|
||||
|
||||
@ -2558,6 +2558,9 @@
|
||||
"select_embedding_model_placeholder": "选择嵌入模型",
|
||||
"embedding_dimensions": "嵌入维度",
|
||||
"stored_memories": "已存储记忆"
|
||||
},
|
||||
"notes": {
|
||||
"title": "笔记"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
30
src/renderer/src/pages/notes/NotesPage.tsx
Normal file
30
src/renderer/src/pages/notes/NotesPage.tsx
Normal file
@ -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 (
|
||||
<Container id="notes-page">
|
||||
<Navbar>
|
||||
<NavbarCenter style={{ borderRight: 'none', gap: 10 }}>笔记</NavbarCenter>
|
||||
</Navbar>
|
||||
<ContentContainer>
|
||||
<h1>笔记页面</h1>
|
||||
<p>这里是笔记功能的内容区域。</p>
|
||||
</ContentContainer>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
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
|
||||
@ -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<SidebarIconsManagerProps> = ({
|
||||
translate: <Languages size={16} />,
|
||||
minapp: <LayoutGrid size={16} />,
|
||||
knowledge: <FileSearch size={16} />,
|
||||
files: <Folder size={15} />
|
||||
files: <Folder size={16} />,
|
||||
notes: <NotepadText size={16} />
|
||||
}),
|
||||
[]
|
||||
)
|
||||
@ -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`
|
||||
|
||||
@ -56,7 +56,7 @@ const persistedReducer = persistReducer(
|
||||
{
|
||||
key: 'cherry-studio',
|
||||
storage,
|
||||
version: 121,
|
||||
version: 122,
|
||||
blacklist: ['runtime', 'messages', 'messageBlocks'],
|
||||
migrate
|
||||
},
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 {}
|
||||
|
||||
@ -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[]
|
||||
|
||||
93
src/renderer/src/types/note.ts
Normal file
93
src/renderer/src/types/note.ts
Normal file
@ -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'
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user