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
291b8156
Commit
291b8156
authored
Jul 01, 2024
by
Steven
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: implement memo detail sidebar
parent
05c6edfe
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
170 additions
and
62 deletions
+170
-62
ExploreSidebarDrawer.tsx
web/src/components/ExploreSidebar/ExploreSidebarDrawer.tsx
+1
-1
HomeSidebarDrawer.tsx
web/src/components/HomeSidebar/HomeSidebarDrawer.tsx
+1
-1
MemoDetailSidebar.tsx
web/src/components/MemoDetailSidebar/MemoDetailSidebar.tsx
+48
-0
MemoDetailSidebarDrawer.tsx
.../components/MemoDetailSidebar/MemoDetailSidebarDrawer.tsx
+41
-0
index.ts
web/src/components/MemoDetailSidebar/index.ts
+4
-0
TimelineSidebarDrawer.tsx
web/src/components/TimelineSidebar/TimelineSidebarDrawer.tsx
+1
-1
UserStatisticsView.tsx
web/src/components/UserStatisticsView.tsx
+2
-2
MemoDetail.tsx
web/src/pages/MemoDetail.tsx
+72
-57
No files found.
web/src/components/ExploreSidebar/ExploreSidebarDrawer.tsx
View file @
291b8156
...
...
@@ -26,7 +26,7 @@ const ExploreSidebarDrawer = () => {
<
Icon
.
Search
className=
"w-5 h-auto dark:text-gray-400"
/>
</
IconButton
>
<
Drawer
anchor=
"right"
size=
"sm"
open=
{
open
}
onClose=
{
toggleDrawer
(
false
)
}
>
<
div
className=
"w-full h-full px-
5
bg-zinc-100 dark:bg-zinc-900"
>
<
div
className=
"w-full h-full px-
4
bg-zinc-100 dark:bg-zinc-900"
>
<
ExploreSidebar
className=
"py-4"
/>
</
div
>
</
Drawer
>
...
...
web/src/components/HomeSidebar/HomeSidebarDrawer.tsx
View file @
291b8156
...
...
@@ -26,7 +26,7 @@ const HomeSidebarDrawer = () => {
<
Icon
.
Search
className=
"w-5 h-auto dark:text-gray-400"
/>
</
IconButton
>
<
Drawer
anchor=
"right"
size=
"sm"
open=
{
open
}
onClose=
{
toggleDrawer
(
false
)
}
>
<
div
className=
"w-full h-full px-
5
bg-zinc-100 dark:bg-zinc-900"
>
<
div
className=
"w-full h-full px-
4
bg-zinc-100 dark:bg-zinc-900"
>
<
HomeSidebar
className=
"py-4"
/>
</
div
>
</
Drawer
>
...
...
web/src/components/MemoDetailSidebar/MemoDetailSidebar.tsx
0 → 100644
View file @
291b8156
import
clsx
from
"clsx"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Icon
from
"../Icon"
;
interface
Props
{
memo
:
Memo
;
className
?:
string
;
}
const
MemoDetailSidebar
=
({
memo
,
className
}:
Props
)
=>
{
const
t
=
useTranslate
();
if
(
!
memo
.
property
)
{
return
;
}
return
(
<
aside
className=
{
clsx
(
"relative w-full h-auto max-h-screen overflow-auto hide-scrollbar flex flex-col justify-start items-start"
,
className
,
)
}
>
<
div
className=
"flex flex-col justify-start items-start w-full mt-1 px-1 h-auto shrink-0 flex-nowrap hide-scrollbar"
>
<
div
className=
"flex flex-row justify-start items-center w-full gap-1 mb-1 text-sm leading-6 text-gray-400 select-none"
>
<
span
>
{
t
(
"common.tags"
)
}
</
span
>
{
memo
.
property
.
tags
.
length
>
0
&&
<
span
className=
"shrink-0"
>
(
{
memo
.
property
.
tags
.
length
}
)
</
span
>
}
</
div
>
<
div
className=
"w-full flex flex-row justify-start items-center relative flex-wrap gap-x-2 gap-y-1"
>
{
memo
.
property
.
tags
.
map
((
tag
)
=>
(
<
div
key=
{
tag
}
className=
"shrink-0 w-auto max-w-full text-sm rounded-md leading-6 flex flex-row justify-start items-center select-none hover:opacity-80 text-gray-600 dark:text-gray-400 dark:border-zinc-800"
>
<
Icon
.
Hash
className=
"group-hover:hidden w-4 h-auto shrink-0 opacity-40"
/>
<
div
className=
{
clsx
(
"inline-flex flex-nowrap ml-0.5 gap-0.5 cursor-pointer max-w-[calc(100%-16px)]"
)
}
>
<
span
className=
"truncate dark:opacity-80"
>
{
tag
}
</
span
>
</
div
>
</
div
>
))
}
</
div
>
</
div
>
</
aside
>
);
};
export
default
MemoDetailSidebar
;
web/src/components/MemoDetailSidebar/MemoDetailSidebarDrawer.tsx
0 → 100644
View file @
291b8156
import
{
Drawer
,
IconButton
}
from
"@mui/joy"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
Icon
from
"../Icon"
;
import
MemoDetailSidebar
from
"./MemoDetailSidebar"
;
interface
Props
{
memo
:
Memo
;
}
const
MemoDetailSidebarDrawer
=
({
memo
}:
Props
)
=>
{
const
location
=
useLocation
();
const
[
open
,
setOpen
]
=
useState
(
false
);
useEffect
(()
=>
{
setOpen
(
false
);
},
[
location
.
pathname
]);
const
toggleDrawer
=
(
inOpen
:
boolean
)
=>
(
event
:
React
.
KeyboardEvent
|
React
.
MouseEvent
)
=>
{
if
(
event
.
type
===
"keydown"
&&
((
event
as
React
.
KeyboardEvent
).
key
===
"Tab"
||
(
event
as
React
.
KeyboardEvent
).
key
===
"Shift"
))
{
return
;
}
setOpen
(
inOpen
);
};
return
(
<>
<
IconButton
onClick=
{
toggleDrawer
(
true
)
}
>
<
Icon
.
GanttChart
className=
"w-5 h-auto dark:text-gray-400"
/>
</
IconButton
>
<
Drawer
anchor=
"right"
size=
"sm"
open=
{
open
}
onClose=
{
toggleDrawer
(
false
)
}
>
<
div
className=
"w-full h-full px-4 bg-zinc-100 dark:bg-zinc-900"
>
<
MemoDetailSidebar
className=
"py-4"
memo=
{
memo
}
/>
</
div
>
</
Drawer
>
</>
);
};
export
default
MemoDetailSidebarDrawer
;
web/src/components/MemoDetailSidebar/index.ts
0 → 100644
View file @
291b8156
import
MemoDetailSidebar
from
"./MemoDetailSidebar"
;
import
MemoDetailSidebarDrawer
from
"./MemoDetailSidebarDrawer"
;
export
{
MemoDetailSidebar
,
MemoDetailSidebarDrawer
};
web/src/components/TimelineSidebar/TimelineSidebarDrawer.tsx
View file @
291b8156
...
...
@@ -26,7 +26,7 @@ const TimelineSidebarDrawer = () => {
<
Icon
.
Search
className=
"w-5 h-auto dark:text-gray-400"
/>
</
IconButton
>
<
Drawer
anchor=
"right"
size=
"sm"
open=
{
open
}
onClose=
{
toggleDrawer
(
false
)
}
>
<
div
className=
"w-full h-full px-
5
bg-zinc-100 dark:bg-zinc-900"
>
<
div
className=
"w-full h-full px-
4
bg-zinc-100 dark:bg-zinc-900"
>
<
TimelineSidebar
className=
"py-4"
/>
</
div
>
</
Drawer
>
...
...
web/src/components/UserStatisticsView.tsx
View file @
291b8156
...
...
@@ -62,10 +62,10 @@ const UserStatisticsView = () => {
};
return
(
<
div
className=
"w-full border mt-2 py-2 px-3 rounded-lg space-y-0.5 text-gray-500 dark:text-gray-400 bg-zinc-50 dark:bg-zinc-900 dark:border-zinc-800"
>
<
div
className=
"
group
w-full border mt-2 py-2 px-3 rounded-lg space-y-0.5 text-gray-500 dark:text-gray-400 bg-zinc-50 dark:bg-zinc-900 dark:border-zinc-800"
>
<
div
className=
"w-full mb-1 flex flex-row justify-between items-center"
>
<
p
className=
"text-sm font-medium leading-6 dark:text-gray-500"
>
{
t
(
"common.statistics"
)
}
</
p
>
<
div
className=
""
>
<
div
className=
"
group-hover:block hidden
"
>
<
Tooltip
title=
{
"Refresh"
}
placement=
"top"
>
<
Icon
.
RefreshCcw
className=
"text-gray-400 w-4 h-auto cursor-pointer opacity-60 hover:opacity-100"
...
...
web/src/pages/MemoDetail.tsx
View file @
291b8156
import
{
Button
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
{
ClientError
}
from
"nice-grpc-web"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
Link
,
useParams
}
from
"react-router-dom"
;
import
Icon
from
"@/components/Icon"
;
import
{
MemoDetailSidebar
,
MemoDetailSidebarDrawer
}
from
"@/components/MemoDetailSidebar"
;
import
showMemoEditorDialog
from
"@/components/MemoEditor/MemoEditorDialog"
;
import
MemoView
from
"@/components/MemoView"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
useResponsiveWidth
from
"@/hooks/useResponsiveWidth"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
import
{
MemoRelation_Type
}
from
"@/types/proto/api/v1/memo_relation_service"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
...
...
@@ -16,6 +19,7 @@ import { useTranslate } from "@/utils/i18n";
const
MemoDetail
=
()
=>
{
const
t
=
useTranslate
();
const
{
md
}
=
useResponsiveWidth
();
const
params
=
useParams
();
const
navigateTo
=
useNavigateTo
();
const
currentUser
=
useCurrentUser
();
...
...
@@ -77,66 +81,77 @@ const MemoDetail = () => {
return
(
<
section
className=
"@container w-full max-w-5xl min-h-full flex flex-col justify-start items-center sm:pt-3 md:pt-6 pb-8"
>
<
MobileHeader
/>
<
div
className=
"w-full px-4 sm:px-6"
>
{
parentMemo
&&
(
<
div
className=
"w-auto inline-block mb-2"
>
<
Link
className=
"px-3 py-1 border rounded-lg max-w-xs w-auto text-sm flex flex-row justify-start items-center flex-nowrap text-gray-600 dark:text-gray-400 dark:border-gray-500 hover:shadow hover:opacity-80"
to=
{
`/m/${parentMemo.uid}`
}
unstable_viewTransition
>
<
Icon
.
ArrowUpLeftFromCircle
className=
"w-4 h-auto shrink-0 opacity-60 mr-2"
/>
<
span
className=
"truncate"
>
{
parentMemo
.
content
}
</
span
>
</
Link
>
</
div
>
)
}
<
MemoView
key=
{
`${memo.name}-${memo.displayTime}`
}
className=
"shadow hover:shadow-xl transition-all"
memo=
{
memo
}
compact=
{
false
}
showCreator
showVisibility
showPinned
/>
<
div
className=
"pt-8 pb-16 w-full"
>
<
h2
id=
"comments"
className=
"sr-only"
>
{
t
(
"memo.comment.self"
)
}
</
h2
>
<
div
className=
"relative mx-auto flex-grow w-full min-h-full flex flex-col justify-start items-start gap-y-1"
>
{
comments
.
length
===
0
?
(
currentUser
&&
(
<
div
className=
"w-full flex flex-row justify-center items-center py-6"
>
<
Button
variant=
"plain"
color=
"neutral"
endDecorator=
{
<
Icon
.
MessageCircle
className=
"w-5 h-auto text-gray-500"
/>
}
onClick=
{
handleShowCommentEditor
}
>
<
span
className=
"font-normal text-gray-500"
>
{
t
(
"memo.comment.write-a-comment"
)
}
</
span
>
</
Button
>
</
div
>
)
)
:
(
<>
<
div
className=
"w-full flex flex-row justify-between items-center px-3 mb-2"
>
<
div
className=
"flex flex-row justify-start items-center"
>
<
Icon
.
MessageCircle
className=
"w-5 h-auto text-gray-400 mr-1"
/>
<
span
className=
"text-gray-400 text-sm"
>
{
t
(
"memo.comment.self"
)
}
</
span
>
<
span
className=
"text-gray-400 text-sm ml-1"
>
(
{
comments
.
length
}
)
</
span
>
{
!
md
&&
(
<
MobileHeader
>
<
MemoDetailSidebarDrawer
memo=
{
memo
}
/>
</
MobileHeader
>
)
}
<
div
className=
{
clsx
(
"w-full flex flex-row justify-start items-start px-4 sm:px-6 gap-4"
)
}
>
<
div
className=
{
clsx
(
md
?
"w-[calc(100%-15rem)]"
:
"w-full"
)
}
>
{
parentMemo
&&
(
<
div
className=
"w-auto inline-block mb-2"
>
<
Link
className=
"px-3 py-1 border rounded-lg max-w-xs w-auto text-sm flex flex-row justify-start items-center flex-nowrap text-gray-600 dark:text-gray-400 dark:border-gray-500 hover:shadow hover:opacity-80"
to=
{
`/m/${parentMemo.uid}`
}
unstable_viewTransition
>
<
Icon
.
ArrowUpLeftFromCircle
className=
"w-4 h-auto shrink-0 opacity-60 mr-2"
/>
<
span
className=
"truncate"
>
{
parentMemo
.
content
}
</
span
>
</
Link
>
</
div
>
)
}
<
MemoView
key=
{
`${memo.name}-${memo.displayTime}`
}
className=
"shadow hover:shadow-md transition-all"
memo=
{
memo
}
compact=
{
false
}
showCreator
showVisibility
showPinned
/>
<
div
className=
"pt-8 pb-16 w-full"
>
<
h2
id=
"comments"
className=
"sr-only"
>
{
t
(
"memo.comment.self"
)
}
</
h2
>
<
div
className=
"relative mx-auto flex-grow w-full min-h-full flex flex-col justify-start items-start gap-y-1"
>
{
comments
.
length
===
0
?
(
currentUser
&&
(
<
div
className=
"w-full flex flex-row justify-center items-center py-6"
>
<
Button
variant=
"plain"
color=
"neutral"
endDecorator=
{
<
Icon
.
MessageCircle
className=
"w-5 h-auto text-gray-500"
/>
}
onClick=
{
handleShowCommentEditor
}
>
<
span
className=
"font-normal text-gray-500"
>
{
t
(
"memo.comment.write-a-comment"
)
}
</
span
>
</
Button
>
</
div
>
)
)
:
(
<>
<
div
className=
"w-full flex flex-row justify-between items-center px-3 mb-2"
>
<
div
className=
"flex flex-row justify-start items-center"
>
<
Icon
.
MessageCircle
className=
"w-5 h-auto text-gray-400 mr-1"
/>
<
span
className=
"text-gray-400 text-sm"
>
{
t
(
"memo.comment.self"
)
}
</
span
>
<
span
className=
"text-gray-400 text-sm ml-1"
>
(
{
comments
.
length
}
)
</
span
>
</
div
>
<
Button
variant=
"plain"
color=
"neutral"
onClick=
{
handleShowCommentEditor
}
>
<
span
className=
"font-normal text-gray-500"
>
{
t
(
"memo.comment.write-a-comment"
)
}
</
span
>
</
Button
>
</
div
>
<
Button
variant=
"plain"
color=
"neutral"
onClick=
{
handleShowCommentEditor
}
>
<
span
className=
"font-normal text-gray-500"
>
{
t
(
"memo.comment.write-a-comment"
)
}
</
span
>
</
Button
>
</
div
>
{
comments
.
map
((
comment
)
=>
(
<
MemoView
key=
{
`${comment.name}-${comment.displayTime}`
}
memo=
{
comment
}
showCreator
compact
/>
))
}
</>
)
}
{
comments
.
map
((
comment
)
=>
(
<
MemoView
key=
{
`${comment.name}-${comment.displayTime}`
}
memo=
{
comment
}
showCreator
compact
/>
))
}
</>
)
}
</
div
>
</
div
>
</
div
>
{
md
&&
(
<
div
className=
"sticky top-0 left-0 shrink-0 -mt-6 w-56 h-full"
>
<
MemoDetailSidebar
className=
"py-6"
memo=
{
memo
}
/>
</
div
>
)
}
</
div
>
</
section
>
);
...
...
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