Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
matrix-editor
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wanjia
matrix-editor
Commits
304fdc2c
Commit
304fdc2c
authored
Dec 17, 2024
by
wanjia
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
迭代一版
parent
b5b01eb1
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
305 additions
and
55 deletions
+305
-55
electron/preload.js
+3
-3
src/App.tsx
+32
-1
src/components/ConfirmDialog.css
+66
-0
src/components/ConfirmDialog.tsx
+39
-0
src/components/Sidebar.css
+37
-14
src/components/Sidebar.tsx
+128
-37
No files found.
electron/preload.js
View file @
304fdc2c
...
@@ -3,13 +3,13 @@ const { contextBridge, ipcRenderer } = require('electron');
...
@@ -3,13 +3,13 @@ const { contextBridge, ipcRenderer } = require('electron');
// 暴露安全的 API 到渲染进程
// 暴露安全的 API 到渲染进程
contextBridge
.
exposeInMainWorld
(
'electronAPI'
,
{
contextBridge
.
exposeInMainWorld
(
'electronAPI'
,
{
// 文件系统操作
// 文件系统操作
getGroups
:
()
=>
ipcRenderer
.
invoke
(
'get-groups'
),
createGroup
:
(
groupName
)
=>
ipcRenderer
.
invoke
(
'create-group'
,
groupName
),
createGroup
:
(
groupName
)
=>
ipcRenderer
.
invoke
(
'create-group'
,
groupName
),
deleteGroup
:
(
groupId
)
=>
ipcRenderer
.
invoke
(
'delete-group'
,
groupId
),
deleteGroup
:
(
groupId
)
=>
ipcRenderer
.
invoke
(
'delete-group'
,
groupId
),
createFile
:
(
groupId
,
fileName
)
=>
ipcRenderer
.
invoke
(
'create-file'
,
groupId
,
fileName
),
createFile
:
(
groupId
,
fileName
)
=>
ipcRenderer
.
invoke
(
'create-file'
,
groupId
,
fileName
),
deleteFile
:
(
groupId
,
fileId
)
=>
ipcRenderer
.
invoke
(
'delete-file'
,
groupId
,
fileId
),
deleteFile
:
(
groupId
,
fileId
)
=>
ipcRenderer
.
invoke
(
'delete-file'
,
groupId
,
fileId
),
saveFile
:
(
fileId
,
content
)
=>
ipcRenderer
.
invoke
(
'save-file'
,
fileId
,
content
),
loadFile
:
(
fileId
)
=>
ipcRenderer
.
invoke
(
'load-file-content'
,
fileId
),
loadFile
:
(
fileId
)
=>
ipcRenderer
.
invoke
(
'load-file'
,
fileId
),
saveFile
:
(
fileId
,
content
)
=>
ipcRenderer
.
invoke
(
'save-file-content'
,
fileId
,
content
),
getGroups
:
()
=>
ipcRenderer
.
invoke
(
'get-groups'
),
// 系统信息
// 系统信息
platform
:
process
.
platform
platform
:
process
.
platform
...
...
src/App.tsx
View file @
304fdc2c
...
@@ -27,11 +27,19 @@ import './components/Sidebar.css';
...
@@ -27,11 +27,19 @@ import './components/Sidebar.css';
type
ViewMode
=
'split'
|
'edit'
|
'preview'
;
type
ViewMode
=
'split'
|
'edit'
|
'preview'
;
interface
Document
{
id
:
string
;
groupId
:
string
;
name
:
string
;
content
:
string
;
}
const
App
:
React
.
FC
=
()
=>
{
const
App
:
React
.
FC
=
()
=>
{
const
editorRef
=
useRef
<
any
>
(
null
);
const
editorRef
=
useRef
<
any
>
(
null
);
const
[
markdown
,
setMarkdown
]
=
useState
<
string
>
(
''
);
const
[
markdown
,
setMarkdown
]
=
useState
<
string
>
(
''
);
const
[
viewMode
,
setViewMode
]
=
useState
<
ViewMode
>
(
'split'
);
const
[
viewMode
,
setViewMode
]
=
useState
<
ViewMode
>
(
'split'
);
const
[
isSidebarOpen
,
setIsSidebarOpen
]
=
useState
(
true
);
const
[
isSidebarOpen
,
setIsSidebarOpen
]
=
useState
(
true
);
const
[
currentDocument
,
setCurrentDocument
]
=
useState
<
Document
|
null
>
(
null
);
const
handleEditorDidMount
=
(
editor
:
any
)
=>
{
const
handleEditorDidMount
=
(
editor
:
any
)
=>
{
editorRef
.
current
=
editor
;
editorRef
.
current
=
editor
;
...
@@ -39,6 +47,9 @@ const App: React.FC = () => {
...
@@ -39,6 +47,9 @@ const App: React.FC = () => {
const
handleEditorChange
=
(
value
:
string
|
undefined
)
=>
{
const
handleEditorChange
=
(
value
:
string
|
undefined
)
=>
{
setMarkdown
(
value
||
''
);
setMarkdown
(
value
||
''
);
if
(
currentDocument
)
{
window
.
electronAPI
.
saveFile
(
currentDocument
.
id
,
value
||
''
);
}
};
};
const
insertAtCursor
=
(
before
:
string
,
after
:
string
=
''
)
=>
{
const
insertAtCursor
=
(
before
:
string
,
after
:
string
=
''
)
=>
{
...
@@ -110,13 +121,33 @@ const App: React.FC = () => {
...
@@ -110,13 +121,33 @@ const App: React.FC = () => {
}
}
},
[]);
},
[]);
const
handleDocumentSelect
=
async
(
groupId
:
string
,
fileId
:
string
)
=>
{
try
{
const
content
=
await
window
.
electronAPI
.
loadFile
(
fileId
);
setCurrentDocument
({
id
:
fileId
,
groupId
,
name
:
''
,
// 这个值会从 Sidebar 组件传过来
content
});
setMarkdown
(
content
);
}
catch
(
error
)
{
console
.
error
(
'Failed to load document:'
,
error
);
}
};
const
toggleSidebar
=
()
=>
{
const
toggleSidebar
=
()
=>
{
setIsSidebarOpen
(
!
isSidebarOpen
);
setIsSidebarOpen
(
!
isSidebarOpen
);
};
};
return
(
return
(
<
div
className=
"app"
>
<
div
className=
"app"
>
<
Sidebar
isOpen=
{
isSidebarOpen
}
onToggle=
{
()
=>
setIsSidebarOpen
(
!
isSidebarOpen
)
}
/>
<
Sidebar
isOpen=
{
isSidebarOpen
}
onToggle=
{
()
=>
setIsSidebarOpen
(
!
isSidebarOpen
)
}
onDocumentSelect=
{
handleDocumentSelect
}
currentDocumentId=
{
currentDocument
?.
id
}
/>
<
div
className=
"main-content"
>
<
div
className=
"main-content"
>
<
div
className=
"toolbar"
>
<
div
className=
"toolbar"
>
<
div
className=
"toolbar-group"
>
<
div
className=
"toolbar-group"
>
...
...
src/components/ConfirmDialog.css
0 → 100644
View file @
304fdc2c
.confirm-dialog-overlay
{
position
:
fixed
;
top
:
0
;
left
:
0
;
right
:
0
;
bottom
:
0
;
background-color
:
rgba
(
0
,
0
,
0
,
0.5
);
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
z-index
:
1000
;
}
.confirm-dialog
{
background-color
:
#fff
;
border-radius
:
8px
;
padding
:
24px
;
width
:
400px
;
max-width
:
90%
;
box-shadow
:
0
4px
12px
rgba
(
0
,
0
,
0
,
0.15
);
}
.confirm-dialog-title
{
margin
:
0
0
16px
0
;
font-size
:
1.25rem
;
color
:
#333
;
}
.confirm-dialog-message
{
margin
:
0
0
24px
0
;
color
:
#666
;
line-height
:
1.5
;
}
.confirm-dialog-actions
{
display
:
flex
;
justify-content
:
flex-end
;
gap
:
12px
;
}
.confirm-dialog-button
{
padding
:
8px
16px
;
border
:
none
;
border-radius
:
4px
;
font-size
:
14px
;
cursor
:
pointer
;
transition
:
background-color
0.2s
;
}
.confirm-dialog-button.cancel
{
background-color
:
#f5f5f5
;
color
:
#333
;
}
.confirm-dialog-button.cancel
:hover
{
background-color
:
#e8e8e8
;
}
.confirm-dialog-button.confirm
{
background-color
:
#dc3545
;
color
:
white
;
}
.confirm-dialog-button.confirm
:hover
{
background-color
:
#c82333
;
}
src/components/ConfirmDialog.tsx
0 → 100644
View file @
304fdc2c
import
React
from
'react'
;
import
'./ConfirmDialog.css'
;
interface
ConfirmDialogProps
{
isOpen
:
boolean
;
title
:
string
;
message
:
string
;
onConfirm
:
()
=>
void
;
onCancel
:
()
=>
void
;
}
const
ConfirmDialog
:
React
.
FC
<
ConfirmDialogProps
>
=
({
isOpen
,
title
,
message
,
onConfirm
,
onCancel
,
})
=>
{
if
(
!
isOpen
)
return
null
;
return
(
<
div
className=
"confirm-dialog-overlay"
>
<
div
className=
"confirm-dialog"
>
<
h3
className=
"confirm-dialog-title"
>
{
title
}
</
h3
>
<
p
className=
"confirm-dialog-message"
>
{
message
}
</
p
>
<
div
className=
"confirm-dialog-actions"
>
<
button
className=
"confirm-dialog-button cancel"
onClick=
{
onCancel
}
>
Cancel
</
button
>
<
button
className=
"confirm-dialog-button confirm"
onClick=
{
onConfirm
}
>
Confirm
</
button
>
</
div
>
</
div
>
</
div
>
);
};
export
default
ConfirmDialog
;
src/components/Sidebar.css
View file @
304fdc2c
...
@@ -61,44 +61,67 @@
...
@@ -61,44 +61,67 @@
}
}
.group
{
.group
{
margin
-bottom
:
10px
;
margin
:
8px
0
;
}
}
.group-header
{
.group-header
{
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
justify-content
:
space-between
;
justify-content
:
space-between
;
padding
:
6px
8
px
;
padding
:
8px
12
px
;
background-color
:
#e8e8e8
;
cursor
:
pointer
;
border-radius
:
4px
;
border-radius
:
4px
;
margin-bottom
:
4px
;
transition
:
background-color
0.2s
;
}
.group-header
:hover
{
background-color
:
rgba
(
255
,
255
,
255
,
0.1
);
}
}
.group-name
{
.group-name
{
font-weight
:
500
;
color
:
#333
;
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
gap
:
6px
;
gap
:
8px
;
font-weight
:
500
;
}
}
.group-actions
{
.group-toggle-icon
{
display
:
flex
;
width
:
12px
;
gap
:
4px
;
height
:
12px
;
transition
:
transform
0.2s
;
}
.group-files
{
margin-left
:
16px
;
transition
:
max-height
0.3s
ease-out
,
opacity
0.2s
ease-out
;
max-height
:
1000px
;
opacity
:
1
;
overflow
:
hidden
;
}
.group-files.collapsed
{
max-height
:
0
;
opacity
:
0
;
}
}
.file-item
{
.file-item
{
display
:
flex
;
display
:
flex
;
align-items
:
center
;
align-items
:
center
;
justify-content
:
space-between
;
justify-content
:
space-between
;
padding
:
4px
8px
;
padding
:
8px
12px
;
margin-left
:
8px
;
margin
:
2px
0
;
border-radius
:
4px
;
cursor
:
pointer
;
cursor
:
pointer
;
border-radius
:
4px
;
transition
:
background-color
0.2s
;
}
}
.file-item
:hover
{
.file-item
:hover
{
background-color
:
#e8e8e8
;
background-color
:
rgba
(
255
,
255
,
255
,
0.1
);
}
.file-item.active
{
background-color
:
rgba
(
255
,
255
,
255
,
0.15
);
font-weight
:
500
;
}
}
.file-name
{
.file-name
{
...
...
src/components/Sidebar.tsx
View file @
304fdc2c
import
React
,
{
useState
,
useEffect
}
from
'react'
;
import
React
,
{
useState
,
useEffect
}
from
'react'
;
import
{
FontAwesomeIcon
}
from
'@fortawesome/react-fontawesome'
;
import
{
import
{
faChevronLeft
,
faChevronLeft
,
faChevronRight
,
faChevronRight
,
faChevronDown
,
faFolder
,
faFolder
,
faFolderPlus
,
faFolderPlus
,
faFile
,
faFile
,
faPlus
,
faPlus
,
faTrash
faTrash
}
from
'@fortawesome/free-solid-svg-icons'
;
}
from
'@fortawesome/free-solid-svg-icons'
;
import
{
FontAwesomeIcon
}
from
'@fortawesome/react-fontawesome'
;
import
'./Sidebar.css'
;
import
'./Sidebar.css'
;
import
ConfirmDialog
from
'./ConfirmDialog'
;
interface
SidebarProps
{
interface
SidebarProps
{
isOpen
:
boolean
;
isOpen
:
boolean
;
onToggle
:
()
=>
void
;
onToggle
:
()
=>
void
;
onDocumentSelect
:
(
groupId
:
string
,
fileId
:
string
)
=>
void
;
currentDocumentId
:
string
|
undefined
;
}
}
interface
Group
{
interface
Group
{
...
@@ -28,12 +32,25 @@ interface File {
...
@@ -28,12 +32,25 @@ interface File {
content
:
string
;
content
:
string
;
}
}
const
Sidebar
:
React
.
FC
<
SidebarProps
>
=
({
isOpen
,
onToggle
})
=>
{
const
Sidebar
:
React
.
FC
<
SidebarProps
>
=
({
isOpen
,
onToggle
,
onDocumentSelect
,
currentDocumentId
})
=>
{
const
[
groups
,
setGroups
]
=
useState
<
Group
[]
>
([]);
const
[
groups
,
setGroups
]
=
useState
<
Group
[]
>
([]);
const
[
showNewGroupForm
,
setShowNewGroupForm
]
=
useState
(
false
);
const
[
showNewGroupForm
,
setShowNewGroupForm
]
=
useState
(
false
);
const
[
newGroupName
,
setNewGroupName
]
=
useState
(
''
);
const
[
newGroupName
,
setNewGroupName
]
=
useState
(
''
);
const
[
showNewFileForm
,
setShowNewFileForm
]
=
useState
<
string
|
null
>
(
null
);
const
[
showNewFileForm
,
setShowNewFileForm
]
=
useState
<
string
|
null
>
(
null
);
const
[
newFileName
,
setNewFileName
]
=
useState
(
''
);
const
[
newFileName
,
setNewFileName
]
=
useState
(
''
);
const
[
collapsedGroups
,
setCollapsedGroups
]
=
useState
<
Set
<
string
>>
(
new
Set
());
const
[
deleteConfirm
,
setDeleteConfirm
]
=
useState
<
{
type
:
'group'
|
'file'
;
groupId
:
string
;
fileId
?:
string
;
name
:
string
;
isOpen
:
boolean
;
}
|
null
>
(
null
);
useEffect
(()
=>
{
useEffect
(()
=>
{
// 从后端加载组和文件
// 从后端加载组和文件
...
@@ -55,12 +72,15 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle }) => {
...
@@ -55,12 +72,15 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle }) => {
};
};
const
handleDeleteGroup
=
async
(
groupId
:
string
)
=>
{
const
handleDeleteGroup
=
async
(
groupId
:
string
)
=>
{
try
{
const
group
=
groups
.
find
(
g
=>
g
.
id
===
groupId
);
await
window
.
electronAPI
.
deleteGroup
(
groupId
);
if
(
!
group
)
return
;
setGroups
(
groups
.
filter
(
group
=>
group
.
id
!==
groupId
));
}
catch
(
error
)
{
setDeleteConfirm
({
console
.
error
(
'Failed to delete group:'
,
error
);
type
:
'group'
,
}
groupId
,
name
:
group
.
name
,
isOpen
:
true
});
};
};
const
handleCreateFile
=
async
(
groupId
:
string
)
=>
{
const
handleCreateFile
=
async
(
groupId
:
string
)
=>
{
...
@@ -78,26 +98,64 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle }) => {
...
@@ -78,26 +98,64 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle }) => {
}));
}));
setNewFileName
(
''
);
setNewFileName
(
''
);
setShowNewFileForm
(
null
);
setShowNewFileForm
(
null
);
// 创建后自动选择新文件
onDocumentSelect
(
groupId
,
newFile
.
id
);
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
error
(
'Failed to create file:'
,
error
);
console
.
error
(
'Failed to create file:'
,
error
);
}
}
};
};
const
handleDeleteFile
=
async
(
groupId
:
string
,
fileId
:
string
)
=>
{
const
handleDeleteFile
=
async
(
groupId
:
string
,
fileId
:
string
)
=>
{
const
group
=
groups
.
find
(
g
=>
g
.
id
===
groupId
);
const
file
=
group
?.
files
.
find
(
f
=>
f
.
id
===
fileId
);
if
(
!
group
||
!
file
)
return
;
setDeleteConfirm
({
type
:
'file'
,
groupId
,
fileId
,
name
:
file
.
name
,
isOpen
:
true
});
};
const
confirmDelete
=
async
()
=>
{
if
(
!
deleteConfirm
)
return
;
try
{
try
{
await
window
.
electronAPI
.
deleteFile
(
groupId
,
fileId
);
if
(
deleteConfirm
.
type
===
'group'
)
{
setGroups
(
groups
.
map
(
group
=>
{
await
window
.
electronAPI
.
deleteGroup
(
deleteConfirm
.
groupId
);
if
(
group
.
id
===
groupId
)
{
setGroups
(
groups
.
filter
(
g
=>
g
.
id
!==
deleteConfirm
.
groupId
));
return
{
}
else
{
...
group
,
if
(
!
deleteConfirm
.
fileId
)
return
;
files
:
group
.
files
.
filter
(
file
=>
file
.
id
!==
fileId
)
await
window
.
electronAPI
.
deleteFile
(
deleteConfirm
.
groupId
,
deleteConfirm
.
fileId
);
};
setGroups
(
groups
.
map
(
group
=>
{
}
if
(
group
.
id
===
deleteConfirm
.
groupId
)
{
return
group
;
return
{
}));
...
group
,
}
catch
(
error
)
{
files
:
group
.
files
.
filter
(
f
=>
f
.
id
!==
deleteConfirm
.
fileId
)
console
.
error
(
'Failed to delete file:'
,
error
);
};
}
return
group
;
}));
}
}
catch
(
err
)
{
console
.
error
(
`Failed to delete
${
deleteConfirm
.
type
}
:`
,
err
);
}
}
setDeleteConfirm
(
null
);
};
const
toggleGroup
=
(
groupId
:
string
)
=>
{
setCollapsedGroups
(
prev
=>
{
const
newSet
=
new
Set
(
prev
);
if
(
newSet
.
has
(
groupId
))
{
newSet
.
delete
(
groupId
);
}
else
{
newSet
.
add
(
groupId
);
}
return
newSet
;
});
};
};
return
(
return
(
...
@@ -122,15 +180,31 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle }) => {
...
@@ -122,15 +180,31 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle }) => {
{
groups
.
map
(
group
=>
(
{
groups
.
map
(
group
=>
(
<
div
key=
{
group
.
id
}
className=
"group"
>
<
div
key=
{
group
.
id
}
className=
"group"
>
<
div
className=
"group-header"
>
<
div
className=
"group-header"
onClick=
{
()
=>
toggleGroup
(
group
.
id
)
}
>
<
span
className=
"group-name"
>
<
span
className=
"group-name"
>
<
FontAwesomeIcon
icon=
{
collapsedGroups
.
has
(
group
.
id
)
?
faChevronRight
:
faChevronDown
}
className=
"group-toggle-icon"
/>
<
FontAwesomeIcon
icon=
{
faFolder
}
/>
{
group
.
name
}
<
FontAwesomeIcon
icon=
{
faFolder
}
/>
{
group
.
name
}
</
span
>
</
span
>
<
div
className=
"group-actions"
>
<
div
className=
"group-actions"
>
<
button
className=
"action-button"
onClick=
{
()
=>
setShowNewFileForm
(
group
.
id
)
}
>
<
button
className=
"action-button"
onClick=
{
(
e
)
=>
{
e
.
stopPropagation
();
setShowNewFileForm
(
group
.
id
);
}
}
>
<
FontAwesomeIcon
icon=
{
faPlus
}
/>
<
FontAwesomeIcon
icon=
{
faPlus
}
/>
</
button
>
</
button
>
<
button
className=
"action-button"
onClick=
{
()
=>
handleDeleteGroup
(
group
.
id
)
}
>
<
button
className=
"action-button"
onClick=
{
(
e
)
=>
{
e
.
stopPropagation
();
handleDeleteGroup
(
group
.
id
);
}
}
>
<
FontAwesomeIcon
icon=
{
faTrash
}
/>
<
FontAwesomeIcon
icon=
{
faTrash
}
/>
</
button
>
</
button
>
</
div
>
</
div
>
...
@@ -149,27 +223,44 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle }) => {
...
@@ -149,27 +223,44 @@ const Sidebar: React.FC<SidebarProps> = ({ isOpen, onToggle }) => {
</
div
>
</
div
>
)
}
)
}
{
group
.
files
.
map
(
file
=>
(
<
div
className=
{
`group-files ${collapsedGroups.has(group.id) ? 'collapsed' : ''}`
}
>
<
div
key=
{
file
.
id
}
className=
"file-item"
>
{
group
.
files
.
map
(
file
=>
(
<
span
className=
"file-name"
>
<
div
<
FontAwesomeIcon
icon=
{
faFile
}
/>
{
file
.
name
}
key=
{
file
.
id
}
</
span
>
className=
{
`file-item ${currentDocumentId === file.id ? 'active' : ''}`
}
<
div
className=
"file-actions"
>
onClick=
{
()
=>
onDocumentSelect
(
group
.
id
,
file
.
id
)
}
<
button
>
className=
"action-button"
<
span
className=
"file-name"
>
onClick=
{
()
=>
handleDeleteFile
(
group
.
id
,
file
.
id
)
}
<
FontAwesomeIcon
icon=
{
faFile
}
/>
{
file
.
name
}
>
</
span
>
<
FontAwesomeIcon
icon=
{
faTrash
}
/>
<
div
className=
"file-actions"
>
</
button
>
<
button
className=
"action-button"
onClick=
{
(
e
)
=>
{
e
.
stopPropagation
();
handleDeleteFile
(
group
.
id
,
file
.
id
);
}
}
>
<
FontAwesomeIcon
icon=
{
faTrash
}
/>
</
button
>
</
div
>
</
div
>
</
div
>
</
div
>
))
}
))
}
</
div
>
</
div
>
</
div
>
))
}
))
}
</
div
>
</
div
>
<
button
className=
"toggle-button"
onClick=
{
onToggle
}
>
<
button
className=
"toggle-button"
onClick=
{
onToggle
}
>
<
FontAwesomeIcon
icon=
{
isOpen
?
faChevronLeft
:
faChevronRight
}
/>
<
FontAwesomeIcon
icon=
{
isOpen
?
faChevronLeft
:
faChevronRight
}
/>
</
button
>
</
button
>
<
ConfirmDialog
isOpen=
{
!!
deleteConfirm
}
title=
{
`Delete ${deleteConfirm?.type === 'group' ? 'Group' : 'File'}`
}
message=
{
`Are you sure you want to delete ${deleteConfirm?.type} "${deleteConfirm?.name}"? This action cannot be undone.`
}
onConfirm=
{
confirmDelete
}
onCancel=
{
()
=>
setDeleteConfirm
(
null
)
}
/>
</
div
>
</
div
>
);
);
};
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment