Fix/newNode (#9727)

* feat: enhance note saving functionality with immediate cache invalidation

* fix: improve file name handling and localization updates

* feat: implement multi-level note sorting and enhance state management

- Introduced sorting options for notes by name, update time, and creation time, allowing users to sort notes in ascending and descending order.
- Updated NotesPage and NotesSidebar components to handle sorting functionality.
- Enhanced Redux store to manage the sorting type, improving state management for note organization.
- Refactored related services to support recursive sorting logic, ensuring a consistent user experience.

* feat(i18n): add new file upload messages for multiple languages

* fix(styles): adjust padding in richtext.scss to accommodate scrollbar

* style(NotesSidebar): add border-top-left-radius to enhance sidebar aesthetics

* feat(RichEditPopup): add isFullWidth prop to enhance popup layout

* feat(RichEditPopup): disable keyboard interaction for improved user experience

* feat(NotesPage): integrate sorting after node deletion and movement

- Added sorting functionality to be triggered after deleting or moving nodes, ensuring notes are organized immediately.
- Updated dependencies in useCallback hooks to include sortType for consistent behavior across operations.

* feat(NotesService): update initWorkSpace and sortAllLevels to accept sortType

- Modified initWorkSpace to include sortType for improved note organization during initialization.
- Enhanced sortAllLevels to optionally accept a tree parameter, allowing for more flexible sorting operations.
- Updated NotesPage to utilize the new parameters, ensuring consistent sorting behavior across various actions.

* feat(NotesSidebar): implement in-place editing for note renaming

- Introduced a new hook, useInPlaceEdit, to manage in-place editing of note names, enhancing user experience during renaming.
- Updated the NotesSidebar component to utilize this hook, streamlining the editing process and improving state management.
- Removed redundant state variables related to editing, simplifying the component's logic.

* refactor(NotesPage): remove commented code for clarity

- Removed a comment regarding folder selection behavior to streamline the code and improve readability.
- This change does not affect functionality but enhances the overall code quality.

* feat(NotesSettings): update initWorkSpace to include default sort type

- Modified initWorkSpace calls in NotesSettings to accept a default sort type of 'sort_a2z', ensuring consistent note organization during path updates and resets.
- This change enhances the initialization process by applying a predefined sorting method.
This commit is contained in:
SuYao 2025-08-31 21:53:53 +08:00 committed by GitHub
parent bf23c5b209
commit ce4cad67a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 198 additions and 80 deletions

View File

@ -311,8 +311,7 @@ export async function scanDir(dirPath: string, depth = 0, basePath?: string): Pr
*/
export function getName(baseDir: string, fileName: string, isFile: boolean): string {
// 首先清理文件名
const sanitizedName = sanitizeFilename(fileName)
const baseName = sanitizedName.replace(/\d+$/, '')
const baseName = sanitizeFilename(fileName)
let candidate = isFile ? baseName + '.md' : baseName
let counter = 1

View File

@ -1,5 +1,6 @@
.tiptap {
padding: 12px 60px;
// 预留5px给scrollbar
padding: 12px 55px 12px 60px;
outline: none;
min-height: 120px;
overflow-wrap: break-word;

View File

@ -97,6 +97,7 @@ const PopupContainer: React.FC<Props> = ({
afterClose={onClose}
afterOpenChange={handleAfterOpenChange}
maskClosable={false}
keyboard={false}
centered>
<EditorContainer>
<RichEditor
@ -108,6 +109,7 @@ const PopupContainer: React.FC<Props> = ({
onCommandsReady={handleCommandsReady}
minHeight={300}
maxHeight={500}
isFullWidth={true}
className="rich-edit-popup-editor"
/>
</EditorContainer>

View File

@ -1615,9 +1615,12 @@
"new_folder": "New Folder",
"new_note": "Create a new note",
"no_content_to_copy": "No content to copy",
"no_file_selected": "Please select the file to upload",
"only_markdown": "Only Markdown files are supported",
"only_one_file_allowed": "Only one file can be uploaded",
"open_folder": "Open an external folder",
"rename": "Rename",
"rename_changed": "Due to security policies, the filename has been changed from {{original}} to {{final}}",
"save": "Save to Notes",
"settings": {
"data": {

View File

@ -1615,9 +1615,12 @@
"new_folder": "新しいフォルダーを作成する",
"new_note": "新規ノート作成",
"no_content_to_copy": "コピーするコンテンツはありません",
"no_file_selected": "アップロードするファイルを選択してください",
"only_markdown": "Markdown ファイルのみをアップロードできます",
"only_one_file_allowed": "アップロードできるファイルは1つだけです",
"open_folder": "外部フォルダーを開きます",
"rename": "名前の変更",
"rename_changed": "セキュリティポリシーにより、ファイル名は{{original}}から{{final}}に変更されました",
"save": "メモに保存する",
"settings": {
"data": {

View File

@ -1615,9 +1615,12 @@
"new_folder": "Новая папка",
"new_note": "Создать заметку",
"no_content_to_copy": "Нет контента для копирования",
"no_file_selected": "Пожалуйста, выберите файл для загрузки",
"only_markdown": "Только Markdown",
"only_one_file_allowed": "Можно загрузить только один файл",
"open_folder": "Откройте внешнюю папку",
"rename": "переименовать",
"rename_changed": "В связи с политикой безопасности имя файла было изменено с {{Original}} на {{final}}",
"save": "Сохранить в заметки",
"settings": {
"data": {

View File

@ -1615,9 +1615,12 @@
"new_folder": "新建文件夹",
"new_note": "新建笔记",
"no_content_to_copy": "没有内容可复制",
"no_file_selected": "请选择要上传的文件",
"only_markdown": "仅支持 Markdown 格式",
"only_one_file_allowed": "只能上传一个文件",
"open_folder": "打开外部文件夹",
"rename": "重命名",
"rename_changed": "由于安全策略,文件名已从 {{original}} 更改为 {{final}}",
"save": "保存到笔记",
"settings": {
"data": {

View File

@ -1615,9 +1615,12 @@
"new_folder": "新建文件夾",
"new_note": "新建筆記",
"no_content_to_copy": "沒有內容可複制",
"no_file_selected": "請選擇要上傳的文件",
"only_markdown": "僅支援 Markdown 格式",
"only_one_file_allowed": "只能上傳一個文件",
"open_folder": "打開外部文件夾",
"rename": "重命名",
"rename_changed": "由於安全策略,文件名已從 {{original}} 更改為 {{final}}",
"save": "儲存到筆記",
"settings": {
"data": {

View File

@ -16,7 +16,7 @@ import {
} from '@renderer/services/NotesService'
import { getNotesTree, isParentNode, updateNodeInTree } from '@renderer/services/NotesTreeService'
import { useAppDispatch, useAppSelector } from '@renderer/store'
import { selectActiveFilePath, setActiveFilePath } from '@renderer/store/note'
import { selectActiveFilePath, selectSortType, setActiveFilePath, setSortType } from '@renderer/store/note'
import { NotesSortType, NotesTreeNode } from '@renderer/types/note'
import { FileChangeEvent } from '@shared/config/types'
import { useLiveQuery } from 'dexie-react-hooks'
@ -37,6 +37,7 @@ const NotesPage: FC = () => {
const { showWorkspace } = useSettings()
const dispatch = useAppDispatch()
const activeFilePath = useAppSelector(selectActiveFilePath)
const sortType = useAppSelector(selectSortType)
const { settings, notesPath, updateNotesPath } = useNotesSettings()
// 混合策略useLiveQuery用于笔记树React Query用于文件内容
@ -53,6 +54,8 @@ const NotesPage: FC = () => {
const isEditorInitialized = useRef(false)
const lastContentRef = useRef<string>('')
const isInitialSortApplied = useRef(false)
const isRenamingRef = useRef(false)
const isCreatingNoteRef = useRef(false)
useEffect(() => {
const updateCharCount = () => {
@ -131,7 +134,7 @@ const NotesPage: FC = () => {
async function applyInitialSort() {
if (notesTree.length > 0 && !isInitialSortApplied.current) {
try {
await sortAllLevels('sort_a2z')
await sortAllLevels(sortType)
isInitialSortApplied.current = true
} catch (error) {
logger.error('Failed to apply initial sorting:', error as Error)
@ -140,14 +143,21 @@ const NotesPage: FC = () => {
}
applyInitialSort()
}, [notesTree.length])
}, [notesTree.length, sortType])
// 处理树同步时的状态管理
useEffect(() => {
if (notesTree.length === 0) return
// 如果有activeFilePath但找不到对应节点清空选择
if (activeFilePath && !activeNode) {
// 但要排除正在同步树结构、重命名或创建笔记的情况,避免在这些操作中误清空
if (
activeFilePath &&
!activeNode &&
!isSyncingTreeRef.current &&
!isRenamingRef.current &&
!isCreatingNoteRef.current
) {
dispatch(setActiveFilePath(undefined))
}
}, [notesTree, activeFilePath, activeNode, dispatch])
@ -191,7 +201,7 @@ const NotesPage: FC = () => {
invalidateFileContent(filePath)
}
} else {
await initWorkSpace(notesPath)
await initWorkSpace(notesPath, sortType)
}
break
}
@ -210,7 +220,7 @@ const NotesPage: FC = () => {
// 重新同步数据库useLiveQuery会自动响应数据库变化
try {
await initWorkSpace(notesPath)
await initWorkSpace(notesPath, sortType)
} catch (error) {
logger.error('Failed to sync database:', error as Error)
} finally {
@ -264,7 +274,8 @@ const NotesPage: FC = () => {
dispatch,
currentContent,
debouncedSave,
saveCurrentNote
saveCurrentNote,
sortType
])
useEffect(() => {
@ -273,7 +284,7 @@ const NotesPage: FC = () => {
// 标记编辑器已初始化
isEditorInitialized.current = true
}
}, [currentContent])
}, [currentContent, activeFilePath])
// 切换文件时重置编辑器初始化状态并兜底保存
useEffect(() => {
@ -319,17 +330,27 @@ const NotesPage: FC = () => {
const handleCreateNote = useCallback(
async (name: string) => {
try {
isCreatingNoteRef.current = true
const targetPath = getTargetFolderPath()
if (!targetPath) {
throw new Error('No folder path selected')
}
const newNote = await createNote(name, '', targetPath)
dispatch(setActiveFilePath(newNote.externalPath))
setSelectedFolderId(null)
await sortAllLevels(sortType)
} catch (error) {
logger.error('Failed to create note:', error as Error)
} finally {
// 延迟重置标志,给数据库同步一些时间
setTimeout(() => {
isCreatingNoteRef.current = false
}, 500)
}
},
[dispatch, getTargetFolderPath]
[dispatch, getTargetFolderPath, sortType]
)
// 切换展开状态
@ -410,10 +431,7 @@ const NotesPage: FC = () => {
logger.error('Failed to load note:', error as Error)
}
} else if (node.type === 'folder') {
// 设置选中的文件夹,同时清除活动文件
setSelectedFolderId(node.id)
// 清除活动文件状态,这样文件的高亮会被清除
dispatch(setActiveFilePath(undefined))
await handleToggleExpanded(node.id)
}
},
@ -432,6 +450,7 @@ const NotesPage: FC = () => {
(nodeToDelete.externalPath === activeFilePath || isParentNode(notesTree, nodeId, activeNode?.id || ''))
await deleteNode(nodeId)
await sortAllLevels(sortType)
// 如果删除的是当前活动节点或其父节点,清空编辑器
if (isActiveNodeOrParent) {
@ -444,24 +463,47 @@ const NotesPage: FC = () => {
logger.error('Failed to delete node:', error as Error)
}
},
[activeFilePath, activeNode, notesTree, dispatch, findNodeById]
[findNodeById, notesTree, activeFilePath, activeNode?.id, sortType, dispatch]
)
// 重命名节点
const handleRenameNode = useCallback(
async (nodeId: string, newName: string) => {
try {
isRenamingRef.current = true
const tree = await getNotesTree()
const node = findNodeById(tree, nodeId)
if (node && node.name !== newName) {
await renameNode(nodeId, newName)
const oldExternalPath = node.externalPath
const renamedNode = await renameNode(nodeId, newName)
if (renamedNode.type === 'file' && activeFilePath === oldExternalPath) {
dispatch(setActiveFilePath(renamedNode.externalPath))
} else if (
renamedNode.type === 'folder' &&
activeFilePath &&
activeFilePath.startsWith(oldExternalPath + '/')
) {
const relativePath = activeFilePath.substring(oldExternalPath.length)
const newFilePath = renamedNode.externalPath + relativePath
dispatch(setActiveFilePath(newFilePath))
}
await sortAllLevels(sortType)
if (renamedNode.name !== newName) {
window.message.info(t('notes.rename_changed', { original: newName, final: renamedNode.name }))
}
}
} catch (error) {
logger.error('Failed to rename node:', error as Error)
} finally {
setTimeout(() => {
isRenamingRef.current = false
}, 500)
}
},
[findNodeById]
[activeFilePath, dispatch, findNodeById, sortType, t]
)
// 处理文件上传
@ -507,22 +549,28 @@ const NotesPage: FC = () => {
async (sourceNodeId: string, targetNodeId: string, position: 'before' | 'after' | 'inside') => {
try {
await moveNode(sourceNodeId, targetNodeId, position)
await sortAllLevels(sortType)
} catch (error) {
logger.error('Failed to move nodes:', error as Error)
}
},
[]
[sortType]
)
// 处理节点排序
const handleSortNodes = useCallback(async (sortType: NotesSortType) => {
try {
await sortAllLevels(sortType)
} catch (error) {
logger.error('Failed to sort notes:', error as Error)
throw error
}
}, [])
const handleSortNodes = useCallback(
async (newSortType: NotesSortType) => {
try {
// 更新Redux中的排序类型
dispatch(setSortType(newSortType))
await sortAllLevels(newSortType)
} catch (error) {
logger.error('Failed to sort notes:', error as Error)
throw error
}
},
[dispatch]
)
const getCurrentNoteContent = useCallback(() => {
if (settings.defaultEditMode === 'source') {

View File

@ -2,11 +2,14 @@ import { loggerService } from '@logger'
import { DeleteIcon } from '@renderer/components/Icons'
import SaveToKnowledgePopup from '@renderer/components/Popups/SaveToKnowledgePopup'
import Scrollbar from '@renderer/components/Scrollbar'
import { useInPlaceEdit } from '@renderer/hooks/useInPlaceEdit'
import { useKnowledgeBases } from '@renderer/hooks/useKnowledge'
import { useActiveNode } from '@renderer/hooks/useNotesQuery'
import NotesSidebarHeader from '@renderer/pages/notes/NotesSidebarHeader'
import { useAppSelector } from '@renderer/store'
import { selectSortType } from '@renderer/store/note'
import { NotesSortType, NotesTreeNode } from '@renderer/types/note'
import { Dropdown, Input, MenuProps } from 'antd'
import { Dropdown, Input, InputRef, MenuProps } from 'antd'
import {
ChevronDown,
ChevronRight,
@ -19,7 +22,7 @@ import {
Star,
StarOff
} from 'lucide-react'
import { FC, useCallback, useMemo, useRef, useState } from 'react'
import { FC, Ref, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
@ -57,8 +60,8 @@ const NotesSidebar: FC<NotesSidebarProps> = ({
const { t } = useTranslation()
const { bases } = useKnowledgeBases()
const { activeNode } = useActiveNode(notesTree)
const sortType = useAppSelector(selectSortType)
const [editingNodeId, setEditingNodeId] = useState<string | null>(null)
const [editingName, setEditingName] = useState('')
const [draggedNodeId, setDraggedNodeId] = useState<string | null>(null)
const [dragOverNodeId, setDragOverNodeId] = useState<string | null>(null)
const [dragPosition, setDragPosition] = useState<'before' | 'inside' | 'after'>('inside')
@ -66,8 +69,56 @@ const NotesSidebar: FC<NotesSidebarProps> = ({
const [isShowSearch, setIsShowSearch] = useState(false)
const [searchKeyword, setSearchKeyword] = useState('')
const [isDragOverSidebar, setIsDragOverSidebar] = useState(false)
const [sortType, setSortType] = useState<NotesSortType>('sort_a2z')
const dragNodeRef = useRef<HTMLDivElement | null>(null)
const scrollbarRef = useRef<any>(null)
const inPlaceEdit = useInPlaceEdit({
onSave: (newName: string) => {
if (editingNodeId && newName) {
onRenameNode(editingNodeId, newName)
logger.debug(`Renamed node ${editingNodeId} to "${newName}"`)
}
setEditingNodeId(null)
},
onCancel: () => {
setEditingNodeId(null)
}
})
// 滚动到活动节点
useEffect(() => {
if (activeNode?.id && !isShowStarred && !isShowSearch && scrollbarRef.current) {
// 延迟一下确保DOM已更新
setTimeout(() => {
const scrollContainer = scrollbarRef.current as HTMLElement
if (scrollContainer) {
const activeElement = scrollContainer.querySelector(`[data-node-id="${activeNode.id}"]`) as HTMLElement
if (activeElement) {
// 获取元素相对于滚动容器的位置
const containerHeight = scrollContainer.clientHeight
const elementOffsetTop = activeElement.offsetTop
const elementHeight = activeElement.offsetHeight
const currentScrollTop = scrollContainer.scrollTop
// 检查元素是否在可视区域内
const elementTop = elementOffsetTop
const elementBottom = elementOffsetTop + elementHeight
const viewTop = currentScrollTop
const viewBottom = currentScrollTop + containerHeight
// 如果元素不在可视区域内,滚动到中心位置
if (elementTop < viewTop || elementBottom > viewBottom) {
const targetScrollTop = elementOffsetTop - (containerHeight - elementHeight) / 2
scrollContainer.scrollTo({
top: Math.max(0, targetScrollTop),
behavior: 'smooth'
})
}
}
}
}, 200)
}
}, [activeNode?.id, isShowStarred, isShowSearch])
const handleCreateFolder = useCallback(() => {
onCreateFolder(t('notes.untitled_folder'))
@ -79,30 +130,18 @@ const NotesSidebar: FC<NotesSidebarProps> = ({
const handleSelectSortType = useCallback(
(selectedSortType: NotesSortType) => {
setSortType(selectedSortType)
onSortNodes(selectedSortType)
},
[onSortNodes]
)
const handleStartEdit = useCallback((node: NotesTreeNode) => {
setEditingNodeId(node.id)
setEditingName(node.name)
}, [])
const handleFinishEdit = useCallback(() => {
if (editingNodeId && editingName.trim()) {
onRenameNode(editingNodeId, editingName.trim())
}
setEditingNodeId(null)
setEditingName('')
logger.debug(`Renamed node ${editingNodeId} to "${editingName.trim()}"`)
}, [editingNodeId, editingName, onRenameNode])
const handleCancelEdit = useCallback(() => {
setEditingNodeId(null)
setEditingName('')
}, [])
const handleStartEdit = useCallback(
(node: NotesTreeNode) => {
setEditingNodeId(node.id)
inPlaceEdit.startEdit(node.name)
},
[inPlaceEdit]
)
const handleDeleteNode = useCallback(
(node: NotesTreeNode) => {
@ -306,8 +345,10 @@ const NotesSidebar: FC<NotesSidebarProps> = ({
const renderTreeNode = useCallback(
(node: NotesTreeNode, depth: number = 0) => {
const isActive = node.id === activeNode?.id || (node.type === 'folder' && node.id === selectedFolderId)
const isEditing = editingNodeId === node.id
const isActive = selectedFolderId
? node.type === 'folder' && node.id === selectedFolderId
: node.id === activeNode?.id
const isEditing = editingNodeId === node.id && inPlaceEdit.isEditing
const hasChildren = node.children && node.children.length > 0
const isDragging = draggedNodeId === node.id
const isDragOver = dragOverNodeId === node.id
@ -328,6 +369,7 @@ const NotesSidebar: FC<NotesSidebarProps> = ({
isDragInside={isDragInside}
isDragAfter={isDragAfter}
draggable={!isEditing}
data-node-id={node.id}
onDragStart={(e) => handleDragStart(e, node)}
onDragOver={(e) => handleDragOver(e, node)}
onDragLeave={handleDragLeave}
@ -361,15 +403,13 @@ const NotesSidebar: FC<NotesSidebarProps> = ({
{isEditing ? (
<EditInput
value={editingName}
onChange={(e) => setEditingName(e.target.value)}
onPressEnter={handleFinishEdit}
onBlur={handleFinishEdit}
onKeyDown={(e) => {
if (e.key === 'Escape') {
handleCancelEdit()
}
}}
ref={inPlaceEdit.inputRef as Ref<InputRef>}
value={inPlaceEdit.editValue}
onChange={inPlaceEdit.handleInputChange}
onPressEnter={inPlaceEdit.saveEdit}
onBlur={inPlaceEdit.saveEdit}
onKeyDown={inPlaceEdit.handleKeyDown}
onClick={(e) => e.stopPropagation()}
autoFocus
size="small"
/>
@ -388,24 +428,27 @@ const NotesSidebar: FC<NotesSidebarProps> = ({
)
},
[
activeNode,
selectedFolderId,
activeNode?.id,
editingNodeId,
editingName,
inPlaceEdit.isEditing,
inPlaceEdit.inputRef,
inPlaceEdit.editValue,
inPlaceEdit.handleInputChange,
inPlaceEdit.saveEdit,
inPlaceEdit.handleKeyDown,
draggedNodeId,
dragOverNodeId,
dragPosition,
onSelectNode,
onToggleExpanded,
handleFinishEdit,
handleCancelEdit,
getMenuItems,
handleDragLeave,
handleDragEnd,
t,
handleDragStart,
handleDragOver,
handleDragLeave,
handleDrop,
handleDragEnd,
getMenuItems,
t
onSelectNode,
onToggleExpanded
]
)
@ -451,7 +494,7 @@ const NotesSidebar: FC<NotesSidebarProps> = ({
/>
<NotesTreeContainer>
<StyledScrollbar>
<StyledScrollbar ref={scrollbarRef}>
<TreeContent>
{filteredTree.map((node) => renderTreeNode(node))}
{!isShowStarred && !isShowSearch && (
@ -480,6 +523,7 @@ const SidebarContainer = styled.div`
height: 100vh;
background-color: var(--color-background);
border-right: 1px solid var(--color-border);
border-top-left-radius: 10px;
display: flex;
flex-direction: column;
position: relative;

View File

@ -70,7 +70,7 @@ const NotesSettings: FC = () => {
}
updateNotesPath(tempPath)
initWorkSpace(tempPath)
initWorkSpace(tempPath, 'sort_a2z')
window.message.success(t('notes.settings.data.path_updated'))
} catch (error) {
logger.error('Failed to apply notes path:', error as Error)
@ -83,7 +83,7 @@ const NotesSettings: FC = () => {
const info = await window.api.getAppInfo()
setTempPath(info.notesPath)
updateNotesPath(info.notesPath)
initWorkSpace(info.notesPath)
initWorkSpace(info.notesPath, 'sort_a2z')
window.message.success(t('notes.settings.data.reset_to_default'))
} catch (error) {
logger.error('Failed to reset to default:', error as Error)

View File

@ -22,9 +22,9 @@ const logger = loggerService.withContext('NotesService')
/**
* /
*/
export async function initWorkSpace(folderPath: string): Promise<void> {
export async function initWorkSpace(folderPath: string, sortType: NotesSortType): Promise<void> {
const tree = await window.api.file.getDirectoryStructure(folderPath)
await db.notes_tree.put({ id: NOTES_TREE_ID, tree })
await sortAllLevels(sortType, tree)
}
/**
@ -326,9 +326,11 @@ function getSortFunction(sortType: NotesSortType): (a: NotesTreeNode, b: NotesTr
/**
*
*/
export async function sortAllLevels(sortType: NotesSortType): Promise<void> {
export async function sortAllLevels(sortType: NotesSortType, tree?: NotesTreeNode[]): Promise<void> {
try {
const tree = await getNotesTree()
if (!tree) {
tree = await getNotesTree()
}
sortNodesArray(tree, sortType)
recursiveSortNodes(tree, sortType)
await db.notes_tree.put({ id: NOTES_TREE_ID, tree })

View File

@ -1,6 +1,7 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { RootState } from '@renderer/store/index'
import { EditorView } from '@renderer/types'
import { NotesSortType } from '@renderer/types/note'
export interface NotesSettings {
isFullWidth: boolean
@ -15,6 +16,7 @@ export interface NoteState {
activeFilePath: string | undefined // 使用文件路径而不是nodeId
settings: NotesSettings
notesPath: string
sortType: NotesSortType
}
export const initialState: NoteState = {
@ -27,7 +29,8 @@ export const initialState: NoteState = {
defaultEditMode: 'preview',
showTabStatus: true
},
notesPath: ''
notesPath: '',
sortType: 'sort_a2z'
}
const noteSlice = createSlice({
@ -45,15 +48,19 @@ const noteSlice = createSlice({
},
setNotesPath: (state, action: PayloadAction<string>) => {
state.notesPath = action.payload
},
setSortType: (state, action: PayloadAction<NotesSortType>) => {
state.sortType = action.payload
}
}
})
export const { setActiveNodeId, setActiveFilePath, updateNotesSettings, setNotesPath } = noteSlice.actions
export const { setActiveNodeId, setActiveFilePath, updateNotesSettings, setNotesPath, setSortType } = noteSlice.actions
export const selectActiveNodeId = (state: RootState) => state.note.activeNodeId
export const selectActiveFilePath = (state: RootState) => state.note.activeFilePath
export const selectNotesSettings = (state: RootState) => state.note.settings
export const selectNotesPath = (state: RootState) => state.note.notesPath
export const selectSortType = (state: RootState) => state.note.sortType
export default noteSlice.reducer