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
e9ac6aff
Unverified
Commit
e9ac6aff
authored
Sep 08, 2022
by
boojack
Committed by
GitHub
Sep 08, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: add explore page (#205)
parent
5eea1339
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
209 additions
and
12 deletions
+209
-12
memo.go
server/memo.go
+4
-4
ArchivedMemo.tsx
web/src/components/ArchivedMemo.tsx
+2
-2
MemoContent.tsx
web/src/components/MemoContent.tsx
+29
-0
MemoList.tsx
web/src/components/MemoList.tsx
+1
-1
MemosHeader.tsx
web/src/components/MemosHeader.tsx
+1
-1
MenuBtnsPopup.tsx
web/src/components/MenuBtnsPopup.tsx
+9
-2
api.ts
web/src/helpers/api.ts
+4
-0
explore.less
web/src/less/explore.less
+58
-0
Explore.tsx
web/src/pages/Explore.tsx
+86
-0
Home.tsx
web/src/pages/Home.tsx
+1
-1
appRouter.tsx
web/src/routers/appRouter.tsx
+2
-0
memoService.ts
web/src/services/memoService.ts
+10
-0
location.ts
web/src/store/modules/location.ts
+1
-1
memo.d.ts
web/src/types/modules/memo.d.ts
+1
-0
No files found.
server/memo.go
View file @
e9ac6aff
...
@@ -162,10 +162,6 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
...
@@ -162,10 +162,6 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
memoFind
.
VisibilityList
=
[]
api
.
Visibility
{
api
.
Public
,
api
.
Protected
}
memoFind
.
VisibilityList
=
[]
api
.
Visibility
{
api
.
Public
,
api
.
Protected
}
}
}
rowStatus
:=
api
.
RowStatus
(
c
.
QueryParam
(
"rowStatus"
))
if
rowStatus
!=
""
{
memoFind
.
RowStatus
=
&
rowStatus
}
pinnedStr
:=
c
.
QueryParam
(
"pinned"
)
pinnedStr
:=
c
.
QueryParam
(
"pinned"
)
if
pinnedStr
!=
""
{
if
pinnedStr
!=
""
{
pinned
:=
pinnedStr
==
"true"
pinned
:=
pinnedStr
==
"true"
...
@@ -191,6 +187,10 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
...
@@ -191,6 +187,10 @@ func (s *Server) registerMemoRoutes(g *echo.Group) {
memoFind
.
Offset
=
offset
memoFind
.
Offset
=
offset
}
}
// Only fetch normal status memos.
normalStatus
:=
api
.
Normal
memoFind
.
RowStatus
=
&
normalStatus
list
,
err
:=
s
.
Store
.
FindMemoList
(
ctx
,
memoFind
)
list
,
err
:=
s
.
Store
.
FindMemoList
(
ctx
,
memoFind
)
if
err
!=
nil
{
if
err
!=
nil
{
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to fetch all memo list"
)
.
SetInternal
(
err
)
return
echo
.
NewHTTPError
(
http
.
StatusInternalServerError
,
"Failed to fetch all memo list"
)
.
SetInternal
(
err
)
...
...
web/src/components/ArchivedMemo.tsx
View file @
e9ac6aff
...
@@ -28,7 +28,7 @@ const ArchivedMemo: React.FC<Props> = (props: Props) => {
...
@@ -28,7 +28,7 @@ const ArchivedMemo: React.FC<Props> = (props: Props) => {
if
(
showConfirmDeleteBtn
)
{
if
(
showConfirmDeleteBtn
)
{
try
{
try
{
await
memoService
.
deleteMemoById
(
memo
.
id
);
await
memoService
.
deleteMemoById
(
memo
.
id
);
await
memoService
.
fetch
All
Memos
();
await
memoService
.
fetchMemos
();
}
catch
(
error
:
any
)
{
}
catch
(
error
:
any
)
{
console
.
error
(
error
);
console
.
error
(
error
);
toastHelper
.
error
(
error
.
response
.
data
.
message
);
toastHelper
.
error
(
error
.
response
.
data
.
message
);
...
@@ -44,7 +44,7 @@ const ArchivedMemo: React.FC<Props> = (props: Props) => {
...
@@ -44,7 +44,7 @@ const ArchivedMemo: React.FC<Props> = (props: Props) => {
id
:
memo
.
id
,
id
:
memo
.
id
,
rowStatus
:
"NORMAL"
,
rowStatus
:
"NORMAL"
,
});
});
await
memoService
.
fetch
All
Memos
();
await
memoService
.
fetchMemos
();
toastHelper
.
info
(
"Restored successfully"
);
toastHelper
.
info
(
"Restored successfully"
);
}
catch
(
error
:
any
)
{
}
catch
(
error
:
any
)
{
console
.
error
(
error
);
console
.
error
(
error
);
...
...
web/src/components/MemoContent.tsx
0 → 100644
View file @
e9ac6aff
import
{
useRef
}
from
"react"
;
import
{
formatMemoContent
}
from
"../helpers/marked"
;
import
"../less/memo-content.less"
;
interface
Props
{
className
:
string
;
content
:
string
;
onMemoContentClick
:
(
e
:
React
.
MouseEvent
)
=>
void
;
}
const
MemoContent
:
React
.
FC
<
Props
>
=
(
props
:
Props
)
=>
{
const
{
className
,
content
,
onMemoContentClick
}
=
props
;
const
memoContentContainerRef
=
useRef
<
HTMLDivElement
>
(
null
);
const
handleMemoContentClick
=
async
(
e
:
React
.
MouseEvent
)
=>
{
onMemoContentClick
(
e
);
};
return
(
<
div
ref=
{
memoContentContainerRef
}
className=
{
`memo-content-text ${className}`
}
onClick=
{
handleMemoContentClick
}
dangerouslySetInnerHTML=
{
{
__html
:
formatMemoContent
(
content
)
}
}
></
div
>
);
};
export
default
MemoContent
;
web/src/components/MemoList.tsx
View file @
e9ac6aff
...
@@ -80,7 +80,7 @@ const MemoList = () => {
...
@@ -80,7 +80,7 @@ const MemoList = () => {
useEffect(() =
>
{
useEffect(() =
>
{
memoService
memoService
.
fetch
All
Memos
()
.
fetchMemos
()
.
then
(()
=>
{
.
then
(()
=>
{
// do nth
// do nth
})
})
...
...
web/src/components/MemosHeader.tsx
View file @
e9ac6aff
...
@@ -29,7 +29,7 @@ const MemosHeader = () => {
...
@@ -29,7 +29,7 @@ const MemosHeader = () => {
const
now
=
Date
.
now
();
const
now
=
Date
.
now
();
if
(
now
-
prevRequestTimestamp
>
1
*
1000
)
{
if
(
now
-
prevRequestTimestamp
>
1
*
1000
)
{
prevRequestTimestamp
=
now
;
prevRequestTimestamp
=
now
;
memoService
.
fetch
All
Memos
().
catch
(()
=>
{
memoService
.
fetchMemos
().
catch
(()
=>
{
// do nth
// do nth
});
});
}
}
...
...
web/src/components/MenuBtnsPopup.tsx
View file @
e9ac6aff
...
@@ -51,6 +51,10 @@ const MenuBtnsPopup: React.FC<Props> = (props: Props) => {
...
@@ -51,6 +51,10 @@ const MenuBtnsPopup: React.FC<Props> = (props: Props) => {
showAboutSiteDialog
();
showAboutSiteDialog
();
};
};
const
handleExploreBtnClick
=
()
=>
{
locationService
.
pushHistory
(
"/explore"
);
};
const
handleSignOutBtnClick
=
async
()
=>
{
const
handleSignOutBtnClick
=
async
()
=>
{
userService
userService
.
doSignOut
()
.
doSignOut
()
...
@@ -65,12 +69,15 @@ const MenuBtnsPopup: React.FC<Props> = (props: Props) => {
...
@@ -65,12 +69,15 @@ const MenuBtnsPopup: React.FC<Props> = (props: Props) => {
return
(
return
(
<
div
className=
{
`menu-btns-popup ${shownStatus ? "" : "hidden"}`
}
ref=
{
popupElRef
}
>
<
div
className=
{
`menu-btns-popup ${shownStatus ? "" : "hidden"}`
}
ref=
{
popupElRef
}
>
<
button
className=
"btn action-btn"
onClick=
{
handle
About
BtnClick
}
>
<
button
className=
"btn action-btn"
onClick=
{
handle
Explore
BtnClick
}
>
<
span
className=
"icon"
>
🤠
</
span
>
{
t
(
"common.about"
)
}
<
span
className=
"icon"
>
👾
</
span
>
Explore
</
button
>
</
button
>
<
button
className=
"btn action-btn"
onClick=
{
handlePingBtnClick
}
>
<
button
className=
"btn action-btn"
onClick=
{
handlePingBtnClick
}
>
<
span
className=
"icon"
>
🎯
</
span
>
Ping
<
span
className=
"icon"
>
🎯
</
span
>
Ping
</
button
>
</
button
>
<
button
className=
"btn action-btn"
onClick=
{
handleAboutBtnClick
}
>
<
span
className=
"icon"
>
🤠
</
span
>
{
t
(
"common.about"
)
}
</
button
>
<
Only
when=
{
!
userService
.
isVisitorMode
()
}
>
<
Only
when=
{
!
userService
.
isVisitorMode
()
}
>
<
button
className=
"btn action-btn"
onClick=
{
handleSignOutBtnClick
}
>
<
button
className=
"btn action-btn"
onClick=
{
handleSignOutBtnClick
}
>
<
span
className=
"icon"
>
👋
</
span
>
{
t
(
"common.sign-out"
)
}
<
span
className=
"icon"
>
👋
</
span
>
{
t
(
"common.sign-out"
)
}
...
...
web/src/helpers/api.ts
View file @
e9ac6aff
...
@@ -58,6 +58,10 @@ export function deleteUser(userDelete: UserDelete) {
...
@@ -58,6 +58,10 @@ export function deleteUser(userDelete: UserDelete) {
return
axios
.
delete
(
`/api/user/
${
userDelete
.
id
}
`
);
return
axios
.
delete
(
`/api/user/
${
userDelete
.
id
}
`
);
}
}
export
function
getAllMemos
()
{
return
axios
.
get
<
ResponseObject
<
Memo
[]
>>
(
"/api/memo/all"
);
}
export
function
getMemoList
(
memoFind
?:
MemoFind
)
{
export
function
getMemoList
(
memoFind
?:
MemoFind
)
{
const
queryList
=
[];
const
queryList
=
[];
if
(
memoFind
?.
creatorId
)
{
if
(
memoFind
?.
creatorId
)
{
...
...
web/src/less/explore.less
0 → 100644
View file @
e9ac6aff
@import "./mixin.less";
.page-wrapper.explore {
@apply relative top-0 w-full h-screen overflow-y-auto overflow-x-hidden;
background-color: #f6f5f4;
> .page-container {
@apply relative w-full min-h-screen mx-auto flex flex-col justify-start items-center;
> .page-header {
@apply relative max-w-2xl w-full min-h-full flex flex-row justify-start items-center px-4 sm:pr-6;
> .logo-img {
@apply h-14 w-auto mt-6 mb-2;
}
}
> .memos-wrapper {
@apply relative flex-grow max-w-2xl w-full min-h-full flex flex-col justify-start items-start px-4 sm:pr-6;
> .memo-container {
@apply flex flex-col justify-start items-start w-full p-4 mt-2 bg-white rounded-lg border border-white hover:border-gray-200;
> .memo-header {
@apply mb-2 w-full flex flex-row justify-start items-center text-sm font-mono text-gray-400;
> .split-text {
@apply mx-2;
}
> .name-text {
@apply hover:text-green-600 hover:underline;
}
}
> .memo-content {
@apply cursor-default;
> * {
@apply cursor-default;
}
}
}
}
> .addtion-btn-container {
@apply fixed bottom-12 left-1/2 -translate-x-1/2;
> .btn {
@apply bg-blue-600 text-white px-4 py-2 rounded-3xl shadow-2xl hover:opacity-80;
> .icon {
@apply text-lg mr-1;
}
}
}
}
}
web/src/pages/Explore.tsx
0 → 100644
View file @
e9ac6aff
import
dayjs
from
"dayjs"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
locationService
,
memoService
,
userService
}
from
"../services"
;
import
{
useAppSelector
}
from
"../store"
;
import
useI18n
from
"../hooks/useI18n"
;
import
useLoading
from
"../hooks/useLoading"
;
import
MemoContent
from
"../components/MemoContent"
;
import
"../less/explore.less"
;
interface
State
{
memos
:
Memo
[];
}
const
Explore
=
()
=>
{
const
{
t
,
locale
}
=
useI18n
();
const
user
=
useAppSelector
((
state
)
=>
state
.
user
.
user
);
const
location
=
useAppSelector
((
state
)
=>
state
.
location
);
const
[
state
,
setState
]
=
useState
<
State
>
({
memos
:
[],
});
const
loadingState
=
useLoading
();
useEffect
(()
=>
{
userService
.
initialState
()
.
catch
()
.
finally
(
async
()
=>
{
const
{
host
}
=
userService
.
getState
();
if
(
!
host
)
{
locationService
.
replaceHistory
(
"/auth"
);
return
;
}
memoService
.
fetchAllMemos
().
then
((
memos
)
=>
{
setState
({
...
state
,
memos
,
});
});
loadingState
.
setFinish
();
});
},
[
location
]);
return
(
<
section
className=
"page-wrapper explore"
>
{
loadingState
.
isLoading
?
null
:
(
<
div
className=
"page-container"
>
<
div
className=
"page-header"
>
<
img
className=
"logo-img"
src=
"/logo-full.webp"
alt=
""
/>
</
div
>
<
main
className=
"memos-wrapper"
>
{
state
.
memos
.
map
((
memo
)
=>
{
const
createdAtStr
=
dayjs
(
memo
.
createdTs
).
locale
(
locale
).
format
(
"YYYY/MM/DD HH:mm:ss"
);
return
(
<
div
className=
"memo-container"
key=
{
memo
.
id
}
>
<
div
className=
"memo-header"
>
<
span
className=
"time-text"
>
{
createdAtStr
}
</
span
>
<
span
className=
"split-text"
>
by
</
span
>
<
a
className=
"name-text"
href=
{
`/u/${memo.creator.id}`
}
>
{
memo
.
creator
.
name
}
</
a
>
</
div
>
<
MemoContent
className=
"memo-content"
content=
{
memo
.
content
}
onMemoContentClick=
{
()
=>
undefined
}
/>
</
div
>
);
})
}
</
main
>
<
div
className=
"addtion-btn-container"
>
{
user
?
(
<
button
className=
"btn"
onClick=
{
()
=>
(
window
.
location
.
href
=
"/"
)
}
>
<
span
className=
"icon"
>
🏠
</
span
>
{
t
(
"common.back-to-home"
)
}
</
button
>
)
:
(
<
button
className=
"btn"
onClick=
{
()
=>
(
window
.
location
.
href
=
"/auth"
)
}
>
<
span
className=
"icon"
>
👉
</
span
>
{
t
(
"common.sign-in"
)
}
</
button
>
)
}
</
div
>
</
div
>
)
}
</
section
>
);
};
export
default
Explore
;
web/src/pages/Home.tsx
View file @
e9ac6aff
...
@@ -35,7 +35,7 @@ function Home() {
...
@@ -35,7 +35,7 @@ function Home() {
}
}
}
else
{
}
else
{
if
(
!
user
)
{
if
(
!
user
)
{
locationService
.
replaceHistory
(
`/
u/
${
host
.
id
}
`
);
locationService
.
replaceHistory
(
`/
explore
`
);
}
}
}
}
loadingState
.
setFinish
();
loadingState
.
setFinish
();
...
...
web/src/routers/appRouter.tsx
View file @
e9ac6aff
import
Home
from
"../pages/Home"
;
import
Home
from
"../pages/Home"
;
import
Auth
from
"../pages/Auth"
;
import
Auth
from
"../pages/Auth"
;
import
Explore
from
"../pages/Explore"
;
const
appRouter
=
{
const
appRouter
=
{
"/auth"
:
<
Auth
/>
,
"/auth"
:
<
Auth
/>
,
"/explore"
:
<
Explore
/>
,
"*"
:
<
Home
/>
,
"*"
:
<
Home
/>
,
};
};
...
...
web/src/services/memoService.ts
View file @
e9ac6aff
...
@@ -17,6 +17,16 @@ const memoService = {
...
@@ -17,6 +17,16 @@ const memoService = {
},
},
fetchAllMemos
:
async
()
=>
{
fetchAllMemos
:
async
()
=>
{
const
memoFind
:
MemoFind
=
{};
if
(
userService
.
isVisitorMode
())
{
memoFind
.
creatorId
=
userService
.
getUserIdFromPath
();
}
const
{
data
}
=
(
await
api
.
getAllMemos
()).
data
;
const
memos
=
data
.
map
((
m
)
=>
convertResponseModelMemo
(
m
));
return
memos
;
},
fetchMemos
:
async
()
=>
{
const
timeoutIndex
=
setTimeout
(()
=>
{
const
timeoutIndex
=
setTimeout
(()
=>
{
store
.
dispatch
(
setIsFetching
(
true
));
store
.
dispatch
(
setIsFetching
(
true
));
},
1000
);
},
1000
);
...
...
web/src/store/modules/location.ts
View file @
e9ac6aff
...
@@ -21,7 +21,7 @@ interface State {
...
@@ -21,7 +21,7 @@ interface State {
const
getValidPathname
=
(
pathname
:
string
):
string
=>
{
const
getValidPathname
=
(
pathname
:
string
):
string
=>
{
const
userPageUrlRegex
=
/^
\/
u
\/\d
+.*/
;
const
userPageUrlRegex
=
/^
\/
u
\/\d
+.*/
;
if
([
"/"
,
"/auth"
].
includes
(
pathname
)
||
userPageUrlRegex
.
test
(
pathname
))
{
if
([
"/"
,
"/auth"
,
"/explore"
].
includes
(
pathname
)
||
userPageUrlRegex
.
test
(
pathname
))
{
return
pathname
;
return
pathname
;
}
else
{
}
else
{
return
"/"
;
return
"/"
;
...
...
web/src/types/modules/memo.d.ts
View file @
e9ac6aff
...
@@ -6,6 +6,7 @@ interface Memo {
...
@@ -6,6 +6,7 @@ interface Memo {
id
:
MemoId
;
id
:
MemoId
;
creatorId
:
UserId
;
creatorId
:
UserId
;
creator
:
User
;
createdTs
:
TimeStamp
;
createdTs
:
TimeStamp
;
updatedTs
:
TimeStamp
;
updatedTs
:
TimeStamp
;
rowStatus
:
RowStatus
;
rowStatus
:
RowStatus
;
...
...
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