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
004713d4
Commit
004713d4
authored
Sep 20, 2022
by
Steven
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
chore: update dropdown component
parent
7a6eb53e
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
139 additions
and
163 deletions
+139
-163
MenuBtnsPopup.tsx
web/src/components/MenuBtnsPopup.tsx
+0
-82
ResourcesDialog.tsx
web/src/components/ResourcesDialog.tsx
+25
-7
MemberSection.tsx
web/src/components/Settings/MemberSection.tsx
+28
-10
UserBanner.tsx
web/src/components/UserBanner.tsx
+61
-8
Dropdown.tsx
web/src/components/common/Dropdown.tsx
+25
-10
dropdown.less
web/src/less/common/dropdown.less
+0
-21
menu-btns-popup.less
web/src/less/menu-btns-popup.less
+0
-13
resources-dialog.less
web/src/less/resources-dialog.less
+0
-6
member-section.less
web/src/less/settings/member-section.less
+0
-6
No files found.
web/src/components/MenuBtnsPopup.tsx
deleted
100644 → 0
View file @
7a6eb53e
import
{
useEffect
,
useRef
}
from
"react"
;
import
{
useTranslation
}
from
"react-i18next"
;
import
{
useNavigate
}
from
"react-router-dom"
;
import
{
userService
}
from
"../services"
;
import
Only
from
"./common/OnlyWhen"
;
import
showAboutSiteDialog
from
"./AboutSiteDialog"
;
import
showArchivedMemoDialog
from
"./ArchivedMemoDialog"
;
import
showResourcesDialog
from
"./ResourcesDialog"
;
import
"../less/menu-btns-popup.less"
;
interface
Props
{
shownStatus
:
boolean
;
setShownStatus
:
(
status
:
boolean
)
=>
void
;
}
const
MenuBtnsPopup
:
React
.
FC
<
Props
>
=
(
props
:
Props
)
=>
{
const
{
shownStatus
,
setShownStatus
}
=
props
;
const
{
t
}
=
useTranslation
();
const
navigate
=
useNavigate
();
const
popupElRef
=
useRef
<
HTMLDivElement
>
(
null
);
useEffect
(()
=>
{
if
(
shownStatus
)
{
const
handleClickOutside
=
(
event
:
MouseEvent
)
=>
{
if
(
!
popupElRef
.
current
?.
contains
(
event
.
target
as
Node
))
{
event
.
stopPropagation
();
}
setShownStatus
(
false
);
};
window
.
addEventListener
(
"click"
,
handleClickOutside
,
{
capture
:
true
,
once
:
true
,
});
}
},
[
shownStatus
]);
const
handleResourcesBtnClick
=
()
=>
{
showResourcesDialog
();
};
const
handleArchivedBtnClick
=
()
=>
{
showArchivedMemoDialog
();
};
const
handleAboutBtnClick
=
()
=>
{
showAboutSiteDialog
();
};
const
handleSignOutBtnClick
=
async
()
=>
{
userService
.
doSignOut
()
.
then
(()
=>
{
navigate
(
"/auth"
);
})
.
catch
(()
=>
{
// do nth
});
};
return
(
<
div
className=
{
`menu-btns-popup ${shownStatus ? "" : "hidden"}`
}
ref=
{
popupElRef
}
>
<
Only
when=
{
!
userService
.
isVisitorMode
()
}
>
<
button
className=
"btn action-btn"
onClick=
{
handleResourcesBtnClick
}
>
<
span
className=
"icon"
>
🌄
</
span
>
{
t
(
"sidebar.resources"
)
}
</
button
>
<
button
className=
"btn action-btn"
onClick=
{
handleArchivedBtnClick
}
>
<
span
className=
"icon"
>
🗂
</
span
>
{
t
(
"sidebar.archived"
)
}
</
button
>
</
Only
>
<
button
className=
"btn action-btn"
onClick=
{
handleAboutBtnClick
}
>
<
span
className=
"icon"
>
🤠
</
span
>
{
t
(
"common.about"
)
}
</
button
>
<
Only
when=
{
!
userService
.
isVisitorMode
()
}
>
<
button
className=
"btn action-btn"
onClick=
{
handleSignOutBtnClick
}
>
<
span
className=
"icon"
>
👋
</
span
>
{
t
(
"common.sign-out"
)
}
</
button
>
</
Only
>
</
div
>
);
};
export
default
MenuBtnsPopup
;
web/src/components/ResourcesDialog.tsx
View file @
004713d4
...
...
@@ -154,13 +154,31 @@ const ResourcesDialog: React.FC<Props> = (props: Props) => {
<
span
className=
"field-text name-text"
>
{
resource
.
filename
}
</
span
>
<
span
className=
"field-text"
>
{
resource
.
type
}
</
span
>
<
div
className=
"buttons-container"
>
<
Dropdown
className=
"actions-dropdown"
>
<
button
onClick=
{
()
=>
handlPreviewBtnClick
(
resource
)
}
>
{
t
(
"resources.preview"
)
}
</
button
>
<
button
onClick=
{
()
=>
handleCopyResourceLinkBtnClick
(
resource
)
}
>
{
t
(
"resources.copy-link"
)
}
</
button
>
<
button
className=
"delete-btn"
onClick=
{
()
=>
handleDeleteResourceBtnClick
(
resource
)
}
>
{
t
(
"common.delete"
)
}
</
button
>
</
Dropdown
>
<
Dropdown
actionsClassName=
"!w-32"
actions=
{
<>
<
button
className=
"w-full px-3 text-left leading-10 cursor-pointer rounded hover:bg-gray-100"
onClick=
{
()
=>
handlPreviewBtnClick
(
resource
)
}
>
{
t
(
"resources.preview"
)
}
</
button
>
<
button
className=
"w-full px-3 text-left leading-10 cursor-pointer rounded hover:bg-gray-100"
onClick=
{
()
=>
handleCopyResourceLinkBtnClick
(
resource
)
}
>
{
t
(
"resources.copy-link"
)
}
</
button
>
<
button
className=
"w-full px-3 text-left leading-10 cursor-pointer rounded text-red-600 hover:bg-gray-100"
onClick=
{
()
=>
handleDeleteResourceBtnClick
(
resource
)
}
>
{
t
(
"common.delete"
)
}
</
button
>
</>
}
/>
</
div
>
</
div
>
))
...
...
web/src/components/Settings/MemberSection.tsx
View file @
004713d4
...
...
@@ -139,18 +139,36 @@ const PreferencesSection = () => {
{
currentUser
?.
id
===
user
.
id
?
(
<
span
className=
"tip-text"
>
{
t
(
"common.yourself"
)
}
</
span
>
)
:
(
<
Dropdown
className=
"actions-dropdown"
>
{
user
.
rowStatus
===
"NORMAL"
?
(
<
button
onClick=
{
()
=>
handleArchiveUserClick
(
user
)
}
>
{
t
(
"common.archive"
)
}
</
button
>
)
:
(
<
Dropdown
actionsClassName=
"!w-24"
actions=
{
<>
<
button
onClick=
{
()
=>
handleRestoreUserClick
(
user
)
}
>
{
t
(
"common.restore"
)
}
</
button
>
<
button
className=
"delete"
onClick=
{
()
=>
handleDeleteUserClick
(
user
)
}
>
{
t
(
"common.delete"
)
}
</
button
>
{
user
.
rowStatus
===
"NORMAL"
?
(
<
button
className=
"w-full px-3 text-left leading-10 cursor-pointer rounded hover:bg-gray-100"
onClick=
{
()
=>
handleArchiveUserClick
(
user
)
}
>
{
t
(
"common.archive"
)
}
</
button
>
)
:
(
<>
<
button
className=
"w-full px-3 text-left leading-10 cursor-pointer rounded hover:bg-gray-100"
onClick=
{
()
=>
handleRestoreUserClick
(
user
)
}
>
{
t
(
"common.restore"
)
}
</
button
>
<
button
className=
"w-full px-3 text-left leading-10 cursor-pointer rounded text-red-600 hover:bg-gray-100"
onClick=
{
()
=>
handleDeleteUserClick
(
user
)
}
>
{
t
(
"common.delete"
)
}
</
button
>
</>
)
}
</>
)
}
</
Dropdown
>
}
/
>
)
}
</
div
>
</
div
>
...
...
web/src/components/UserBanner.tsx
View file @
004713d4
import
{
useCallback
,
useEffect
,
useState
}
from
"react"
;
import
{
useTranslation
}
from
"react-i18next"
;
import
{
useNavigate
}
from
"react-router-dom"
;
import
*
as
utils
from
"../helpers/utils"
;
import
userService
from
"../services/userService"
;
import
{
locationService
}
from
"../services"
;
import
{
useAppSelector
}
from
"../store"
;
import
Icon
from
"./Icon"
;
import
MenuBtnsPopup
from
"./MenuBtnsPopup"
;
import
Dropdown
from
"./common/Dropdown"
;
import
Only
from
"./common/OnlyWhen"
;
import
showResourcesDialog
from
"./ResourcesDialog"
;
import
showArchivedMemoDialog
from
"./ArchivedMemoDialog"
;
import
showAboutSiteDialog
from
"./AboutSiteDialog"
;
import
"../less/user-banner.less"
;
const
UserBanner
=
()
=>
{
const
{
t
}
=
useTranslation
();
const
navigate
=
useNavigate
();
const
{
user
,
owner
}
=
useAppSelector
((
state
)
=>
state
.
user
);
const
{
memos
,
tags
}
=
useAppSelector
((
state
)
=>
state
.
memo
);
const
[
shouldShowPopupBtns
,
setShouldShowPopupBtns
]
=
useState
(
false
);
const
[
username
,
setUsername
]
=
useState
(
"Memos"
);
const
[
createdDays
,
setCreatedDays
]
=
useState
(
0
);
const
isVisitorMode
=
userService
.
isVisitorMode
();
...
...
@@ -34,8 +39,27 @@ const UserBanner = () => {
locationService
.
clearQuery
();
},
[]);
const
handlePopupBtnClick
=
()
=>
{
setShouldShowPopupBtns
(
true
);
const
handleResourcesBtnClick
=
()
=>
{
showResourcesDialog
();
};
const
handleArchivedBtnClick
=
()
=>
{
showArchivedMemoDialog
();
};
const
handleAboutBtnClick
=
()
=>
{
showAboutSiteDialog
();
};
const
handleSignOutBtnClick
=
async
()
=>
{
userService
.
doSignOut
()
.
then
(()
=>
{
navigate
(
"/auth"
);
})
.
catch
(()
=>
{
// do nth
});
};
return
(
...
...
@@ -45,10 +69,39 @@ const UserBanner = () => {
<
span
className=
"username-text"
>
{
username
}
</
span
>
{
!
isVisitorMode
&&
user
?.
role
===
"HOST"
?
<
span
className=
"tag"
>
MOD
</
span
>
:
null
}
</
div
>
<
button
className=
"action-btn menu-popup-btn"
onClick=
{
handlePopupBtnClick
}
>
<
Icon
.
MoreHorizontal
className=
"icon-img"
/>
</
button
>
<
MenuBtnsPopup
shownStatus=
{
shouldShowPopupBtns
}
setShownStatus=
{
setShouldShowPopupBtns
}
/>
<
Dropdown
trigger=
{
<
Icon
.
MoreHorizontal
className=
"w-5 h-auto cursor-pointer"
/>
}
actionsClassName=
"!w-36"
actions=
{
<>
<
Only
when=
{
!
userService
.
isVisitorMode
()
}
>
<
button
className=
"w-full px-3 text-left leading-10 cursor-pointer rounded hover:bg-gray-100"
onClick=
{
handleResourcesBtnClick
}
>
<
span
className=
"mr-1"
>
🌄
</
span
>
{
t
(
"sidebar.resources"
)
}
</
button
>
<
button
className=
"w-full px-3 text-left leading-10 cursor-pointer rounded hover:bg-gray-100"
onClick=
{
handleArchivedBtnClick
}
>
<
span
className=
"mr-1"
>
🗂
</
span
>
{
t
(
"sidebar.archived"
)
}
</
button
>
</
Only
>
<
button
className=
"w-full px-3 text-left leading-10 cursor-pointer rounded hover:bg-gray-100"
onClick=
{
handleAboutBtnClick
}
>
<
span
className=
"mr-1"
>
🤠
</
span
>
{
t
(
"common.about"
)
}
</
button
>
<
Only
when=
{
!
userService
.
isVisitorMode
()
}
>
<
button
className=
"w-full px-3 text-left leading-10 cursor-pointer rounded hover:bg-gray-100"
onClick=
{
handleSignOutBtnClick
}
>
<
span
className=
"mr-1"
>
👋
</
span
>
{
t
(
"common.sign-out"
)
}
</
button
>
</
Only
>
</>
}
/>
</
div
>
<
div
className=
"amount-text-container"
>
<
div
className=
"status-text memos-text"
>
...
...
web/src/components/common/Dropdown.tsx
View file @
004713d4
import
{
ReactNode
,
useEffect
,
useRef
}
from
"react"
;
import
useToggle
from
"../../hooks/useToggle"
;
import
Icon
from
"../Icon"
;
import
"../../less/common/dropdown.less"
;
interface
DropdownProps
{
children
?:
ReactNode
;
interface
Props
{
trigger
?:
ReactNode
;
actions
?:
ReactNode
;
className
?:
string
;
actionsClassName
?:
string
;
}
const
Dropdown
:
React
.
FC
<
DropdownProps
>
=
(
props
:
Dropdown
Props
)
=>
{
const
{
children
,
c
lassName
}
=
props
;
const
Dropdown
:
React
.
FC
<
Props
>
=
(
props
:
Props
)
=>
{
const
{
trigger
,
actions
,
className
,
actionsC
lassName
}
=
props
;
const
[
dropdownStatus
,
toggleDropdownStatus
]
=
useToggle
(
false
);
const
dropdownWrapperRef
=
useRef
<
HTMLDivElement
>
(
null
);
...
...
@@ -28,11 +29,25 @@ const Dropdown: React.FC<DropdownProps> = (props: DropdownProps) => {
},
[
dropdownStatus
]);
return
(
<
div
ref=
{
dropdownWrapperRef
}
className=
{
`dropdown-wrapper ${className ?? ""}`
}
onClick=
{
()
=>
toggleDropdownStatus
()
}
>
<
span
className=
"trigger-button"
>
<
Icon
.
MoreHorizontal
className=
"icon-img"
/>
</
span
>
<
div
className=
{
`action-buttons-container ${dropdownStatus ? "" : "!hidden"}`
}
>
{
children
}
</
div
>
<
div
ref=
{
dropdownWrapperRef
}
className=
{
`relative flex flex-col justify-start items-start select-none ${className ?? ""}`
}
onClick=
{
()
=>
toggleDropdownStatus
()
}
>
{
trigger
?
(
trigger
)
:
(
<
button
className=
"flex flex-row justify-center items-center border p-1 rounded shadow text-gray-600 cursor-pointer hover:opacity-80"
>
<
Icon
.
MoreHorizontal
className=
"w-4 h-auto"
/>
</
button
>
)
}
<
div
className=
{
`w-auto mt-1 absolute top-full right-0 flex flex-col justify-start items-start bg-white z-1 border p-1 rounded-md shadow ${
actionsClassName ?? ""
} ${dropdownStatus ? "" : "!hidden"}`
}
>
{
actions
}
</
div
>
</
div
>
);
};
...
...
web/src/less/common/dropdown.less
deleted
100644 → 0
View file @
7a6eb53e
@import "../mixin.less";
.dropdown-wrapper {
@apply relative flex flex-col justify-start items-start select-none;
> .trigger-button {
@apply flex flex-row justify-center items-center border p-1 rounded shadow text-gray-600 cursor-pointer hover:opacity-80;
> .icon-img {
@apply w-4 h-auto;
}
}
> .action-buttons-container {
@apply w-28 mt-1 absolute top-full right-0 flex flex-col justify-start items-start bg-white z-1 border p-1 rounded shadow;
> button {
@apply w-full text-left px-2 text-sm leading-7 rounded hover:bg-gray-100;
}
}
}
web/src/less/menu-btns-popup.less
deleted
100644 → 0
View file @
7a6eb53e
@import "./mixin.less";
.menu-btns-popup {
@apply absolute right-2 top-6 flex flex-col justify-start items-start mt-4 p-1 w-36 rounded-lg z-10 shadow bg-white;
> .btn {
@apply flex flex-row justify-start items-center w-full py-2 px-3 text-base rounded text-left hover:bg-gray-100;
> .icon {
@apply block w-6 text-center mr-2 text-base;
}
}
}
web/src/less/resources-dialog.less
View file @
004713d4
...
...
@@ -45,12 +45,6 @@
> .buttons-container {
@apply w-full flex flex-row justify-end items-center;
> .actions-dropdown {
.delete-btn {
@apply text-red-600;
}
}
}
}
...
...
web/src/less/settings/member-section.less
View file @
004713d4
...
...
@@ -52,12 +52,6 @@
> .tip-text {
@apply text-gray-400;
}
> .actions-dropdown {
.delete {
@apply text-red-600;
}
}
}
}
}
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