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
ca213437
Commit
ca213437
authored
Sep 21, 2024
by
Steven
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: implement nesting lists
parent
7a4d54bb
Changes
14
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
685 additions
and
455 deletions
+685
-455
apidocs.swagger.yaml
docs/apidocs.swagger.yaml
+214
-64
go.mod
go.mod
+1
-1
go.sum
go.sum
+2
-2
markdown_service.proto
proto/api/v1/markdown_service.proto
+9
-1
markdown_service.pb.go
proto/gen/api/v1/markdown_service.pb.go
+371
-292
markdown_service.go
server/router/api/v1/markdown_service.go
+29
-2
List.tsx
web/src/components/MemoContent/List.tsx
+36
-14
OrderedListItem.tsx
web/src/components/MemoContent/OrderedListItem.tsx
+5
-18
TaskListItem.tsx
web/src/components/MemoContent/TaskListItem.tsx
+10
-18
UnorderedListItem.tsx
web/src/components/MemoContent/UnorderedListItem.tsx
+5
-18
index.tsx
web/src/components/MemoEditor/index.tsx
+1
-1
UserBanner.tsx
web/src/components/UserBanner.tsx
+2
-2
tailwind.config.js
web/tailwind.config.js
+0
-14
vercel.json
web/vercel.json
+0
-8
No files found.
docs/apidocs.swagger.yaml
View file @
ca213437
This diff is collapsed.
Click to expand it.
go.mod
View file @
ca213437
...
...
@@ -23,7 +23,7 @@ require (
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.9.0
github.com/usememos/gomark v0.0.0-2024092
0000613-9640de1955cd
github.com/usememos/gomark v0.0.0-2024092
1115339-c9d3461efcd8
golang.org/x/crypto v0.27.0
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0
golang.org/x/mod v0.21.0
...
...
go.sum
View file @
ca213437
...
...
@@ -438,8 +438,8 @@ github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVM
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/usememos/gomark v0.0.0-2024092
0000613-9640de1955cd h1:tqBJ00an5/MWAu1pIFkyE9TCSIe1JYAhShJlVeveYgs
=
github.com/usememos/gomark v0.0.0-2024092
0000613-9640de1955cd
/go.mod h1:7CZRoYFQyyljzplOTeyODFR26O+wr0BbnpTWVLGfKJA=
github.com/usememos/gomark v0.0.0-2024092
1115339-c9d3461efcd8 h1:kutNP+XD8oiBzoJJER35fbVaphCeRhU1dKDjZ5eKT0M
=
github.com/usememos/gomark v0.0.0-2024092
1115339-c9d3461efcd8
/go.mod h1:7CZRoYFQyyljzplOTeyODFR26O+wr0BbnpTWVLGfKJA=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
...
...
proto/api/v1/markdown_service.proto
View file @
ca213437
...
...
@@ -173,7 +173,15 @@ message BlockquoteNode {
}
message
ListNode
{
repeated
Node
children
=
1
;
enum
Kind
{
KIND_UNSPECIFIED
=
0
;
ORDERED
=
1
;
UNORDERED
=
2
;
DESCRIPTION
=
3
;
}
Kind
kind
=
1
;
int32
indent
=
2
;
repeated
Node
children
=
3
;
}
message
OrderedListItemNode
{
...
...
proto/gen/api/v1/markdown_service.pb.go
View file @
ca213437
This diff is collapsed.
Click to expand it.
server/router/api/v1/markdown_service.go
View file @
ca213437
...
...
@@ -77,7 +77,7 @@ func convertFromASTNode(rawNode ast.Node) *v1pb.Node {
node
.
Node
=
&
v1pb
.
Node_BlockquoteNode
{
BlockquoteNode
:
&
v1pb
.
BlockquoteNode
{
Children
:
children
}}
case
*
ast
.
List
:
children
:=
convertFromASTNodes
(
n
.
Children
)
node
.
Node
=
&
v1pb
.
Node_ListNode
{
ListNode
:
&
v1pb
.
ListNode
{
Children
:
children
}}
node
.
Node
=
&
v1pb
.
Node_ListNode
{
ListNode
:
&
v1pb
.
ListNode
{
Kind
:
convertListKindFromASTNode
(
n
.
Kind
),
Indent
:
int32
(
n
.
Indent
),
Children
:
children
}}
case
*
ast
.
OrderedListItem
:
children
:=
convertFromASTNodes
(
n
.
Children
)
node
.
Node
=
&
v1pb
.
Node_OrderedListItemNode
{
OrderedListItemNode
:
&
v1pb
.
OrderedListItemNode
{
Number
:
n
.
Number
,
Indent
:
int32
(
n
.
Indent
),
Children
:
children
}}
...
...
@@ -156,6 +156,19 @@ func convertTableFromASTNode(node *ast.Table) *v1pb.TableNode {
return
table
}
func
convertListKindFromASTNode
(
node
ast
.
ListKind
)
v1pb
.
ListNode_Kind
{
switch
node
{
case
ast
.
OrderedList
:
return
v1pb
.
ListNode_ORDERED
case
ast
.
UnorderedList
:
return
v1pb
.
ListNode_UNORDERED
case
ast
.
DescrpitionList
:
return
v1pb
.
ListNode_DESCRIPTION
default
:
return
v1pb
.
ListNode_KIND_UNSPECIFIED
}
}
func
convertToASTNode
(
node
*
v1pb
.
Node
)
ast
.
Node
{
switch
n
:=
node
.
Node
.
(
type
)
{
case
*
v1pb
.
Node_LineBreakNode
:
...
...
@@ -175,7 +188,7 @@ func convertToASTNode(node *v1pb.Node) ast.Node {
return
&
ast
.
Blockquote
{
Children
:
children
}
case
*
v1pb
.
Node_ListNode
:
children
:=
convertToASTNodes
(
n
.
ListNode
.
Children
)
return
&
ast
.
List
{
Children
:
children
}
return
&
ast
.
List
{
Kind
:
convertListKindToASTNode
(
n
.
ListNode
.
Kind
),
Indent
:
int
(
n
.
ListNode
.
Indent
),
Children
:
children
}
case
*
v1pb
.
Node_OrderedListItemNode
:
children
:=
convertToASTNodes
(
n
.
OrderedListItemNode
.
Children
)
return
&
ast
.
OrderedListItem
{
Number
:
n
.
OrderedListItemNode
.
Number
,
Indent
:
int
(
n
.
OrderedListItemNode
.
Indent
),
Children
:
children
}
...
...
@@ -252,3 +265,17 @@ func convertTableToASTNode(node *v1pb.TableNode) *ast.Table {
}
return
table
}
func
convertListKindToASTNode
(
kind
v1pb
.
ListNode_Kind
)
ast
.
ListKind
{
switch
kind
{
case
v1pb
.
ListNode_ORDERED
:
return
ast
.
OrderedList
case
v1pb
.
ListNode_UNORDERED
:
return
ast
.
UnorderedList
case
v1pb
.
ListNode_DESCRIPTION
:
return
ast
.
DescrpitionList
default
:
// Default to description list.
return
ast
.
DescrpitionList
}
}
web/src/components/MemoContent/List.tsx
View file @
ca213437
import
{
Node
,
NodeType
}
from
"@/types/proto/api/v1/markdown_service"
;
import
clsx
from
"clsx"
;
import
React
from
"react"
;
import
{
ListNode_Kind
,
Node
,
NodeType
}
from
"@/types/proto/api/v1/markdown_service"
;
import
Renderer
from
"./Renderer"
;
interface
Props
{
index
:
string
;
kind
:
ListNode_Kind
;
indent
:
number
;
children
:
Node
[];
}
const
List
:
React
.
FC
<
Props
>
=
({
children
}:
Props
)
=>
{
const
List
:
React
.
FC
<
Props
>
=
({
kind
,
indent
,
children
}:
Props
)
=>
{
let
prevNode
:
Node
|
null
=
null
;
let
skipNextLineBreakFlag
=
false
;
return
(
<
dl
>
{
children
.
map
((
child
,
index
)
=>
{
if
(
prevNode
?.
type
!==
NodeType
.
LINE_BREAK
&&
child
.
type
===
NodeType
.
LINE_BREAK
&&
skipNextLineBreakFlag
)
{
skipNextLineBreakFlag
=
false
;
return
null
;
}
const
getListContainer
=
(
kind
:
ListNode_Kind
)
=>
{
switch
(
kind
)
{
case
ListNode_Kind
.
ORDERED
:
return
"ol"
;
case
ListNode_Kind
.
UNORDERED
:
return
"ul"
;
case
ListNode_Kind
.
DESCRIPTION
:
return
"dl"
;
default
:
return
"div"
;
}
};
prevNode
=
child
;
skipNextLineBreakFlag
=
true
;
return
<
Renderer
key=
{
`${child.type}-${index}`
}
index=
{
String
(
index
)
}
node=
{
child
}
/>;
})
}
</
dl
>
return
React
.
createElement
(
getListContainer
(
kind
),
{
className
:
clsx
(
`list-inside
${
kind
===
ListNode_Kind
.
ORDERED
?
"list-decimal"
:
kind
===
ListNode_Kind
.
UNORDERED
?
"list-disc"
:
"list-none"
}
`
,
indent
>
0
?
`pl-
${
2
*
indent
}
`
:
""
,
),
},
children
.
map
((
child
,
index
)
=>
{
if
(
prevNode
?.
type
!==
NodeType
.
LINE_BREAK
&&
child
.
type
===
NodeType
.
LINE_BREAK
&&
skipNextLineBreakFlag
)
{
skipNextLineBreakFlag
=
false
;
return
null
;
}
prevNode
=
child
;
skipNextLineBreakFlag
=
true
;
return
<
Renderer
key=
{
`${child.type}-${index}`
}
index=
{
String
(
index
)
}
node=
{
child
}
/>;
}),
);
};
...
...
web/src/components/MemoContent/OrderedListItem.tsx
View file @
ca213437
import
{
repeat
}
from
"lodash-es"
;
import
{
Node
}
from
"@/types/proto/api/v1/markdown_service"
;
import
Renderer
from
"./Renderer"
;
import
{
BaseProps
}
from
"./types"
;
...
...
@@ -9,24 +8,12 @@ interface Props extends BaseProps {
children
:
Node
[];
}
const
OrderedListItem
:
React
.
FC
<
Props
>
=
({
number
,
indent
,
children
}:
Props
)
=>
{
const
OrderedListItem
:
React
.
FC
<
Props
>
=
({
children
}:
Props
)
=>
{
return
(
<
li
className=
"w-full flex flex-row"
>
{
indent
>
0
&&
(
<
div
className=
"block font-mono shrink-0"
>
<
span
>
{
repeat
(
" "
,
indent
)
}
</
span
>
</
div
>
)
}
<
div
className=
"w-auto grid grid-cols-[24px_1fr] gap-1"
>
<
div
className=
"w-7 h-6 flex justify-center items-center"
>
<
span
className=
"opacity-80"
>
{
number
}
.
</
span
>
</
div
>
<
div
>
{
children
.
map
((
child
,
index
)
=>
(
<
Renderer
key=
{
`${child.type}-${index}`
}
index=
{
String
(
index
)
}
node=
{
child
}
/>
))
}
</
div
>
</
div
>
<
li
>
{
children
.
map
((
child
,
index
)
=>
(
<
Renderer
key=
{
`${child.type}-${index}`
}
index=
{
String
(
index
)
}
node=
{
child
}
/>
))
}
</
li
>
);
};
...
...
web/src/components/MemoContent/TaskListItem.tsx
View file @
ca213437
import
{
Checkbox
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
{
repeat
}
from
"lodash-es"
;
import
{
useContext
,
useState
}
from
"react"
;
import
{
markdownServiceClient
}
from
"@/grpcweb"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
...
...
@@ -17,7 +16,7 @@ interface Props {
children
:
Node
[];
}
const
TaskListItem
:
React
.
FC
<
Props
>
=
({
node
,
indent
,
complete
,
children
}:
Props
)
=>
{
const
TaskListItem
:
React
.
FC
<
Props
>
=
({
node
,
complete
,
children
}:
Props
)
=>
{
const
context
=
useContext
(
RendererContext
);
const
memoStore
=
useMemoStore
();
const
[
checked
]
=
useState
(
complete
);
...
...
@@ -39,22 +38,15 @@ const TaskListItem: React.FC<Props> = ({ node, indent, complete, children }: Pro
};
return
(
<
li
className=
"w-full flex flex-row"
>
{
indent
>
0
&&
(
<
div
className=
"block font-mono shrink-0"
>
<
span
>
{
repeat
(
" "
,
indent
)
}
</
span
>
</
div
>
)
}
<
div
className=
"w-auto grid grid-cols-[24px_1fr] gap-1"
>
<
div
className=
"w-7 h-6 flex justify-center items-center"
>
<
Checkbox
size=
"sm"
checked=
{
checked
}
disabled=
{
context
.
readonly
}
onChange=
{
(
e
)
=>
handleCheckboxChange
(
e
.
target
.
checked
)
}
/>
</
div
>
<
div
className=
{
clsx
(
complete
&&
"line-through opacity-80"
)
}
>
{
children
.
map
((
child
,
index
)
=>
(
<
Renderer
key=
{
`${child.type}-${index}`
}
index=
{
String
(
index
)
}
node=
{
child
}
/>
))
}
</
div
>
</
div
>
<
li
className=
{
clsx
(
"w-full grid grid-cols-[24px_1fr]"
)
}
>
<
span
className=
"w-6 h-6 flex justify-start items-center"
>
<
Checkbox
size=
"sm"
checked=
{
checked
}
disabled=
{
context
.
readonly
}
onChange=
{
(
e
)
=>
handleCheckboxChange
(
e
.
target
.
checked
)
}
/>
</
span
>
<
p
className=
{
clsx
(
complete
&&
"line-through opacity-80"
)
}
>
{
children
.
map
((
child
,
index
)
=>
(
<
Renderer
key=
{
`${child.type}-${index}`
}
index=
{
String
(
index
)
}
node=
{
child
}
/>
))
}
</
p
>
</
li
>
);
};
...
...
web/src/components/MemoContent/UnorderedListItem.tsx
View file @
ca213437
import
{
repeat
}
from
"lodash-es"
;
import
{
Node
}
from
"@/types/proto/api/v1/markdown_service"
;
import
Renderer
from
"./Renderer"
;
...
...
@@ -8,24 +7,12 @@ interface Props {
children
:
Node
[];
}
const
UnorderedListItem
:
React
.
FC
<
Props
>
=
({
indent
,
children
}:
Props
)
=>
{
const
UnorderedListItem
:
React
.
FC
<
Props
>
=
({
children
}:
Props
)
=>
{
return
(
<
li
className=
"w-full flex flex-row"
>
{
indent
>
0
&&
(
<
div
className=
"block font-mono shrink-0"
>
<
span
>
{
repeat
(
" "
,
indent
)
}
</
span
>
</
div
>
)
}
<
div
className=
"w-auto grid grid-cols-[24px_1fr] gap-1"
>
<
div
className=
"w-7 h-6 flex justify-center items-center"
>
<
span
className=
"opacity-80"
>
•
</
span
>
</
div
>
<
div
>
{
children
.
map
((
child
,
index
)
=>
(
<
Renderer
key=
{
`${child.type}-${index}`
}
index=
{
String
(
index
)
}
node=
{
child
}
/>
))
}
</
div
>
</
div
>
<
li
>
{
children
.
map
((
child
,
index
)
=>
(
<
Renderer
key=
{
`${child.type}-${index}`
}
index=
{
String
(
index
)
}
node=
{
child
}
/>
))
}
</
li
>
);
};
...
...
web/src/components/MemoEditor/index.tsx
View file @
ca213437
...
...
@@ -443,7 +443,7 @@ const MemoEditor = (props: Props) => {
<
AddMemoRelationPopover
editorRef=
{
editorRef
}
/>
</
div
>
</
div
>
<
Divider
className=
"!mt-2"
/>
<
Divider
className=
"!mt-2
opacity-40
"
/>
<
div
className=
"w-full flex flex-row justify-between items-center py-3 dark:border-t-zinc-500"
>
<
div
className=
"relative flex flex-row justify-start items-center"
onFocus=
{
(
e
)
=>
e
.
stopPropagation
()
}
>
<
Select
...
...
web/src/components/UserBanner.tsx
View file @
ca213437
...
...
@@ -23,8 +23,8 @@ const UserBanner = (props: Props) => {
const
workspaceSettingStore
=
useWorkspaceSettingStore
();
const
workspaceGeneralSetting
=
workspaceSettingStore
.
getWorkspaceSettingByKey
(
WorkspaceSettingKey
.
GENERAL
).
generalSetting
||
WorkspaceGeneralSetting
.
fromPartial
({});
const
title
=
user
?
user
.
nickname
||
user
.
username
:
workspaceGeneralSetting
.
customProfile
?.
title
;
const
avatarUrl
=
user
?
user
.
avatarUrl
:
workspaceGeneralSetting
.
customProfile
?.
logoUrl
;
const
title
=
(
user
?
user
.
nickname
||
user
.
username
:
workspaceGeneralSetting
.
customProfile
?.
title
)
||
"Memos"
;
const
avatarUrl
=
(
user
?
user
.
avatarUrl
:
workspaceGeneralSetting
.
customProfile
?.
logoUrl
)
||
"/logo.webp"
;
const
handleSignOut
=
async
()
=>
{
await
authServiceClient
.
signOut
({});
...
...
web/tailwind.config.js
View file @
ca213437
...
...
@@ -81,20 +81,6 @@ module.exports = {
md
:
"calc(var(--radius) - 2px)"
,
sm
:
"calc(var(--radius) - 4px)"
,
},
keyframes
:
{
"accordion-down"
:
{
from
:
{
height
:
"0"
},
to
:
{
height
:
"var(--radix-accordion-content-height)"
},
},
"accordion-up"
:
{
from
:
{
height
:
"var(--radix-accordion-content-height)"
},
to
:
{
height
:
"0"
},
},
},
animation
:
{
"accordion-down"
:
"accordion-down 0.2s ease-out"
,
"accordion-up"
:
"accordion-up 0.2s ease-out"
,
},
},
},
plugins
:
[
require
(
"tailwindcss-animate"
)],
...
...
web/vercel.json
deleted
100644 → 0
View file @
7a4d54bb
{
"rewrites"
:
[
{
"source"
:
"/(.*)"
,
"destination"
:
"/index.html"
}
]
}
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