Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
canifa_note
Project
Project
Details
Activity
Releases
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
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
canifa_note
Commits
ab1fa44f
Commit
ab1fa44f
authored
Jan 13, 2024
by
Steven
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: implement markdown buttons
parent
cd0004cf
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
156 additions
and
1 deletion
+156
-1
MarkdownMenu.tsx
web/src/components/MemoEditor/ActionButton/MarkdownMenu.tsx
+96
-0
index.tsx
web/src/components/MemoEditor/index.tsx
+3
-1
PreviewMarkdownDialog.tsx
web/src/components/PreviewMarkdownDialog.tsx
+57
-0
No files found.
web/src/components/MemoEditor/ActionButton/MarkdownMenu.tsx
0 → 100644
View file @
ab1fa44f
import
{
Dropdown
,
IconButton
,
Menu
,
MenuButton
,
MenuItem
}
from
"@mui/joy"
;
import
Icon
from
"@/components/Icon"
;
import
showPreviewMarkdownDialog
from
"@/components/PreviewMarkdownDialog"
;
import
{
EditorRefActions
}
from
"../Editor"
;
interface
Props
{
editorRef
:
React
.
RefObject
<
EditorRefActions
>
;
}
const
MarkdownMenu
=
(
props
:
Props
)
=>
{
const
{
editorRef
}
=
props
;
const
handleCodeBlockClick
=
()
=>
{
if
(
!
editorRef
.
current
)
{
return
;
}
const
cursorPosition
=
editorRef
.
current
.
getCursorPosition
();
const
prevValue
=
editorRef
.
current
.
getContent
().
slice
(
0
,
cursorPosition
);
if
(
prevValue
===
""
||
prevValue
.
endsWith
(
"
\n
"
))
{
editorRef
.
current
.
insertText
(
""
,
"```
\n
"
,
"
\n
```"
);
}
else
{
editorRef
.
current
.
insertText
(
""
,
"
\n
```
\n
"
,
"
\n
```"
);
}
setTimeout
(()
=>
{
editorRef
.
current
?.
scrollToCursor
();
editorRef
.
current
?.
focus
();
});
};
const
handleCheckboxClick
=
()
=>
{
if
(
!
editorRef
.
current
)
{
return
;
}
const
currentPosition
=
editorRef
.
current
.
getCursorPosition
();
const
currentLineNumber
=
editorRef
.
current
.
getCursorLineNumber
();
const
currentLine
=
editorRef
.
current
.
getLine
(
currentLineNumber
);
let
newLine
=
""
;
let
cursorChange
=
0
;
if
(
/^-
\[(
|x|X
)\]
/
.
test
(
currentLine
))
{
newLine
=
currentLine
.
replace
(
/^-
\[(
|x|X
)\]
/
,
""
);
cursorChange
=
-
6
;
}
else
if
(
/^
\d
+
\.
|- /
.
test
(
currentLine
))
{
const
match
=
currentLine
.
match
(
/^
\d
+
\.
|- /
)
??
[
""
];
newLine
=
currentLine
.
replace
(
/^
\d
+
\.
|- /
,
"- [ ] "
);
cursorChange
=
-
match
[
0
].
length
+
6
;
}
else
{
newLine
=
"- [ ] "
+
currentLine
;
cursorChange
=
6
;
}
editorRef
.
current
.
setLine
(
currentLineNumber
,
newLine
);
editorRef
.
current
.
setCursorPosition
(
currentPosition
+
cursorChange
);
setTimeout
(()
=>
{
editorRef
.
current
?.
scrollToCursor
();
editorRef
.
current
?.
focus
();
});
};
const
handlePreviewClick
=
()
=>
{
showPreviewMarkdownDialog
(
editorRef
.
current
?.
getContent
()
??
""
);
};
return
(
<
Dropdown
>
<
MenuButton
slots=
{
{
root
:
IconButton
}
}
slotProps=
{
{
root
:
{
className
:
"flex flex-row justify-center items-center p-1 w-auto h-auto mr-1 select-none rounded cursor-pointer text-gray-600 dark:!text-gray-400 hover:bg-gray-300 dark:hover:bg-zinc-800 hover:shadow"
,
size
:
"sm"
,
},
}
}
>
<
Icon
.
SquareSlash
className=
"w-5 h-5 mx-auto"
/>
</
MenuButton
>
<
Menu
className=
"text-sm"
size=
"sm"
>
<
MenuItem
onClick=
{
handleCodeBlockClick
}
>
<
Icon
.
Code2
className=
"w-4 h-auto"
/>
<
span
>
Code block
</
span
>
</
MenuItem
>
<
MenuItem
onClick=
{
handleCheckboxClick
}
>
<
Icon
.
CheckSquare
className=
"w-4 h-auto"
/>
<
span
>
Checkbox
</
span
>
</
MenuItem
>
<
MenuItem
onClick=
{
handlePreviewClick
}
>
<
Icon
.
NotebookText
className=
"w-4 h-auto"
/>
<
span
>
Preview
</
span
>
</
MenuItem
>
</
Menu
>
</
Dropdown
>
);
};
export
default
MarkdownMenu
;
web/src/components/MemoEditor/index.tsx
View file @
ab1fa44f
...
@@ -18,6 +18,7 @@ import showCreateMemoRelationDialog from "../CreateMemoRelationDialog";
...
@@ -18,6 +18,7 @@ import showCreateMemoRelationDialog from "../CreateMemoRelationDialog";
import
showCreateResourceDialog
from
"../CreateResourceDialog"
;
import
showCreateResourceDialog
from
"../CreateResourceDialog"
;
import
Icon
from
"../Icon"
;
import
Icon
from
"../Icon"
;
import
VisibilityIcon
from
"../VisibilityIcon"
;
import
VisibilityIcon
from
"../VisibilityIcon"
;
import
MarkdownMenu
from
"./ActionButton/MarkdownMenu"
;
import
TagSelector
from
"./ActionButton/TagSelector"
;
import
TagSelector
from
"./ActionButton/TagSelector"
;
import
Editor
,
{
EditorRefActions
}
from
"./Editor"
;
import
Editor
,
{
EditorRefActions
}
from
"./Editor"
;
import
RelationListView
from
"./RelationListView"
;
import
RelationListView
from
"./RelationListView"
;
...
@@ -366,7 +367,7 @@ const MemoEditor = (props: Props) => {
...
@@ -366,7 +367,7 @@ const MemoEditor = (props: Props) => {
onFocus=
{
handleEditorFocus
}
onFocus=
{
handleEditorFocus
}
>
>
<
Editor
ref=
{
editorRef
}
{
...
editorConfig
}
/>
<
Editor
ref=
{
editorRef
}
{
...
editorConfig
}
/>
<
div
className=
"relative w-full flex flex-row justify-between items-center pt-2"
>
<
div
className=
"relative w-full flex flex-row justify-between items-center pt-2"
onFocus=
{
(
e
)
=>
e
.
stopPropagation
()
}
>
<
div
className=
"flex flex-row justify-start items-center"
>
<
div
className=
"flex flex-row justify-start items-center"
>
<
TagSelector
onTagSelectorClick=
{
(
tag
)
=>
handleTagSelectorClick
(
tag
)
}
/>
<
TagSelector
onTagSelectorClick=
{
(
tag
)
=>
handleTagSelectorClick
(
tag
)
}
/>
<
IconButton
<
IconButton
...
@@ -383,6 +384,7 @@ const MemoEditor = (props: Props) => {
...
@@ -383,6 +384,7 @@ const MemoEditor = (props: Props) => {
>
>
<
Icon
.
Link
className=
"w-5 h-5 mx-auto"
/>
<
Icon
.
Link
className=
"w-5 h-5 mx-auto"
/>
</
IconButton
>
</
IconButton
>
<
MarkdownMenu
editorRef=
{
editorRef
}
/>
</
div
>
</
div
>
</
div
>
</
div
>
<
ResourceListView
resourceList=
{
state
.
resourceList
}
setResourceList=
{
handleSetResourceList
}
/>
<
ResourceListView
resourceList=
{
state
.
resourceList
}
setResourceList=
{
handleSetResourceList
}
/>
...
...
web/src/components/PreviewMarkdownDialog.tsx
0 → 100644
View file @
ab1fa44f
import
{
useEffect
,
useState
}
from
"react"
;
import
{
markdownServiceClient
}
from
"@/grpcweb"
;
import
{
Node
}
from
"@/types/proto/api/v2/markdown_service"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
Icon
from
"./Icon"
;
import
MemoContent
from
"./MemoContent"
;
interface
Props
extends
DialogProps
{
content
:
string
;
}
const
PreviewMarkdownDialog
:
React
.
FC
<
Props
>
=
({
content
,
destroy
}:
Props
)
=>
{
const
[
nodes
,
setNodes
]
=
useState
<
Node
[]
>
([]);
useEffect
(()
=>
{
(
async
()
=>
{
const
{
nodes
}
=
await
markdownServiceClient
.
parseMarkdown
({
markdown
:
content
,
});
setNodes
(
nodes
);
})();
},
[]);
const
handleCloseBtnClick
=
()
=>
{
destroy
();
};
return
(
<>
<
div
className=
"dialog-header-container"
>
<
div
className=
"flex flex-row justify-start items-center"
>
<
p
className=
"text-black opacity-80 dark:text-gray-200"
>
Preview
</
p
>
</
div
>
<
button
className=
"btn close-btn"
onClick=
{
handleCloseBtnClick
}
>
<
Icon
.
X
/>
</
button
>
</
div
>
<
div
className=
"flex flex-col justify-start items-start max-w-full w-[32rem]"
>
<
MemoContent
nodes=
{
nodes
}
/>
</
div
>
</>
);
};
export
default
function
showPreviewMarkdownDialog
(
content
:
string
):
void
{
generateDialog
(
{
className
:
"preview-markdown-dialog"
,
dialogName
:
"preview-markdown-dialog"
,
containerClassName
:
"dark:!bg-zinc-800"
,
},
PreviewMarkdownDialog
,
{
content
,
}
);
}
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