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
25efc33b
Commit
25efc33b
authored
Feb 05, 2024
by
Steven
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
chore: tweak timeline styles
parent
ba460382
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
134 additions
and
65 deletions
+134
-65
TimelineSidebar.tsx
web/src/components/TimelineSidebar.tsx
+23
-0
TimelineSidebarDrawer.tsx
web/src/components/TimelineSidebarDrawer.tsx
+37
-0
Timeline.tsx
web/src/pages/Timeline.tsx
+73
-64
vite.config.ts
web/vite.config.ts
+1
-1
No files found.
web/src/components/TimelineSidebar.tsx
0 → 100644
View file @
25efc33b
import
classNames
from
"classnames"
;
import
SearchBar
from
"./SearchBar"
;
import
TagList
from
"./TagList"
;
interface
Props
{
className
?:
string
;
}
const
TimelineSidebar
=
(
props
:
Props
)
=>
{
return
(
<
aside
className=
{
classNames
(
"relative w-full h-auto max-h-screen overflow-auto hide-scrollbar flex flex-col justify-start items-start"
,
props
.
className
,
)
}
>
<
SearchBar
/>
<
TagList
/>
</
aside
>
);
};
export
default
TimelineSidebar
;
web/src/components/TimelineSidebarDrawer.tsx
0 → 100644
View file @
25efc33b
import
{
Drawer
,
IconButton
}
from
"@mui/joy"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
Icon
from
"./Icon"
;
import
TimelineSidebar
from
"./TimelineSidebar"
;
const
TimelineSidebarDrawer
=
()
=>
{
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
.
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"
>
<
TimelineSidebar
className=
"py-4"
/>
</
div
>
</
Drawer
>
</>
);
};
export
default
TimelineSidebarDrawer
;
web/src/pages/Timeline.tsx
View file @
25efc33b
import
{
Button
,
Divider
,
IconButton
}
from
"@mui/joy"
;
import
classNames
from
"classnames"
;
import
{
sum
}
from
"lodash-es"
;
import
{
Fragment
,
useEffect
,
useRef
,
useState
}
from
"react"
;
import
ActivityCalendar
from
"@/components/ActivityCalendar"
;
import
Empty
from
"@/components/Empty"
;
...
...
@@ -9,6 +8,8 @@ import showMemoEditorDialog from "@/components/MemoEditor/MemoEditorDialog";
import
MemoFilter
from
"@/components/MemoFilter"
;
import
MemoView
from
"@/components/MemoView"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
TimelineSidebar
from
"@/components/TimelineSidebar"
;
import
TimelineSidebarDrawer
from
"@/components/TimelineSidebarDrawer"
;
import
{
memoServiceClient
}
from
"@/grpcweb"
;
import
{
DAILY_TIMESTAMP
,
DEFAULT_MEMO_LIMIT
}
from
"@/helpers/consts"
;
import
{
getNormalizedTimeString
,
getTimeStampByDate
}
from
"@/helpers/datetime"
;
...
...
@@ -120,50 +121,53 @@ const Timeline = () => {
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"
>
<
div
className=
"w-full shadow flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-800 text-black dark:text-gray-300"
>
<
div
className=
"relative w-full flex flex-row justify-between items-center"
>
<
div
>
<
div
className=
"py-1 flex flex-row justify-start items-center select-none opacity-80"
onClick=
{
()
=>
setSelectedDay
(
undefined
)
}
>
<
Icon
.
GanttChartSquare
className=
"w-6 h-auto mr-1 opacity-80"
/>
<
span
className=
"text-lg"
>
{
t
(
"timeline.title"
)
}
</
span
>
{
!
md
&&
(
<
MobileHeader
>
<
TimelineSidebarDrawer
/>
</
MobileHeader
>
)
}
<
div
className=
{
classNames
(
"w-full flex flex-row justify-start items-start px-4 sm:px-6 gap-4"
)
}
>
<
div
className=
{
classNames
(
md
?
"w-[calc(100%-15rem)]"
:
"w-full"
)
}
>
<
div
className=
"w-full shadow flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-800 text-black dark:text-gray-300"
>
<
div
className=
"relative w-full flex flex-row justify-between items-center"
>
<
div
>
<
div
className=
"py-1 flex flex-row justify-start items-center select-none opacity-80"
onClick=
{
()
=>
setSelectedDay
(
undefined
)
}
>
<
Icon
.
GanttChartSquare
className=
"w-6 h-auto mr-1 opacity-80"
/>
<
span
className=
"text-lg"
>
{
t
(
"timeline.title"
)
}
</
span
>
</
div
>
</
div
>
<
div
className=
"flex justify-end items-center gap-2"
>
<
IconButton
variant=
"outlined"
size=
"sm"
onClick=
{
()
=>
handleNewMemo
()
}
>
<
Icon
.
Plus
className=
"w-5 h-auto"
/>
</
IconButton
>
</
div
>
</
div
>
<
div
className=
"flex justify-end items-center gap-2"
>
<
IconButton
variant=
"outlined"
size=
"sm"
onClick=
{
()
=>
handleNewMemo
()
}
>
<
Icon
.
Plus
className=
"w-5 h-auto"
/>
</
IconButton
>
</
div
>
</
div
>
<
div
className=
"w-full h-auto flex flex-col justify-start items-start"
>
<
MemoFilter
className=
"px-2 my-4"
/>
<
div
className=
"w-full h-auto flex flex-col justify-start items-start"
>
<
MemoFilter
className=
"px-2 my-4"
/>
{
groupedByMonth
.
map
((
group
,
index
)
=>
(
<
Fragment
key=
{
group
.
month
}
>
<
div
className=
{
classNames
(
"flex justify-start items-start w-full mt-2 last:mb-4"
,
md
?
"flex-row"
:
"flex-col"
)
}
>
<
div
className=
{
classNames
(
"flex shrink-0"
,
md
?
"flex-col w-40 pr-4 pl-2 pb-8"
:
"flex-row w-full pl-1 mt-2 mb-2"
)
}
>
<
div
className=
{
classNames
(
"w-full flex flex-col"
,
md
&&
"mt-4 mb-2"
)
}
>
<
span
className=
"font-medium text-3xl leading-none mb-1"
>
{
new
Date
(
group
.
month
).
toLocaleString
(
i18n
.
language
,
{
month
:
"short"
,
timeZone
:
"UTC"
})
}
</
span
>
<
span
className=
"opacity-60"
>
{
new
Date
(
group
.
month
).
getUTCFullYear
()
}
</
span
>
<
span
className=
"text-xs opacity-40"
>
Total:
{
sum
(
Object
.
values
(
group
.
data
))
}
</
span
>
{
groupedByMonth
.
map
((
group
,
index
)
=>
(
<
Fragment
key=
{
group
.
month
}
>
<
div
className=
{
classNames
(
"flex flex-col justify-start items-start w-full mt-2 last:mb-4"
)
}
>
<
div
className=
{
classNames
(
"flex shrink-0 flex-row w-full pl-1 mt-2 mb-2"
)
}
>
<
div
className=
{
classNames
(
"w-full flex flex-col"
)
}
>
<
span
className=
"font-medium text-3xl leading-none mb-1"
>
{
new
Date
(
group
.
month
).
toLocaleString
(
i18n
.
language
,
{
month
:
"short"
,
timeZone
:
"UTC"
})
}
</
span
>
<
span
className=
"opacity-60"
>
{
new
Date
(
group
.
month
).
getUTCFullYear
()
}
</
span
>
</
div
>
<
ActivityCalendar
month=
{
group
.
month
}
data=
{
group
.
data
}
onClick=
{
(
date
)
=>
setSelectedDay
(
date
)
}
/>
</
div
>
<
ActivityCalendar
month=
{
group
.
month
}
data=
{
group
.
data
}
onClick=
{
(
date
)
=>
setSelectedDay
(
date
)
}
/>
</
div
>
<
div
className=
{
classNames
(
"flex flex-col justify-start items-start"
,
md
?
"w-[calc(100%-8rem)]"
:
"w-full"
)
}
>
{
group
.
memos
.
map
((
memo
,
index
)
=>
(
<
div
key=
{
`${memo.id}-${memo.displayTime}`
}
className=
{
classNames
(
"relative w-full flex flex-col justify-start items-start pl-4 sm:pl-10 pt-0"
)
}
>
<
MemoView
className=
"!border !border-gray-100 dark:!border-zinc-700"
memo=
{
memo
}
/>
{
group
.
memos
.
length
>
1
&&
(
<
div
className=
{
classNames
(
"w-full flex flex-col justify-start items-start"
)
}
>
{
group
.
memos
.
map
((
memo
,
index
)
=>
(
<
div
key=
{
`${memo.id}-${memo.displayTime}`
}
className=
{
classNames
(
"relative w-full flex flex-col justify-start items-start pl-4 sm:pl-10 pt-0"
)
}
>
<
MemoView
className=
"!border max-w-full !border-gray-100 dark:!border-zinc-700"
memo=
{
memo
}
/>
<
div
className=
"absolute -left-2 sm:left-2 top-4 h-full"
>
{
index
!==
group
.
memos
.
length
-
1
&&
(
<
div
className=
"absolute top-2 left-[7px] h-full w-0.5 bg-gray-200 dark:bg-gray-700 block"
></
div
>
...
...
@@ -172,35 +176,40 @@ const Timeline = () => {
<
Icon
.
Circle
className=
"w-2 h-auto bg-gray-200 text-gray-200 dark:bg-gray-700 dark:text-gray-700 rounded-full"
/>
</
div
>
</
div
>
)
}
</
div
>
))
}
</
div
>
))
}
</
div
>
</
div
>
{
index
!==
groupedByMonth
.
length
-
1
&&
<
Divider
className=
"w-full !my-4 md:!mb-8 !bg-gray-100 dark:!bg-zinc-700"
/>
}
</
Fragment
>
))
}
{
isRequesting
?
(
<
div
className=
"flex flex-row justify-center items-center w-full my-4 text-gray-400"
>
<
Icon
.
Loader
className=
"w-4 h-auto animate-spin mr-1"
/>
<
p
className=
"text-sm italic"
>
{
t
(
"memo.fetching-data"
)
}
</
p
>
</
div
>
{
index
!==
groupedByMonth
.
length
-
1
&&
<
Divider
className=
"w-full !my-4 md:!mb-8 !bg-gray-100 dark:!bg-zinc-700"
/>
}
</
Fragment
>
))
}
{
isRequesting
?
(
<
div
className=
"flex flex-row justify-center items-center w-full my-4 text-gray-400"
>
<
Icon
.
Loader
className=
"w-4 h-auto animate-spin mr-1"
/>
<
p
className=
"text-sm italic"
>
{
t
(
"memo.fetching-data"
)
}
</
p
>
</
div
>
)
:
!
nextPageTokenRef
.
current
?
(
sortedMemos
.
length
===
0
&&
(
<
div
className=
"w-full mt-12 mb-8 flex flex-col justify-center items-center italic"
>
<
Empty
/>
<
p
className=
"mt-2 text-gray-600 dark:text-gray-400"
>
{
t
(
"message.no-data"
)
}
</
p
>
)
:
!
nextPageTokenRef
.
current
?
(
sortedMemos
.
length
===
0
&&
(
<
div
className=
"w-full mt-12 mb-8 flex flex-col justify-center items-center italic"
>
<
Empty
/>
<
p
className=
"mt-2 text-gray-600 dark:text-gray-400"
>
{
t
(
"message.no-data"
)
}
</
p
>
</
div
>
)
)
:
(
<
div
className=
"w-full flex flex-row justify-center items-center my-4"
>
<
Button
variant=
"plain"
endDecorator=
{
<
Icon
.
ArrowDown
className=
"w-5 h-auto"
/>
}
onClick=
{
fetchMemos
}
>
{
t
(
"memo.fetch-more"
)
}
</
Button
>
</
div
>
)
)
:
(
<
div
className=
"w-full flex flex-row justify-center items-center my-4"
>
<
Button
variant=
"plain"
endDecorator=
{
<
Icon
.
ArrowDown
className=
"w-5 h-auto"
/>
}
onClick=
{
fetchMemos
}
>
{
t
(
"memo.fetch-more"
)
}
</
Button
>
</
div
>
)
}
)
}
</
div
>
</
div
>
</
div
>
{
md
&&
(
<
div
className=
"sticky top-0 left-0 shrink-0 -mt-6 w-56 h-full"
>
<
TimelineSidebar
className=
"py-6"
/>
</
div
>
)
}
</
div
>
</
section
>
);
...
...
web/vite.config.ts
View file @
25efc33b
...
...
@@ -2,7 +2,7 @@ import react from "@vitejs/plugin-react";
import
{
resolve
}
from
"path"
;
import
{
defineConfig
}
from
"vite"
;
let
devProxyServer
=
"http://localhost:8081
/
"
;
let
devProxyServer
=
"http://localhost:8081"
;
if
(
process
.
env
.
DEV_PROXY_SERVER
&&
process
.
env
.
DEV_PROXY_SERVER
.
length
>
0
)
{
console
.
log
(
"Use devProxyServer from environment: "
,
process
.
env
.
DEV_PROXY_SERVER
);
devProxyServer
=
process
.
env
.
DEV_PROXY_SERVER
;
...
...
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