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
2dbf92f7
Unverified
Commit
2dbf92f7
authored
Aug 28, 2024
by
Michel Heusschen
Committed by
GitHub
Aug 28, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
perf: reduce bundle size by 21% with direct icon imports (#3844)
parent
d11bd30e
Changes
63
Hide whitespace changes
Inline
Side-by-side
Showing
63 changed files
with
222 additions
and
217 deletions
+222
-217
AppearanceSelect.tsx
web/src/components/AppearanceSelect.tsx
+4
-4
ChangeMemberPasswordDialog.tsx
web/src/components/ChangeMemberPasswordDialog.tsx
+2
-2
ChangePasswordDialog.tsx
web/src/components/ChangePasswordDialog.tsx
+2
-2
CreateAccessTokenDialog.tsx
web/src/components/CreateAccessTokenDialog.tsx
+2
-2
CreateIdentityProviderDialog.tsx
web/src/components/CreateIdentityProviderDialog.tsx
+2
-2
CreateWebhookDialog.tsx
web/src/components/CreateWebhookDialog.tsx
+2
-2
Empty.tsx
web/src/components/Empty.tsx
+2
-2
ExploreSidebarDrawer.tsx
web/src/components/ExploreSidebar/ExploreSidebarDrawer.tsx
+2
-2
HomeSidebarDrawer.tsx
web/src/components/HomeSidebar/HomeSidebarDrawer.tsx
+2
-2
TagsSection.tsx
web/src/components/HomeSidebar/TagsSection.tsx
+7
-7
Icon.tsx
web/src/components/Icon.tsx
+0
-3
MemoCommentMessage.tsx
web/src/components/Inbox/MemoCommentMessage.tsx
+3
-6
VersionUpdateMessage.tsx
web/src/components/Inbox/VersionUpdateMessage.tsx
+3
-6
LearnMore.tsx
web/src/components/LearnMore.tsx
+2
-2
LocaleSelect.tsx
web/src/components/LocaleSelect.tsx
+2
-2
MemoActionMenu.tsx
web/src/components/MemoActionMenu.tsx
+16
-7
CodeBlock.tsx
web/src/components/MemoContent/CodeBlock.tsx
+2
-2
EmbeddedMemo.tsx
...c/components/MemoContent/EmbeddedContent/EmbeddedMemo.tsx
+2
-2
MemoDetailSidebar.tsx
web/src/components/MemoDetailSidebar/MemoDetailSidebar.tsx
+5
-5
MemoDetailSidebarDrawer.tsx
.../components/MemoDetailSidebar/MemoDetailSidebarDrawer.tsx
+2
-2
MemoDisplaySettingMenu.tsx
web/src/components/MemoDisplaySettingMenu.tsx
+2
-2
AddMemoRelationPopover.tsx
...onents/MemoEditor/ActionButton/AddMemoRelationPopover.tsx
+2
-2
MarkdownMenu.tsx
web/src/components/MemoEditor/ActionButton/MarkdownMenu.tsx
+4
-4
TagSelector.tsx
web/src/components/MemoEditor/ActionButton/TagSelector.tsx
+2
-2
UploadResourceButton.tsx
...mponents/MemoEditor/ActionButton/UploadResourceButton.tsx
+2
-2
RelationListView.tsx
web/src/components/MemoEditor/RelationListView.tsx
+3
-3
ResourceListView.tsx
web/src/components/MemoEditor/ResourceListView.tsx
+2
-2
index.tsx
web/src/components/MemoEditor/index.tsx
+2
-2
MemoFilters.tsx
web/src/components/MemoFilters.tsx
+10
-10
MemoRelationListView.tsx
web/src/components/MemoRelationListView.tsx
+5
-5
MemoView.tsx
web/src/components/MemoView.tsx
+3
-3
Navigation.tsx
web/src/components/Navigation.tsx
+10
-10
NavigationDrawer.tsx
web/src/components/NavigationDrawer.tsx
+2
-2
PreviewImageDialog.tsx
web/src/components/PreviewImageDialog.tsx
+2
-2
ReactionSelector.tsx
web/src/components/ReactionSelector.tsx
+2
-2
RenameTagDialog.tsx
web/src/components/RenameTagDialog.tsx
+2
-2
ResourceIcon.tsx
web/src/components/ResourceIcon.tsx
+21
-11
SearchBar.tsx
web/src/components/SearchBar.tsx
+2
-2
AccessTokenSection.tsx
web/src/components/Settings/AccessTokenSection.tsx
+3
-3
MemberSection.tsx
web/src/components/Settings/MemberSection.tsx
+2
-2
MyAccountSection.tsx
web/src/components/Settings/MyAccountSection.tsx
+3
-3
SSOSection.tsx
web/src/components/Settings/SSOSection.tsx
+2
-2
StorageSection.tsx
web/src/components/Settings/StorageSection.tsx
+2
-2
WebhookSection.tsx
web/src/components/Settings/WebhookSection.tsx
+3
-3
WorkspaceSection.tsx
web/src/components/Settings/WorkspaceSection.tsx
+2
-2
TagTree.tsx
web/src/components/TagTree.tsx
+3
-3
UpdateAccountDialog.tsx
web/src/components/UpdateAccountDialog.tsx
+3
-3
UpdateCustomizedProfileDialog.tsx
web/src/components/UpdateCustomizedProfileDialog.tsx
+2
-2
UserBanner.tsx
web/src/components/UserBanner.tsx
+3
-3
UserStatisticsView.tsx
web/src/components/UserStatisticsView.tsx
+7
-11
VisibilityIcon.tsx
web/src/components/VisibilityIcon.tsx
+4
-4
RootLayout.tsx
web/src/layouts/RootLayout.tsx
+3
-3
About.tsx
web/src/pages/About.tsx
+4
-4
Archived.tsx
web/src/pages/Archived.tsx
+5
-5
AuthCallback.tsx
web/src/pages/AuthCallback.tsx
+2
-2
Explore.tsx
web/src/pages/Explore.tsx
+2
-2
Home.tsx
web/src/pages/Home.tsx
+2
-2
Inboxes.tsx
web/src/pages/Inboxes.tsx
+2
-2
Loading.tsx
web/src/pages/Loading.tsx
+2
-2
MemoDetail.tsx
web/src/pages/MemoDetail.tsx
+4
-4
Resources.tsx
web/src/pages/Resources.tsx
+4
-4
Setting.tsx
web/src/pages/Setting.tsx
+8
-9
UserProfile.tsx
web/src/pages/UserProfile.tsx
+3
-3
No files found.
web/src/components/AppearanceSelect.tsx
View file @
2dbf92f7
import
{
Option
,
Select
}
from
"@mui/joy"
;
import
{
Option
,
Select
}
from
"@mui/joy"
;
import
{
SunIcon
,
MoonIcon
,
SmileIcon
}
from
"lucide-react"
;
import
{
FC
}
from
"react"
;
import
{
FC
}
from
"react"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Icon
from
"./Icon"
;
interface
Props
{
interface
Props
{
value
:
Appearance
;
value
:
Appearance
;
...
@@ -18,11 +18,11 @@ const AppearanceSelect: FC<Props> = (props: Props) => {
...
@@ -18,11 +18,11 @@ const AppearanceSelect: FC<Props> = (props: Props) => {
const
getPrefixIcon
=
(
appearance
:
Appearance
)
=>
{
const
getPrefixIcon
=
(
appearance
:
Appearance
)
=>
{
const
className
=
"w-4 h-auto"
;
const
className
=
"w-4 h-auto"
;
if
(
appearance
===
"light"
)
{
if
(
appearance
===
"light"
)
{
return
<
Icon
.
Su
n
className=
{
className
}
/>;
return
<
SunIco
n
className=
{
className
}
/>;
}
else
if
(
appearance
===
"dark"
)
{
}
else
if
(
appearance
===
"dark"
)
{
return
<
Icon
.
Mo
on
className=
{
className
}
/>;
return
<
MoonIc
on
className=
{
className
}
/>;
}
else
{
}
else
{
return
<
Icon
.
Smile
className=
{
className
}
/>;
return
<
SmileIcon
className=
{
className
}
/>;
}
}
};
};
...
...
web/src/components/ChangeMemberPasswordDialog.tsx
View file @
2dbf92f7
import
{
Button
,
IconButton
,
Input
}
from
"@mui/joy"
;
import
{
Button
,
IconButton
,
Input
}
from
"@mui/joy"
;
import
{
XIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
useUserStore
}
from
"@/store/v1"
;
import
{
useUserStore
}
from
"@/store/v1"
;
import
{
User
}
from
"@/types/proto/api/v1/user_service"
;
import
{
User
}
from
"@/types/proto/api/v1/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
Icon
from
"./Icon"
;
interface
Props
extends
DialogProps
{
interface
Props
extends
DialogProps
{
user
:
User
;
user
:
User
;
...
@@ -71,7 +71,7 @@ const ChangeMemberPasswordDialog: React.FC<Props> = (props: Props) => {
...
@@ -71,7 +71,7 @@ const ChangeMemberPasswordDialog: React.FC<Props> = (props: Props) => {
{
t
(
"setting.account-section.change-password"
)
}
(
{
user
.
nickname
}
)
{
t
(
"setting.account-section.change-password"
)
}
(
{
user
.
nickname
}
)
</
p
>
</
p
>
<
IconButton
size=
"sm"
onClick=
{
handleCloseBtnClick
}
>
<
IconButton
size=
"sm"
onClick=
{
handleCloseBtnClick
}
>
<
Icon
.
X
className=
"w-5 h-auto"
/>
<
XIcon
className=
"w-5 h-auto"
/>
</
IconButton
>
</
IconButton
>
</
div
>
</
div
>
<
div
className=
"dialog-content-container"
>
<
div
className=
"dialog-content-container"
>
...
...
web/src/components/ChangePasswordDialog.tsx
View file @
2dbf92f7
import
{
Button
,
IconButton
,
Input
}
from
"@mui/joy"
;
import
{
Button
,
IconButton
,
Input
}
from
"@mui/joy"
;
import
{
XIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
...
@@ -6,7 +7,6 @@ import { useCommonContext } from "@/layouts/CommonContextProvider";
...
@@ -6,7 +7,6 @@ import { useCommonContext } from "@/layouts/CommonContextProvider";
import
{
useUserStore
}
from
"@/store/v1"
;
import
{
useUserStore
}
from
"@/store/v1"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
Icon
from
"./Icon"
;
type
Props
=
DialogProps
;
type
Props
=
DialogProps
;
...
@@ -70,7 +70,7 @@ const ChangePasswordDialog: React.FC<Props> = ({ destroy }: Props) => {
...
@@ -70,7 +70,7 @@ const ChangePasswordDialog: React.FC<Props> = ({ destroy }: Props) => {
<
div
className=
"dialog-header-container !w-64"
>
<
div
className=
"dialog-header-container !w-64"
>
<
p
className=
"title-text"
>
{
t
(
"setting.account-section.change-password"
)
}
</
p
>
<
p
className=
"title-text"
>
{
t
(
"setting.account-section.change-password"
)
}
</
p
>
<
IconButton
size=
"sm"
onClick=
{
handleCloseBtnClick
}
>
<
IconButton
size=
"sm"
onClick=
{
handleCloseBtnClick
}
>
<
Icon
.
X
className=
"w-5 h-auto"
/>
<
XIcon
className=
"w-5 h-auto"
/>
</
IconButton
>
</
IconButton
>
</
div
>
</
div
>
<
div
className=
"dialog-content-container"
>
<
div
className=
"dialog-content-container"
>
...
...
web/src/components/CreateAccessTokenDialog.tsx
View file @
2dbf92f7
import
{
Button
,
IconButton
,
Input
,
Radio
,
RadioGroup
}
from
"@mui/joy"
;
import
{
Button
,
IconButton
,
Input
,
Radio
,
RadioGroup
}
from
"@mui/joy"
;
import
{
XIcon
}
from
"lucide-react"
;
import
React
,
{
useState
}
from
"react"
;
import
React
,
{
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
userServiceClient
}
from
"@/grpcweb"
;
import
{
userServiceClient
}
from
"@/grpcweb"
;
...
@@ -6,7 +7,6 @@ import useCurrentUser from "@/hooks/useCurrentUser";
...
@@ -6,7 +7,6 @@ import useCurrentUser from "@/hooks/useCurrentUser";
import
useLoading
from
"@/hooks/useLoading"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
Icon
from
"./Icon"
;
interface
Props
extends
DialogProps
{
interface
Props
extends
DialogProps
{
onConfirm
:
()
=>
void
;
onConfirm
:
()
=>
void
;
...
@@ -87,7 +87,7 @@ const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
...
@@ -87,7 +87,7 @@ const CreateAccessTokenDialog: React.FC<Props> = (props: Props) => {
<
div
className=
"dialog-header-container"
>
<
div
className=
"dialog-header-container"
>
<
p
className=
"title-text"
>
Create access token
</
p
>
<
p
className=
"title-text"
>
Create access token
</
p
>
<
IconButton
size=
"sm"
onClick=
{
()
=>
destroy
()
}
>
<
IconButton
size=
"sm"
onClick=
{
()
=>
destroy
()
}
>
<
Icon
.
X
className=
"w-5 h-auto"
/>
<
XIcon
className=
"w-5 h-auto"
/>
</
IconButton
>
</
IconButton
>
</
div
>
</
div
>
<
div
className=
"dialog-content-container !w-80"
>
<
div
className=
"dialog-content-container !w-80"
>
...
...
web/src/components/CreateIdentityProviderDialog.tsx
View file @
2dbf92f7
import
{
Button
,
Divider
,
IconButton
,
Input
,
Option
,
Select
,
Typography
}
from
"@mui/joy"
;
import
{
Button
,
Divider
,
IconButton
,
Input
,
Option
,
Select
,
Typography
}
from
"@mui/joy"
;
import
{
XIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
identityProviderServiceClient
}
from
"@/grpcweb"
;
import
{
identityProviderServiceClient
}
from
"@/grpcweb"
;
...
@@ -6,7 +7,6 @@ import { absolutifyLink } from "@/helpers/utils";
...
@@ -6,7 +7,6 @@ import { absolutifyLink } from "@/helpers/utils";
import
{
FieldMapping
,
IdentityProvider
,
IdentityProvider_Type
,
OAuth2Config
}
from
"@/types/proto/api/v1/idp_service"
;
import
{
FieldMapping
,
IdentityProvider
,
IdentityProvider_Type
,
OAuth2Config
}
from
"@/types/proto/api/v1/idp_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
Icon
from
"./Icon"
;
const
templateList
:
IdentityProvider
[]
=
[
const
templateList
:
IdentityProvider
[]
=
[
{
{
...
@@ -245,7 +245,7 @@ const CreateIdentityProviderDialog: React.FC<Props> = (props: Props) => {
...
@@ -245,7 +245,7 @@ const CreateIdentityProviderDialog: React.FC<Props> = (props: Props) => {
<
div
className=
"dialog-header-container"
>
<
div
className=
"dialog-header-container"
>
<
p
>
{
t
(
isCreating
?
"setting.sso-section.create-sso"
:
"setting.sso-section.update-sso"
)
}
</
p
>
<
p
>
{
t
(
isCreating
?
"setting.sso-section.create-sso"
:
"setting.sso-section.update-sso"
)
}
</
p
>
<
IconButton
size=
"sm"
onClick=
{
handleCloseBtnClick
}
>
<
IconButton
size=
"sm"
onClick=
{
handleCloseBtnClick
}
>
<
Icon
.
X
className=
"w-5 h-auto"
/>
<
XIcon
className=
"w-5 h-auto"
/>
</
IconButton
>
</
IconButton
>
</
div
>
</
div
>
<
div
className=
"dialog-content-container min-w-[19rem]"
>
<
div
className=
"dialog-content-container min-w-[19rem]"
>
...
...
web/src/components/CreateWebhookDialog.tsx
View file @
2dbf92f7
import
{
Button
,
IconButton
,
Input
}
from
"@mui/joy"
;
import
{
Button
,
IconButton
,
Input
}
from
"@mui/joy"
;
import
{
XIcon
}
from
"lucide-react"
;
import
React
,
{
useEffect
,
useState
}
from
"react"
;
import
React
,
{
useEffect
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
webhookServiceClient
}
from
"@/grpcweb"
;
import
{
webhookServiceClient
}
from
"@/grpcweb"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
Icon
from
"./Icon"
;
interface
Props
extends
DialogProps
{
interface
Props
extends
DialogProps
{
webhookId
?:
number
;
webhookId
?:
number
;
...
@@ -97,7 +97,7 @@ const CreateWebhookDialog: React.FC<Props> = (props: Props) => {
...
@@ -97,7 +97,7 @@ const CreateWebhookDialog: React.FC<Props> = (props: Props) => {
<
div
className=
"dialog-header-container"
>
<
div
className=
"dialog-header-container"
>
<
p
className=
"title-text"
>
{
isCreating
?
"Create webhook"
:
"Edit webhook"
}
</
p
>
<
p
className=
"title-text"
>
{
isCreating
?
"Create webhook"
:
"Edit webhook"
}
</
p
>
<
IconButton
size=
"sm"
onClick=
{
()
=>
destroy
()
}
>
<
IconButton
size=
"sm"
onClick=
{
()
=>
destroy
()
}
>
<
Icon
.
X
className=
"w-5 h-auto"
/>
<
XIcon
className=
"w-5 h-auto"
/>
</
IconButton
>
</
IconButton
>
</
div
>
</
div
>
<
div
className=
"dialog-content-container !w-80"
>
<
div
className=
"dialog-content-container !w-80"
>
...
...
web/src/components/Empty.tsx
View file @
2dbf92f7
import
Icon
from
"./Icon
"
;
import
{
BirdIcon
}
from
"lucide-react
"
;
const
Empty
=
()
=>
{
const
Empty
=
()
=>
{
return
(
return
(
<
div
className=
"mx-auto"
>
<
div
className=
"mx-auto"
>
<
Icon
.
Bird
strokeWidth=
{
1
}
className=
"w-24 h-auto text-gray-500 dark:text-gray-400"
/>
<
BirdIcon
strokeWidth=
{
1
}
className=
"w-24 h-auto text-gray-500 dark:text-gray-400"
/>
</
div
>
</
div
>
);
);
};
};
...
...
web/src/components/ExploreSidebar/ExploreSidebarDrawer.tsx
View file @
2dbf92f7
import
{
Drawer
,
IconButton
}
from
"@mui/joy"
;
import
{
Drawer
,
IconButton
}
from
"@mui/joy"
;
import
{
SearchIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
Icon
from
"../Icon"
;
import
ExploreSidebar
from
"./ExploreSidebar"
;
import
ExploreSidebar
from
"./ExploreSidebar"
;
const
ExploreSidebarDrawer
=
()
=>
{
const
ExploreSidebarDrawer
=
()
=>
{
...
@@ -23,7 +23,7 @@ const ExploreSidebarDrawer = () => {
...
@@ -23,7 +23,7 @@ const ExploreSidebarDrawer = () => {
return
(
return
(
<>
<>
<
IconButton
onClick=
{
toggleDrawer
(
true
)
}
>
<
IconButton
onClick=
{
toggleDrawer
(
true
)
}
>
<
Icon
.
Search
className=
"w-5 h-auto dark:text-gray-400"
/>
<
SearchIcon
className=
"w-5 h-auto dark:text-gray-400"
/>
</
IconButton
>
</
IconButton
>
<
Drawer
anchor=
"right"
size=
"sm"
open=
{
open
}
onClose=
{
toggleDrawer
(
false
)
}
>
<
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"
>
<
div
className=
"w-full h-full px-4 bg-zinc-100 dark:bg-zinc-900"
>
...
...
web/src/components/HomeSidebar/HomeSidebarDrawer.tsx
View file @
2dbf92f7
import
{
Drawer
,
IconButton
}
from
"@mui/joy"
;
import
{
Drawer
,
IconButton
}
from
"@mui/joy"
;
import
{
SearchIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
Icon
from
"../Icon"
;
import
HomeSidebar
from
"./HomeSidebar"
;
import
HomeSidebar
from
"./HomeSidebar"
;
const
HomeSidebarDrawer
=
()
=>
{
const
HomeSidebarDrawer
=
()
=>
{
...
@@ -23,7 +23,7 @@ const HomeSidebarDrawer = () => {
...
@@ -23,7 +23,7 @@ const HomeSidebarDrawer = () => {
return
(
return
(
<>
<>
<
IconButton
onClick=
{
toggleDrawer
(
true
)
}
>
<
IconButton
onClick=
{
toggleDrawer
(
true
)
}
>
<
Icon
.
Search
className=
"w-5 h-auto dark:text-gray-400"
/>
<
SearchIcon
className=
"w-5 h-auto dark:text-gray-400"
/>
</
IconButton
>
</
IconButton
>
<
Drawer
anchor=
"right"
size=
"sm"
open=
{
open
}
onClose=
{
toggleDrawer
(
false
)
}
>
<
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"
>
<
div
className=
"w-full h-full px-4 bg-zinc-100 dark:bg-zinc-900"
>
...
...
web/src/components/HomeSidebar/TagsSection.tsx
View file @
2dbf92f7
import
{
Dropdown
,
Menu
,
MenuButton
,
MenuItem
,
Switch
}
from
"@mui/joy"
;
import
{
Dropdown
,
Menu
,
MenuButton
,
MenuItem
,
Switch
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
{
Edit3Icon
,
HashIcon
,
MoreVerticalIcon
,
TagsIcon
,
TrashIcon
}
from
"lucide-react"
;
import
toast
from
"react-hot-toast"
;
import
toast
from
"react-hot-toast"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
useDebounce
from
"react-use/lib/useDebounce"
;
import
useDebounce
from
"react-use/lib/useDebounce"
;
...
@@ -8,7 +9,6 @@ import { memoServiceClient } from "@/grpcweb";
...
@@ -8,7 +9,6 @@ import { memoServiceClient } from "@/grpcweb";
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
{
useMemoFilterStore
,
useMemoList
,
useTagStore
}
from
"@/store/v1"
;
import
{
useMemoFilterStore
,
useMemoList
,
useTagStore
}
from
"@/store/v1"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Icon
from
"../Icon"
;
import
showRenameTagDialog
from
"../RenameTagDialog"
;
import
showRenameTagDialog
from
"../RenameTagDialog"
;
import
TagTree
from
"../TagTree"
;
import
TagTree
from
"../TagTree"
;
import
{
Popover
,
PopoverContent
,
PopoverTrigger
}
from
"../ui/Popover"
;
import
{
Popover
,
PopoverContent
,
PopoverTrigger
}
from
"../ui/Popover"
;
...
@@ -66,7 +66,7 @@ const TagsSection = (props: Props) => {
...
@@ -66,7 +66,7 @@ const TagsSection = (props: Props) => {
{
tagAmounts
.
length
>
0
&&
(
{
tagAmounts
.
length
>
0
&&
(
<
Popover
>
<
Popover
>
<
PopoverTrigger
>
<
PopoverTrigger
>
<
Icon
.
MoreVertical
className=
"w-4 h-auto shrink-0 opacity-60"
/>
<
MoreVerticalIcon
className=
"w-4 h-auto shrink-0 opacity-60"
/>
</
PopoverTrigger
>
</
PopoverTrigger
>
<
PopoverContent
align=
"end"
alignOffset=
{
-
12
}
>
<
PopoverContent
align=
"end"
alignOffset=
{
-
12
}
>
<
div
className=
"w-auto flex flex-row justify-between items-center gap-2"
>
<
div
className=
"w-auto flex flex-row justify-between items-center gap-2"
>
...
@@ -90,17 +90,17 @@ const TagsSection = (props: Props) => {
...
@@ -90,17 +90,17 @@ const TagsSection = (props: Props) => {
<
Dropdown
>
<
Dropdown
>
<
MenuButton
slots=
{
{
root
:
"div"
}
}
>
<
MenuButton
slots=
{
{
root
:
"div"
}
}
>
<
div
className=
"shrink-0 group"
>
<
div
className=
"shrink-0 group"
>
<
Icon
.
Hash
className=
"group-hover:hidden w-4 h-auto shrink-0 opacity-40"
/>
<
HashIcon
className=
"group-hover:hidden w-4 h-auto shrink-0 opacity-40"
/>
<
Icon
.
MoreVertical
className=
"hidden group-hover:block w-4 h-auto shrink-0 opacity-60"
/>
<
MoreVerticalIcon
className=
"hidden group-hover:block w-4 h-auto shrink-0 opacity-60"
/>
</
div
>
</
div
>
</
MenuButton
>
</
MenuButton
>
<
Menu
size=
"sm"
placement=
"bottom-start"
>
<
Menu
size=
"sm"
placement=
"bottom-start"
>
<
MenuItem
onClick=
{
()
=>
showRenameTagDialog
({
tag
:
tag
})
}
>
<
MenuItem
onClick=
{
()
=>
showRenameTagDialog
({
tag
:
tag
})
}
>
<
Icon
.
Edit3
className=
"w-4 h-auto"
/>
<
Edit3Icon
className=
"w-4 h-auto"
/>
{
t
(
"common.rename"
)
}
{
t
(
"common.rename"
)
}
</
MenuItem
>
</
MenuItem
>
<
MenuItem
color=
"danger"
onClick=
{
()
=>
handleDeleteTag
(
tag
)
}
>
<
MenuItem
color=
"danger"
onClick=
{
()
=>
handleDeleteTag
(
tag
)
}
>
<
Icon
.
Trash
className=
"w-4 h-auto"
/>
<
TrashIcon
className=
"w-4 h-auto"
/>
{
t
(
"common.delete"
)
}
{
t
(
"common.delete"
)
}
</
MenuItem
>
</
MenuItem
>
</
Menu
>
</
Menu
>
...
@@ -119,7 +119,7 @@ const TagsSection = (props: Props) => {
...
@@ -119,7 +119,7 @@ const TagsSection = (props: Props) => {
)
:
(
)
:
(
!
props
.
readonly
&&
(
!
props
.
readonly
&&
(
<
div
className=
"p-2 border border-dashed dark:border-zinc-800 rounded-md flex flex-row justify-start items-start gap-1 text-gray-400 dark:text-gray-500"
>
<
div
className=
"p-2 border border-dashed dark:border-zinc-800 rounded-md flex flex-row justify-start items-start gap-1 text-gray-400 dark:text-gray-500"
>
<
Icon
.
Tags
/>
<
TagsIcon
/>
<
p
className=
"mt-0.5 text-sm leading-snug italic"
>
{
t
(
"tag.create-tags-guide"
)
}
</
p
>
<
p
className=
"mt-0.5 text-sm leading-snug italic"
>
{
t
(
"tag.create-tags-guide"
)
}
</
p
>
</
div
>
</
div
>
)
)
...
...
web/src/components/Icon.tsx
deleted
100644 → 0
View file @
d11bd30e
import
*
as
Icon
from
"lucide-react"
;
export
default
Icon
;
web/src/components/Inbox/MemoCommentMessage.tsx
View file @
2dbf92f7
import
{
Tooltip
}
from
"@mui/joy"
;
import
{
Tooltip
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
{
InboxIcon
,
MessageCircleIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
toast
from
"react-hot-toast"
;
import
toast
from
"react-hot-toast"
;
import
{
activityServiceClient
}
from
"@/grpcweb"
;
import
{
activityServiceClient
}
from
"@/grpcweb"
;
...
@@ -9,7 +10,6 @@ import { Inbox, Inbox_Status } from "@/types/proto/api/v1/inbox_service";
...
@@ -9,7 +10,6 @@ import { Inbox, Inbox_Status } from "@/types/proto/api/v1/inbox_service";
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
User
}
from
"@/types/proto/api/v1/user_service"
;
import
{
User
}
from
"@/types/proto/api/v1/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Icon
from
"../Icon"
;
interface
Props
{
interface
Props
{
inbox
:
Inbox
;
inbox
:
Inbox
;
...
@@ -81,7 +81,7 @@ const MemoCommentMessage = ({ inbox }: Props) => {
...
@@ -81,7 +81,7 @@ const MemoCommentMessage = ({ inbox }: Props) => {
)
}
)
}
>
>
<
Tooltip
title=
{
"Comment"
}
placement=
"bottom"
>
<
Tooltip
title=
{
"Comment"
}
placement=
"bottom"
>
<
Icon
.
MessageCircle
className=
"w-4 sm:w-5 h-auto"
/>
<
MessageCircleIcon
className=
"w-4 sm:w-5 h-auto"
/>
</
Tooltip
>
</
Tooltip
>
</
div
>
</
div
>
<
div
<
div
...
@@ -95,10 +95,7 @@ const MemoCommentMessage = ({ inbox }: Props) => {
...
@@ -95,10 +95,7 @@ const MemoCommentMessage = ({ inbox }: Props) => {
<
div
>
<
div
>
{
inbox
.
status
===
Inbox_Status
.
UNREAD
&&
(
{
inbox
.
status
===
Inbox_Status
.
UNREAD
&&
(
<
Tooltip
title=
{
t
(
"common.archive"
)
}
placement=
"top"
>
<
Tooltip
title=
{
t
(
"common.archive"
)
}
placement=
"top"
>
<
Icon
.
Inbox
<
InboxIcon
className=
"w-4 h-auto cursor-pointer text-gray-400 hover:text-blue-600"
onClick=
{
()
=>
handleArchiveMessage
()
}
/>
className=
"w-4 h-auto cursor-pointer text-gray-400 hover:text-blue-600"
onClick=
{
()
=>
handleArchiveMessage
()
}
/>
</
Tooltip
>
</
Tooltip
>
)
}
)
}
</
div
>
</
div
>
...
...
web/src/components/Inbox/VersionUpdateMessage.tsx
View file @
2dbf92f7
import
{
Tooltip
}
from
"@mui/joy"
;
import
{
Tooltip
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
{
ArrowUpIcon
,
InboxIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
toast
from
"react-hot-toast"
;
import
toast
from
"react-hot-toast"
;
import
{
activityServiceClient
}
from
"@/grpcweb"
;
import
{
activityServiceClient
}
from
"@/grpcweb"
;
...
@@ -7,7 +8,6 @@ import { activityNamePrefix, useInboxStore } from "@/store/v1";
...
@@ -7,7 +8,6 @@ import { activityNamePrefix, useInboxStore } from "@/store/v1";
import
{
Activity
}
from
"@/types/proto/api/v1/activity_service"
;
import
{
Activity
}
from
"@/types/proto/api/v1/activity_service"
;
import
{
Inbox
,
Inbox_Status
}
from
"@/types/proto/api/v1/inbox_service"
;
import
{
Inbox
,
Inbox_Status
}
from
"@/types/proto/api/v1/inbox_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Icon
from
"../Icon"
;
interface
Props
{
interface
Props
{
inbox
:
Inbox
;
inbox
:
Inbox
;
...
@@ -66,7 +66,7 @@ const VersionUpdateMessage = ({ inbox }: Props) => {
...
@@ -66,7 +66,7 @@ const VersionUpdateMessage = ({ inbox }: Props) => {
)}
)}
>
>
<Tooltip title={"Update"} placement="bottom">
<Tooltip title={"Update"} placement="bottom">
<
Icon.ArrowUp
className="w-4 sm:w-5 h-auto" />
<
ArrowUpIcon
className="w-4 sm:w-5 h-auto" />
</Tooltip>
</Tooltip>
</div>
</div>
<div
<div
...
@@ -80,10 +80,7 @@ const VersionUpdateMessage = ({ inbox }: Props) => {
...
@@ -80,10 +80,7 @@ const VersionUpdateMessage = ({ inbox }: Props) => {
<div>
<div>
{inbox.status === Inbox_Status.UNREAD && (
{inbox.status === Inbox_Status.UNREAD && (
<Tooltip title={t("common.archive")} placement="top">
<Tooltip title={t("common.archive")} placement="top">
<Icon.Inbox
<InboxIcon className="w-4 h-auto cursor-pointer text-gray-400 hover:text-blue-600" onClick={() => handleArchiveMessage()} />
className="w-4 h-auto cursor-pointer text-gray-400 hover:text-blue-600"
onClick={() => handleArchiveMessage()}
/>
</Tooltip>
</Tooltip>
)}
)}
</div>
</div>
...
...
web/src/components/LearnMore.tsx
View file @
2dbf92f7
import
{
Tooltip
}
from
"@mui/joy"
;
import
{
Tooltip
}
from
"@mui/joy"
;
import
{
ExternalLinkIcon
}
from
"lucide-react"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Icon
from
"./Icon"
;
interface
Props
{
interface
Props
{
className
?:
string
;
className
?:
string
;
...
@@ -15,7 +15,7 @@ const LearnMore: React.FC<Props> = (props: Props) => {
...
@@ -15,7 +15,7 @@ const LearnMore: React.FC<Props> = (props: Props) => {
return
(
return
(
<
Tooltip
title=
{
title
??
t
(
"common.learn-more"
)
}
placement=
"top"
>
<
Tooltip
title=
{
title
??
t
(
"common.learn-more"
)
}
placement=
"top"
>
<
a
className=
{
`text-gray-500 dark:text-gray-400 hover:text-blue-600 ${className}`
}
href=
{
url
}
target=
"_blank"
>
<
a
className=
{
`text-gray-500 dark:text-gray-400 hover:text-blue-600 ${className}`
}
href=
{
url
}
target=
"_blank"
>
<
Icon
.
ExternalLink
className=
"w-4 h-auto"
/>
<
ExternalLinkIcon
className=
"w-4 h-auto"
/>
</
a
>
</
a
>
</
Tooltip
>
</
Tooltip
>
);
);
...
...
web/src/components/LocaleSelect.tsx
View file @
2dbf92f7
import
{
Option
,
Select
}
from
"@mui/joy"
;
import
{
Option
,
Select
}
from
"@mui/joy"
;
import
{
GlobeIcon
}
from
"lucide-react"
;
import
{
FC
}
from
"react"
;
import
{
FC
}
from
"react"
;
import
{
locales
}
from
"@/i18n"
;
import
{
locales
}
from
"@/i18n"
;
import
Icon
from
"./Icon"
;
interface
Props
{
interface
Props
{
value
:
Locale
;
value
:
Locale
;
...
@@ -19,7 +19,7 @@ const LocaleSelect: FC<Props> = (props: Props) => {
...
@@ -19,7 +19,7 @@ const LocaleSelect: FC<Props> = (props: Props) => {
return
(
return
(
<
Select
<
Select
className=
{
`!min-w-[10rem] w-auto whitespace-nowrap ${className ?? ""}`
}
className=
{
`!min-w-[10rem] w-auto whitespace-nowrap ${className ?? ""}`
}
startDecorator=
{
<
Icon
.
Globe
className=
"w-4 h-auto"
/>
}
startDecorator=
{
<
GlobeIcon
className=
"w-4 h-auto"
/>
}
value=
{
value
}
value=
{
value
}
onChange=
{
(
_
,
value
)
=>
handleSelectChange
(
value
as
Locale
)
}
onChange=
{
(
_
,
value
)
=>
handleSelectChange
(
value
as
Locale
)
}
>
>
...
...
web/src/components/MemoActionMenu.tsx
View file @
2dbf92f7
import
{
Dropdown
,
Menu
,
MenuButton
,
MenuItem
}
from
"@mui/joy"
;
import
{
Dropdown
,
Menu
,
MenuButton
,
MenuItem
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
copy
from
"copy-to-clipboard"
;
import
copy
from
"copy-to-clipboard"
;
import
{
ArchiveIcon
,
ArchiveRestoreIcon
,
BookmarkMinusIcon
,
BookmarkPlusIcon
,
CopyIcon
,
Edit3Icon
,
MoreVerticalIcon
,
TrashIcon
,
}
from
"lucide-react"
;
import
toast
from
"react-hot-toast"
;
import
toast
from
"react-hot-toast"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
Icon
from
"@/components/Icon"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
import
{
RowStatus
}
from
"@/types/proto/api/v1/common"
;
...
@@ -108,34 +117,34 @@ const MemoActionMenu = (props: Props) => {
...
@@ -108,34 +117,34 @@ const MemoActionMenu = (props: Props) => {
<
Dropdown
>
<
Dropdown
>
<
MenuButton
slots=
{
{
root
:
"div"
}
}
>
<
MenuButton
slots=
{
{
root
:
"div"
}
}
>
<
span
className=
{
clsx
(
"flex justify-center items-center rounded-full hover:opacity-70"
,
props
.
className
)
}
>
<
span
className=
{
clsx
(
"flex justify-center items-center rounded-full hover:opacity-70"
,
props
.
className
)
}
>
<
Icon
.
MoreVertical
className=
"w-4 h-4 mx-auto text-gray-500 dark:text-gray-400"
/>
<
MoreVerticalIcon
className=
"w-4 h-4 mx-auto text-gray-500 dark:text-gray-400"
/>
</
span
>
</
span
>
</
MenuButton
>
</
MenuButton
>
<
Menu
className=
"text-sm"
size=
"sm"
placement=
"bottom-end"
>
<
Menu
className=
"text-sm"
size=
"sm"
placement=
"bottom-end"
>
{
!
hiddenActions
?.
includes
(
"pin"
)
&&
(
{
!
hiddenActions
?.
includes
(
"pin"
)
&&
(
<
MenuItem
onClick=
{
handleTogglePinMemoBtnClick
}
>
<
MenuItem
onClick=
{
handleTogglePinMemoBtnClick
}
>
{
memo
.
pinned
?
<
Icon
.
BookmarkMinus
className=
"w-4 h-auto"
/>
:
<
Icon
.
BookmarkPlus
className=
"w-4 h-auto"
/>
}
{
memo
.
pinned
?
<
BookmarkMinusIcon
className=
"w-4 h-auto"
/>
:
<
BookmarkPlusIcon
className=
"w-4 h-auto"
/>
}
{
memo
.
pinned
?
t
(
"common.unpin"
)
:
t
(
"common.pin"
)
}
{
memo
.
pinned
?
t
(
"common.unpin"
)
:
t
(
"common.pin"
)
}
</
MenuItem
>
</
MenuItem
>
)
}
)
}
{
!
hiddenActions
?.
includes
(
"edit"
)
&&
props
.
onEdit
&&
(
{
!
hiddenActions
?.
includes
(
"edit"
)
&&
props
.
onEdit
&&
(
<
MenuItem
onClick=
{
handleEditMemoClick
}
>
<
MenuItem
onClick=
{
handleEditMemoClick
}
>
<
Icon
.
Edit3
className=
"w-4 h-auto"
/>
<
Edit3Icon
className=
"w-4 h-auto"
/>
{
t
(
"common.edit"
)
}
{
t
(
"common.edit"
)
}
</
MenuItem
>
</
MenuItem
>
)
}
)
}
{
!
hiddenActions
?.
includes
(
"share"
)
&&
(
{
!
hiddenActions
?.
includes
(
"share"
)
&&
(
<
MenuItem
onClick=
{
handleCopyLink
}
>
<
MenuItem
onClick=
{
handleCopyLink
}
>
<
Icon
.
Copy
className=
"w-4 h-auto"
/>
<
CopyIcon
className=
"w-4 h-auto"
/>
{
t
(
"memo.copy-link"
)
}
{
t
(
"memo.copy-link"
)
}
</
MenuItem
>
</
MenuItem
>
)
}
)
}
<
MenuItem
color=
"warning"
onClick=
{
handleToggleMemoStatusClick
}
>
<
MenuItem
color=
"warning"
onClick=
{
handleToggleMemoStatusClick
}
>
{
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
?
<
Icon
.
ArchiveRestore
className=
"w-4 h-auto"
/>
:
<
Icon
.
Archive
className=
"w-4 h-auto"
/>
}
{
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
?
<
ArchiveRestoreIcon
className=
"w-4 h-auto"
/>
:
<
ArchiveIcon
className=
"w-4 h-auto"
/>
}
{
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
?
t
(
"common.restore"
)
:
t
(
"common.archive"
)
}
{
memo
.
rowStatus
===
RowStatus
.
ARCHIVED
?
t
(
"common.restore"
)
:
t
(
"common.archive"
)
}
</
MenuItem
>
</
MenuItem
>
<
MenuItem
color=
"danger"
onClick=
{
handleDeleteMemoClick
}
>
<
MenuItem
color=
"danger"
onClick=
{
handleDeleteMemoClick
}
>
<
Icon
.
Trash
className=
"w-4 h-auto"
/>
<
TrashIcon
className=
"w-4 h-auto"
/>
{
t
(
"common.delete"
)
}
{
t
(
"common.delete"
)
}
</
MenuItem
>
</
MenuItem
>
</
Menu
>
</
Menu
>
...
...
web/src/components/MemoContent/CodeBlock.tsx
View file @
2dbf92f7
...
@@ -2,9 +2,9 @@ import clsx from "clsx";
...
@@ -2,9 +2,9 @@ import clsx from "clsx";
import
copy
from
"copy-to-clipboard"
;
import
copy
from
"copy-to-clipboard"
;
import
DOMPurify
from
"dompurify"
;
import
DOMPurify
from
"dompurify"
;
import
hljs
from
"highlight.js"
;
import
hljs
from
"highlight.js"
;
import
{
CopyIcon
}
from
"lucide-react"
;
import
{
useCallback
,
useMemo
}
from
"react"
;
import
{
useCallback
,
useMemo
}
from
"react"
;
import
toast
from
"react-hot-toast"
;
import
toast
from
"react-hot-toast"
;
import
Icon
from
"../Icon"
;
import
MermaidBlock
from
"./MermaidBlock"
;
import
MermaidBlock
from
"./MermaidBlock"
;
import
{
BaseProps
}
from
"./types"
;
import
{
BaseProps
}
from
"./types"
;
...
@@ -57,7 +57,7 @@ const CodeBlock: React.FC<Props> = ({ language, content }: Props) => {
...
@@ -57,7 +57,7 @@ const CodeBlock: React.FC<Props> = ({ language, content }: Props) => {
<
div
className=
"w-full my-1 bg-amber-100 border-l-4 border-amber-400 rounded hover:shadow dark:bg-zinc-600 dark:border-zinc-400 relative"
>
<
div
className=
"w-full my-1 bg-amber-100 border-l-4 border-amber-400 rounded hover:shadow dark:bg-zinc-600 dark:border-zinc-400 relative"
>
<
div
className=
"w-full px-2 py-1 flex flex-row justify-between items-center text-amber-500 dark:text-zinc-400"
>
<
div
className=
"w-full px-2 py-1 flex flex-row justify-between items-center text-amber-500 dark:text-zinc-400"
>
<
span
className=
"text-sm font-mono"
>
{
formatedLanguage
}
</
span
>
<
span
className=
"text-sm font-mono"
>
{
formatedLanguage
}
</
span
>
<
Icon
.
Copy
className=
"w-4 h-auto cursor-pointer hover:opacity-80"
onClick=
{
handleCopyButtonClick
}
/>
<
CopyIcon
className=
"w-4 h-auto cursor-pointer hover:opacity-80"
onClick=
{
handleCopyButtonClick
}
/>
</
div
>
</
div
>
<
div
className=
"overflow-auto"
>
<
div
className=
"overflow-auto"
>
...
...
web/src/components/MemoContent/EmbeddedContent/EmbeddedMemo.tsx
View file @
2dbf92f7
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
copy
from
"copy-to-clipboard"
;
import
copy
from
"copy-to-clipboard"
;
import
{
ArrowUpRightIcon
}
from
"lucide-react"
;
import
{
useContext
,
useEffect
}
from
"react"
;
import
{
useContext
,
useEffect
}
from
"react"
;
import
toast
from
"react-hot-toast"
;
import
toast
from
"react-hot-toast"
;
import
{
Link
}
from
"react-router-dom"
;
import
{
Link
}
from
"react-router-dom"
;
import
Icon
from
"@/components/Icon"
;
import
MemoResourceListView
from
"@/components/MemoResourceListView"
;
import
MemoResourceListView
from
"@/components/MemoResourceListView"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
...
@@ -76,7 +76,7 @@ const EmbeddedMemo = ({ resourceId: uid, params: paramsStr }: Props) => {
...
@@ -76,7 +76,7 @@ const EmbeddedMemo = ({ resourceId: uid, params: paramsStr }: Props) => {
{
memo
.
uid
.
slice
(
0
,
8
)
}
{
memo
.
uid
.
slice
(
0
,
8
)
}
</
span
>
</
span
>
<
Link
className=
"opacity-60 hover:opacity-80"
to=
{
`/m/${memo.uid}`
}
unstable_viewTransition
>
<
Link
className=
"opacity-60 hover:opacity-80"
to=
{
`/m/${memo.uid}`
}
unstable_viewTransition
>
<
Icon
.
ArrowUpRight
className=
"w-5 h-auto"
/>
<
ArrowUpRightIcon
className=
"w-5 h-auto"
/>
</
Link
>
</
Link
>
</
div
>
</
div
>
</
div
>
</
div
>
...
...
web/src/components/MemoDetailSidebar/MemoDetailSidebar.tsx
View file @
2dbf92f7
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
{
isEqual
}
from
"lodash-es"
;
import
{
isEqual
}
from
"lodash-es"
;
import
{
CheckCircleIcon
,
Code2Icon
,
HashIcon
,
LinkIcon
}
from
"lucide-react"
;
import
{
Memo
,
MemoProperty
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
Memo
,
MemoProperty
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Icon
from
"../Icon"
;
interface
Props
{
interface
Props
{
memo
:
Memo
;
memo
:
Memo
;
...
@@ -45,7 +45,7 @@ const MemoDetailSidebar = ({ memo, className }: Props) => {
...
@@ -45,7 +45,7 @@ const MemoDetailSidebar = ({ memo, className }: Props) => {
{
property
.
hasLink
&&
(
{
property
.
hasLink
&&
(
<
div
className=
"w-auto border dark:border-zinc-800 pl-1 pr-1.5 rounded-md flex justify-between items-center"
>
<
div
className=
"w-auto border dark:border-zinc-800 pl-1 pr-1.5 rounded-md flex justify-between items-center"
>
<
div
className=
"w-auto flex justify-start items-center mr-1"
>
<
div
className=
"w-auto flex justify-start items-center mr-1"
>
<
Icon
.
Link
className=
"w-4 h-auto mr-1"
/>
<
LinkIcon
className=
"w-4 h-auto mr-1"
/>
<
span
className=
"block text-sm"
>
{
t
(
"memo.links"
)
}
</
span
>
<
span
className=
"block text-sm"
>
{
t
(
"memo.links"
)
}
</
span
>
</
div
>
</
div
>
</
div
>
</
div
>
...
@@ -53,7 +53,7 @@ const MemoDetailSidebar = ({ memo, className }: Props) => {
...
@@ -53,7 +53,7 @@ const MemoDetailSidebar = ({ memo, className }: Props) => {
{
property
.
hasTaskList
&&
(
{
property
.
hasTaskList
&&
(
<
div
className=
"w-auto border dark:border-zinc-800 pl-1 pr-1.5 rounded-md flex justify-between items-center"
>
<
div
className=
"w-auto border dark:border-zinc-800 pl-1 pr-1.5 rounded-md flex justify-between items-center"
>
<
div
className=
"w-auto flex justify-start items-center mr-1"
>
<
div
className=
"w-auto flex justify-start items-center mr-1"
>
<
Icon
.
CheckCircle
className=
"w-4 h-auto mr-1"
/>
<
CheckCircleIcon
className=
"w-4 h-auto mr-1"
/>
<
span
className=
"block text-sm"
>
{
t
(
"memo.to-do"
)
}
</
span
>
<
span
className=
"block text-sm"
>
{
t
(
"memo.to-do"
)
}
</
span
>
</
div
>
</
div
>
</
div
>
</
div
>
...
@@ -61,7 +61,7 @@ const MemoDetailSidebar = ({ memo, className }: Props) => {
...
@@ -61,7 +61,7 @@ const MemoDetailSidebar = ({ memo, className }: Props) => {
{
property
.
hasCode
&&
(
{
property
.
hasCode
&&
(
<
div
className=
"w-auto border dark:border-zinc-800 pl-1 pr-1.5 rounded-md flex justify-between items-center"
>
<
div
className=
"w-auto border dark:border-zinc-800 pl-1 pr-1.5 rounded-md flex justify-between items-center"
>
<
div
className=
"w-auto flex justify-start items-center mr-1"
>
<
div
className=
"w-auto flex justify-start items-center mr-1"
>
<
Icon
.
Code2
className=
"w-4 h-auto mr-1"
/>
<
Code2Icon
className=
"w-4 h-auto mr-1"
/>
<
span
className=
"block text-sm"
>
{
t
(
"memo.code"
)
}
</
span
>
<
span
className=
"block text-sm"
>
{
t
(
"memo.code"
)
}
</
span
>
</
div
>
</
div
>
</
div
>
</
div
>
...
@@ -81,7 +81,7 @@ const MemoDetailSidebar = ({ memo, className }: Props) => {
...
@@ -81,7 +81,7 @@ const MemoDetailSidebar = ({ memo, className }: Props) => {
key=
{
tag
}
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"
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"
/>
<
HashIcon
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)]"
)
}
>
<
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
>
<
span
className=
"truncate dark:opacity-80"
>
{
tag
}
</
span
>
</
div
>
</
div
>
...
...
web/src/components/MemoDetailSidebar/MemoDetailSidebarDrawer.tsx
View file @
2dbf92f7
import
{
Drawer
,
IconButton
}
from
"@mui/joy"
;
import
{
Drawer
,
IconButton
}
from
"@mui/joy"
;
import
{
GanttChartIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
Icon
from
"../Icon"
;
import
MemoDetailSidebar
from
"./MemoDetailSidebar"
;
import
MemoDetailSidebar
from
"./MemoDetailSidebar"
;
interface
Props
{
interface
Props
{
...
@@ -27,7 +27,7 @@ const MemoDetailSidebarDrawer = ({ memo }: Props) => {
...
@@ -27,7 +27,7 @@ const MemoDetailSidebarDrawer = ({ memo }: Props) => {
return
(
return
(
<>
<>
<
IconButton
onClick=
{
toggleDrawer
(
true
)
}
>
<
IconButton
onClick=
{
toggleDrawer
(
true
)
}
>
<
Icon
.
GanttChart
className=
"w-5 h-auto dark:text-gray-400"
/>
<
GanttChartIcon
className=
"w-5 h-auto dark:text-gray-400"
/>
</
IconButton
>
</
IconButton
>
<
Drawer
anchor=
"right"
size=
"sm"
open=
{
open
}
onClose=
{
toggleDrawer
(
false
)
}
>
<
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"
>
<
div
className=
"w-full h-full px-4 bg-zinc-100 dark:bg-zinc-900"
>
...
...
web/src/components/MemoDisplaySettingMenu.tsx
View file @
2dbf92f7
import
{
Option
,
Select
}
from
"@mui/joy"
;
import
{
Option
,
Select
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
{
Settings2Icon
}
from
"lucide-react"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
Icon
from
"./Icon"
;
import
{
Popover
,
PopoverContent
,
PopoverTrigger
}
from
"./ui/Popover"
;
import
{
Popover
,
PopoverContent
,
PopoverTrigger
}
from
"./ui/Popover"
;
interface
Props
{
interface
Props
{
...
@@ -17,7 +17,7 @@ const MemoDisplaySettingMenu = ({ className }: Props) => {
...
@@ -17,7 +17,7 @@ const MemoDisplaySettingMenu = ({ className }: Props) => {
<
PopoverTrigger
<
PopoverTrigger
className=
{
clsx
(
className
,
isApplying
?
"text-teal-600 bg-teal-50 dark:text-teal-500 dark:bg-teal-900 rounded-sm"
:
"opacity-40"
)
}
className=
{
clsx
(
className
,
isApplying
?
"text-teal-600 bg-teal-50 dark:text-teal-500 dark:bg-teal-900 rounded-sm"
:
"opacity-40"
)
}
>
>
<
Icon
.
Settings2
className=
"w-4 h-auto shrink-0"
/>
<
Settings2Icon
className=
"w-4 h-auto shrink-0"
/>
</
PopoverTrigger
>
</
PopoverTrigger
>
<
PopoverContent
align=
"end"
alignOffset=
{
-
12
}
sideOffset=
{
14
}
>
<
PopoverContent
align=
"end"
alignOffset=
{
-
12
}
sideOffset=
{
14
}
>
<
div
className=
"flex flex-col gap-2"
>
<
div
className=
"flex flex-col gap-2"
>
...
...
web/src/components/MemoEditor/ActionButton/AddMemoRelationPopover.tsx
View file @
2dbf92f7
import
{
Autocomplete
,
AutocompleteOption
,
Button
,
Checkbox
,
Chip
,
IconButton
}
from
"@mui/joy"
;
import
{
Autocomplete
,
AutocompleteOption
,
Button
,
Checkbox
,
Chip
,
IconButton
}
from
"@mui/joy"
;
import
{
uniqBy
}
from
"lodash-es"
;
import
{
uniqBy
}
from
"lodash-es"
;
import
{
LinkIcon
}
from
"lucide-react"
;
import
React
,
{
useContext
,
useState
}
from
"react"
;
import
React
,
{
useContext
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
useDebounce
from
"react-use/lib/useDebounce"
;
import
useDebounce
from
"react-use/lib/useDebounce"
;
import
Icon
from
"@/components/Icon"
;
import
{
Popover
,
PopoverContent
,
PopoverTrigger
}
from
"@/components/ui/Popover"
;
import
{
Popover
,
PopoverContent
,
PopoverTrigger
}
from
"@/components/ui/Popover"
;
import
{
memoServiceClient
}
from
"@/grpcweb"
;
import
{
memoServiceClient
}
from
"@/grpcweb"
;
import
{
DEFAULT_LIST_MEMOS_PAGE_SIZE
}
from
"@/helpers/consts"
;
import
{
DEFAULT_LIST_MEMOS_PAGE_SIZE
}
from
"@/helpers/consts"
;
...
@@ -127,7 +127,7 @@ const AddMemoRelationPopover = (props: Props) => {
...
@@ -127,7 +127,7 @@ const AddMemoRelationPopover = (props: Props) => {
<
Popover
open=
{
popoverOpen
}
onOpenChange=
{
setPopoverOpen
}
>
<
Popover
open=
{
popoverOpen
}
onOpenChange=
{
setPopoverOpen
}
>
<
PopoverTrigger
>
<
PopoverTrigger
>
<
IconButton
size=
"sm"
component=
"div"
>
<
IconButton
size=
"sm"
component=
"div"
>
<
Icon
.
Link
className=
"w-5 h-5 mx-auto"
/>
<
LinkIcon
className=
"w-5 h-5 mx-auto"
/>
</
IconButton
>
</
IconButton
>
</
PopoverTrigger
>
</
PopoverTrigger
>
<
PopoverContent
align=
"center"
>
<
PopoverContent
align=
"center"
>
...
...
web/src/components/MemoEditor/ActionButton/MarkdownMenu.tsx
View file @
2dbf92f7
import
{
Dropdown
,
IconButton
,
Menu
,
MenuButton
,
MenuItem
}
from
"@mui/joy"
;
import
{
Dropdown
,
IconButton
,
Menu
,
MenuButton
,
MenuItem
}
from
"@mui/joy"
;
import
{
Link
}
from
"@mui/joy"
;
import
{
Link
}
from
"@mui/joy"
;
import
Icon
from
"@/components/Icon
"
;
import
{
CheckSquareIcon
,
Code2Icon
,
SquareSlashIcon
}
from
"lucide-react
"
;
import
{
EditorRefActions
}
from
"../Editor"
;
import
{
EditorRefActions
}
from
"../Editor"
;
interface
Props
{
interface
Props
{
...
@@ -67,15 +67,15 @@ const MarkdownMenu = (props: Props) => {
...
@@ -67,15 +67,15 @@ const MarkdownMenu = (props: Props) => {
},
},
}
}
}
}
>
>
<
Icon
.
SquareSlash
className=
"w-5 h-5 mx-auto"
/>
<
SquareSlashIcon
className=
"w-5 h-5 mx-auto"
/>
</
MenuButton
>
</
MenuButton
>
<
Menu
className=
"text-sm"
size=
"sm"
placement=
"bottom-start"
>
<
Menu
className=
"text-sm"
size=
"sm"
placement=
"bottom-start"
>
<
MenuItem
onClick=
{
handleCodeBlockClick
}
>
<
MenuItem
onClick=
{
handleCodeBlockClick
}
>
<
Icon
.
Code2
className=
"w-4 h-auto"
/>
<
Code2Icon
className=
"w-4 h-auto"
/>
<
span
>
Code block
</
span
>
<
span
>
Code block
</
span
>
</
MenuItem
>
</
MenuItem
>
<
MenuItem
onClick=
{
handleCheckboxClick
}
>
<
MenuItem
onClick=
{
handleCheckboxClick
}
>
<
Icon
.
CheckSquare
className=
"w-4 h-auto"
/>
<
CheckSquareIcon
className=
"w-4 h-auto"
/>
<
span
>
Checkbox
</
span
>
<
span
>
Checkbox
</
span
>
</
MenuItem
>
</
MenuItem
>
<
div
className=
"-mt-0.5 pl-2"
>
<
div
className=
"-mt-0.5 pl-2"
>
...
...
web/src/components/MemoEditor/ActionButton/TagSelector.tsx
View file @
2dbf92f7
import
{
Dropdown
,
IconButton
,
Menu
,
MenuButton
}
from
"@mui/joy"
;
import
{
Dropdown
,
IconButton
,
Menu
,
MenuButton
}
from
"@mui/joy"
;
import
{
HashIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useRef
,
useState
}
from
"react"
;
import
{
useEffect
,
useRef
,
useState
}
from
"react"
;
import
useClickAway
from
"react-use/lib/useClickAway"
;
import
useClickAway
from
"react-use/lib/useClickAway"
;
import
Icon
from
"@/components/Icon"
;
import
OverflowTip
from
"@/components/kit/OverflowTip"
;
import
OverflowTip
from
"@/components/kit/OverflowTip"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
{
useTagStore
}
from
"@/store/v1"
;
import
{
useTagStore
}
from
"@/store/v1"
;
...
@@ -58,7 +58,7 @@ const TagSelector = (props: Props) => {
...
@@ -58,7 +58,7 @@ const TagSelector = (props: Props) => {
},
},
}
}
}
}
>
>
<
Icon
.
Hash
className=
"w-5 h-5 mx-auto"
/>
<
HashIcon
className=
"w-5 h-5 mx-auto"
/>
</
MenuButton
>
</
MenuButton
>
<
Menu
className=
"relative text-sm"
component=
"div"
size=
"sm"
placement=
"bottom-start"
>
<
Menu
className=
"relative text-sm"
component=
"div"
size=
"sm"
placement=
"bottom-start"
>
<
div
ref=
{
containerRef
}
>
<
div
ref=
{
containerRef
}
>
...
...
web/src/components/MemoEditor/ActionButton/UploadResourceButton.tsx
View file @
2dbf92f7
import
{
IconButton
}
from
"@mui/joy"
;
import
{
IconButton
}
from
"@mui/joy"
;
import
{
PaperclipIcon
}
from
"lucide-react"
;
import
{
useContext
,
useRef
,
useState
}
from
"react"
;
import
{
useContext
,
useRef
,
useState
}
from
"react"
;
import
toast
from
"react-hot-toast"
;
import
toast
from
"react-hot-toast"
;
import
Icon
from
"@/components/Icon"
;
import
{
useResourceStore
}
from
"@/store/v1"
;
import
{
useResourceStore
}
from
"@/store/v1"
;
import
{
Resource
}
from
"@/types/proto/api/v1/resource_service"
;
import
{
Resource
}
from
"@/types/proto/api/v1/resource_service"
;
import
{
MemoEditorContext
}
from
"../types"
;
import
{
MemoEditorContext
}
from
"../types"
;
...
@@ -67,7 +67,7 @@ const UploadResourceButton = () => {
...
@@ -67,7 +67,7 @@ const UploadResourceButton = () => {
return
(
return
(
<
IconButton
size=
"sm"
disabled=
{
state
.
uploadingFlag
}
>
<
IconButton
size=
"sm"
disabled=
{
state
.
uploadingFlag
}
>
<
Icon
.
Paperclip
className=
"w-5 h-5 mx-auto"
/>
<
PaperclipIcon
className=
"w-5 h-5 mx-auto"
/>
<
input
<
input
className=
"absolute inset-0 w-full h-full opacity-0 cursor-pointer"
className=
"absolute inset-0 w-full h-full opacity-0 cursor-pointer"
ref=
{
fileInputRef
}
ref=
{
fileInputRef
}
...
...
web/src/components/MemoEditor/RelationListView.tsx
View file @
2dbf92f7
import
{
LinkIcon
,
XIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
import
{
MemoRelation
,
MemoRelation_Type
}
from
"@/types/proto/api/v1/memo_relation_service"
;
import
{
MemoRelation
,
MemoRelation_Type
}
from
"@/types/proto/api/v1/memo_relation_service"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
Icon
from
"../Icon"
;
interface
Props
{
interface
Props
{
relationList
:
MemoRelation
[];
relationList
:
MemoRelation
[];
...
@@ -41,9 +41,9 @@ const RelationListView = (props: Props) => {
...
@@ -41,9 +41,9 @@ const RelationListView = (props: Props) => {
className=
"w-auto max-w-xs overflow-hidden flex flex-row justify-start items-center bg-zinc-100 dark:bg-zinc-900 hover:opacity-80 rounded-md text-sm p-1 px-2 text-gray-500 dark:text-gray-400 cursor-pointer hover:line-through"
className=
"w-auto max-w-xs overflow-hidden flex flex-row justify-start items-center bg-zinc-100 dark:bg-zinc-900 hover:opacity-80 rounded-md text-sm p-1 px-2 text-gray-500 dark:text-gray-400 cursor-pointer hover:line-through"
onClick=
{
()
=>
handleDeleteRelation
(
memo
)
}
onClick=
{
()
=>
handleDeleteRelation
(
memo
)
}
>
>
<
Icon
.
Link
className=
"w-4 h-auto shrink-0 opacity-80"
/>
<
LinkIcon
className=
"w-4 h-auto shrink-0 opacity-80"
/>
<
span
className=
"mx-1 max-w-full text-ellipsis whitespace-nowrap overflow-hidden"
>
{
memo
.
snippet
}
</
span
>
<
span
className=
"mx-1 max-w-full text-ellipsis whitespace-nowrap overflow-hidden"
>
{
memo
.
snippet
}
</
span
>
<
Icon
.
X
className=
"w-4 h-auto cursor-pointer shrink-0 opacity-60 hover:opacity-100"
/>
<
XIcon
className=
"w-4 h-auto cursor-pointer shrink-0 opacity-60 hover:opacity-100"
/>
</
div
>
</
div
>
);
);
})
}
})
}
...
...
web/src/components/MemoEditor/ResourceListView.tsx
View file @
2dbf92f7
import
{
DndContext
,
closestCenter
,
MouseSensor
,
TouchSensor
,
useSensor
,
useSensors
,
DragEndEvent
}
from
"@dnd-kit/core"
;
import
{
DndContext
,
closestCenter
,
MouseSensor
,
TouchSensor
,
useSensor
,
useSensors
,
DragEndEvent
}
from
"@dnd-kit/core"
;
import
{
arrayMove
,
SortableContext
,
verticalListSortingStrategy
}
from
"@dnd-kit/sortable"
;
import
{
arrayMove
,
SortableContext
,
verticalListSortingStrategy
}
from
"@dnd-kit/sortable"
;
import
{
XIcon
}
from
"lucide-react"
;
import
{
Resource
}
from
"@/types/proto/api/v1/resource_service"
;
import
{
Resource
}
from
"@/types/proto/api/v1/resource_service"
;
import
Icon
from
"../Icon"
;
import
ResourceIcon
from
"../ResourceIcon"
;
import
ResourceIcon
from
"../ResourceIcon"
;
import
SortableItem
from
"./SortableItem"
;
import
SortableItem
from
"./SortableItem"
;
...
@@ -45,7 +45,7 @@ const ResourceListView = (props: Props) => {
...
@@ -45,7 +45,7 @@ const ResourceListView = (props: Props) => {
<
span
className=
"text-sm max-w-[8rem] truncate"
>
{
resource
.
filename
}
</
span
>
<
span
className=
"text-sm max-w-[8rem] truncate"
>
{
resource
.
filename
}
</
span
>
</
SortableItem
>
</
SortableItem
>
<
button
className=
"shrink-0"
onClick=
{
()
=>
handleDeleteResource
(
resource
.
name
)
}
>
<
button
className=
"shrink-0"
onClick=
{
()
=>
handleDeleteResource
(
resource
.
name
)
}
>
<
Icon
.
X
className=
"w-4 h-auto cursor-pointer opacity-60 hover:opacity-100"
/>
<
XIcon
className=
"w-4 h-auto cursor-pointer opacity-60 hover:opacity-100"
/>
</
button
>
</
button
>
</
div
>
</
div
>
);
);
...
...
web/src/components/MemoEditor/index.tsx
View file @
2dbf92f7
import
{
Select
,
Option
,
Button
,
Divider
}
from
"@mui/joy"
;
import
{
Select
,
Option
,
Button
,
Divider
}
from
"@mui/joy"
;
import
{
isEqual
}
from
"lodash-es"
;
import
{
isEqual
}
from
"lodash-es"
;
import
{
SendIcon
}
from
"lucide-react"
;
import
React
,
{
useEffect
,
useMemo
,
useRef
,
useState
}
from
"react"
;
import
React
,
{
useEffect
,
useMemo
,
useRef
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
useTranslation
}
from
"react-i18next"
;
import
{
useTranslation
}
from
"react-i18next"
;
...
@@ -18,7 +19,6 @@ import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_sett
...
@@ -18,7 +19,6 @@ import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_sett
import
{
WorkspaceSettingKey
}
from
"@/types/proto/store/workspace_setting"
;
import
{
WorkspaceSettingKey
}
from
"@/types/proto/store/workspace_setting"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
convertVisibilityFromString
,
convertVisibilityToString
}
from
"@/utils/memo"
;
import
{
convertVisibilityFromString
,
convertVisibilityToString
}
from
"@/utils/memo"
;
import
Icon
from
"../Icon"
;
import
VisibilityIcon
from
"../VisibilityIcon"
;
import
VisibilityIcon
from
"../VisibilityIcon"
;
import
AddMemoRelationPopover
from
"./ActionButton/AddMemoRelationPopover"
;
import
AddMemoRelationPopover
from
"./ActionButton/AddMemoRelationPopover"
;
import
MarkdownMenu
from
"./ActionButton/MarkdownMenu"
;
import
MarkdownMenu
from
"./ActionButton/MarkdownMenu"
;
...
@@ -473,7 +473,7 @@ const MemoEditor = (props: Props) => {
...
@@ -473,7 +473,7 @@ const MemoEditor = (props: Props) => {
className=
"!font-normal"
className=
"!font-normal"
disabled=
{
!
allowSave
}
disabled=
{
!
allowSave
}
loading=
{
state
.
isRequesting
}
loading=
{
state
.
isRequesting
}
endDecorator=
{
<
Icon
.
Send
className=
"w-4 h-auto"
/>
}
endDecorator=
{
<
SendIcon
className=
"w-4 h-auto"
/>
}
onClick=
{
handleSaveBtnClick
}
onClick=
{
handleSaveBtnClick
}
>
>
{
t
(
"editor.save"
)
}
{
t
(
"editor.save"
)
}
...
...
web/src/components/MemoFilters.tsx
View file @
2dbf92f7
import
{
isEqual
}
from
"lodash-es"
;
import
{
isEqual
}
from
"lodash-es"
;
import
{
CalendarIcon
,
CheckCircleIcon
,
CodeIcon
,
EyeIcon
,
FilterIcon
,
LinkIcon
,
SearchIcon
,
TagIcon
,
XIcon
}
from
"lucide-react"
;
import
{
FilterFactor
,
getMemoFilterKey
,
MemoFilter
,
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
FilterFactor
,
getMemoFilterKey
,
MemoFilter
,
useMemoFilterStore
}
from
"@/store/v1"
;
import
Icon
from
"./Icon"
;
const
MemoFilters
=
()
=>
{
const
MemoFilters
=
()
=>
{
const
memoFilterStore
=
useMemoFilterStore
();
const
memoFilterStore
=
useMemoFilterStore
();
...
@@ -23,7 +23,7 @@ const MemoFilters = () => {
...
@@ -23,7 +23,7 @@ const MemoFilters = () => {
return
(
return
(
<
div
className=
"w-full mb-2 flex flex-row justify-start items-start gap-2"
>
<
div
className=
"w-full mb-2 flex flex-row justify-start items-start gap-2"
>
<
span
className=
"flex flex-row items-center gap-0.5 text-gray-500 text-sm leading-6 border border-transparent"
>
<
span
className=
"flex flex-row items-center gap-0.5 text-gray-500 text-sm leading-6 border border-transparent"
>
<
Icon
.
Filter
className=
"w-4 h-auto opacity-60 inline"
/>
<
FilterIcon
className=
"w-4 h-auto opacity-60 inline"
/>
Filters
Filters
</
span
>
</
span
>
<
div
className=
"flex flex-row justify-start items-center flex-wrap gap-2 leading-6 h-6"
>
<
div
className=
"flex flex-row justify-start items-center flex-wrap gap-2 leading-6 h-6"
>
...
@@ -36,7 +36,7 @@ const MemoFilters = () => {
...
@@ -36,7 +36,7 @@ const MemoFilters = () => {
<
FactorIcon
className=
"w-4 h-auto text-gray-500 dark:text-gray-400 opacity-60"
factor=
{
filter
.
factor
}
/>
<
FactorIcon
className=
"w-4 h-auto text-gray-500 dark:text-gray-400 opacity-60"
factor=
{
filter
.
factor
}
/>
<
span
className=
"text-gray-500 dark:text-gray-400 text-sm max-w-32 truncate"
>
{
getFilterDisplayText
(
filter
)
}
</
span
>
<
span
className=
"text-gray-500 dark:text-gray-400 text-sm max-w-32 truncate"
>
{
getFilterDisplayText
(
filter
)
}
</
span
>
<
button
className=
"text-gray-500 dark:text-gray-300 opacity-60 hover:opacity-100"
>
<
button
className=
"text-gray-500 dark:text-gray-300 opacity-60 hover:opacity-100"
>
<
Icon
.
X
className=
"w-4 h-auto"
/>
<
XIcon
className=
"w-4 h-auto"
/>
</
button
>
</
button
>
</
div
>
</
div
>
))
}
))
}
...
@@ -47,13 +47,13 @@ const MemoFilters = () => {
...
@@ -47,13 +47,13 @@ const MemoFilters = () => {
const
FactorIcon
=
({
factor
,
className
}:
{
factor
:
FilterFactor
;
className
?:
string
})
=>
{
const
FactorIcon
=
({
factor
,
className
}:
{
factor
:
FilterFactor
;
className
?:
string
})
=>
{
const
iconMap
=
{
const
iconMap
=
{
tagSearch
:
<
Icon
.
Tag
className=
{
className
}
/>,
tagSearch
:
<
TagIcon
className=
{
className
}
/>,
visibility
:
<
Icon
.
Eye
className=
{
className
}
/>,
visibility
:
<
EyeIcon
className=
{
className
}
/>,
contentSearch
:
<
Icon
.
Search
className=
{
className
}
/>,
contentSearch
:
<
SearchIcon
className=
{
className
}
/>,
displayTime
:
<
Icon
.
Calendar
className=
{
className
}
/>,
displayTime
:
<
CalendarIcon
className=
{
className
}
/>,
"property.hasLink"
:
<
Icon
.
Link
className
=
{
className
}
/>
,
"property.hasLink"
:
<
LinkIcon
className
=
{
className
}
/>
,
"property.hasTaskList"
:
<
Icon
.
CheckCircle
className
=
{
className
}
/>
,
"property.hasTaskList"
:
<
CheckCircleIcon
className
=
{
className
}
/>
,
"property.hasCode"
:
<
Icon
.
Code
className
=
{
className
}
/>
,
"property.hasCode"
:
<
CodeIcon
className
=
{
className
}
/>
,
};
};
return
iconMap
[
factor
as
keyof
typeof
iconMap
]
||
<></>;
return
iconMap
[
factor
as
keyof
typeof
iconMap
]
||
<></>;
};
};
...
...
web/src/components/MemoRelationListView.tsx
View file @
2dbf92f7
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
{
DotIcon
,
LinkIcon
,
MilestoneIcon
}
from
"lucide-react"
;
import
{
memo
,
useState
}
from
"react"
;
import
{
memo
,
useState
}
from
"react"
;
import
{
Link
}
from
"react-router-dom"
;
import
{
Link
}
from
"react-router-dom"
;
import
useAsyncEffect
from
"@/hooks/useAsyncEffect"
;
import
useAsyncEffect
from
"@/hooks/useAsyncEffect"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
import
{
MemoRelation
}
from
"@/types/proto/api/v1/memo_relation_service"
;
import
{
MemoRelation
}
from
"@/types/proto/api/v1/memo_relation_service"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
Memo
}
from
"@/types/proto/api/v1/memo_service"
;
import
Icon
from
"./Icon"
;
interface
Props
{
interface
Props
{
memo
:
Memo
;
memo
:
Memo
;
...
@@ -54,7 +54,7 @@ const MemoRelationListView = (props: Props) => {
...
@@ -54,7 +54,7 @@ const MemoRelationListView = (props: Props) => {
)
}
)
}
onClick=
{
()
=>
setSelectedTab
(
"referencing"
)
}
onClick=
{
()
=>
setSelectedTab
(
"referencing"
)
}
>
>
<
Icon
.
Link
className=
"w-3 h-auto shrink-0 opacity-70"
/>
<
LinkIcon
className=
"w-3 h-auto shrink-0 opacity-70"
/>
<
span
>
Referencing
</
span
>
<
span
>
Referencing
</
span
>
<
span
className=
"opacity-80"
>
(
{
referencingMemoList
.
length
}
)
</
span
>
<
span
className=
"opacity-80"
>
(
{
referencingMemoList
.
length
}
)
</
span
>
</
button
>
</
button
>
...
@@ -67,7 +67,7 @@ const MemoRelationListView = (props: Props) => {
...
@@ -67,7 +67,7 @@ const MemoRelationListView = (props: Props) => {
)
}
)
}
onClick=
{
()
=>
setSelectedTab
(
"referenced"
)
}
onClick=
{
()
=>
setSelectedTab
(
"referenced"
)
}
>
>
<
Icon
.
Milestone
className=
"w-3 h-auto shrink-0 opacity-70"
/>
<
MilestoneIcon
className=
"w-3 h-auto shrink-0 opacity-70"
/>
<
span
>
Referenced by
</
span
>
<
span
>
Referenced by
</
span
>
<
span
className=
"opacity-80"
>
(
{
referencedMemoList
.
length
}
)
</
span
>
<
span
className=
"opacity-80"
>
(
{
referencedMemoList
.
length
}
)
</
span
>
</
button
>
</
button
>
...
@@ -83,7 +83,7 @@ const MemoRelationListView = (props: Props) => {
...
@@ -83,7 +83,7 @@ const MemoRelationListView = (props: Props) => {
to=
{
`/m/${memo.uid}`
}
to=
{
`/m/${memo.uid}`
}
unstable_viewTransition
unstable_viewTransition
>
>
<
Icon
.
Dot
className=
"shrink-0 w-4 h-auto opacity-40"
/>
<
DotIcon
className=
"shrink-0 w-4 h-auto opacity-40"
/>
<
span
className=
"truncate"
>
{
memo
.
snippet
}
</
span
>
<
span
className=
"truncate"
>
{
memo
.
snippet
}
</
span
>
</
Link
>
</
Link
>
);
);
...
@@ -100,7 +100,7 @@ const MemoRelationListView = (props: Props) => {
...
@@ -100,7 +100,7 @@ const MemoRelationListView = (props: Props) => {
to=
{
`/m/${memo.uid}`
}
to=
{
`/m/${memo.uid}`
}
unstable_viewTransition
unstable_viewTransition
>
>
<
Icon
.
Dot
className=
"shrink-0 w-4 h-auto opacity-40"
/>
<
DotIcon
className=
"shrink-0 w-4 h-auto opacity-40"
/>
<
span
className=
"truncate"
>
{
memo
.
snippet
}
</
span
>
<
span
className=
"truncate"
>
{
memo
.
snippet
}
</
span
>
</
Link
>
</
Link
>
);
);
...
...
web/src/components/MemoView.tsx
View file @
2dbf92f7
import
{
Tooltip
}
from
"@mui/joy"
;
import
{
Tooltip
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
{
BookmarkIcon
,
MessageCircleMoreIcon
}
from
"lucide-react"
;
import
{
memo
,
useCallback
,
useEffect
,
useRef
,
useState
}
from
"react"
;
import
{
memo
,
useCallback
,
useEffect
,
useRef
,
useState
}
from
"react"
;
import
{
Link
,
useLocation
}
from
"react-router-dom"
;
import
{
Link
,
useLocation
}
from
"react-router-dom"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
...
@@ -11,7 +12,6 @@ import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_sett
...
@@ -11,7 +12,6 @@ import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_sett
import
{
WorkspaceSettingKey
}
from
"@/types/proto/store/workspace_setting"
;
import
{
WorkspaceSettingKey
}
from
"@/types/proto/store/workspace_setting"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
convertVisibilityToString
}
from
"@/utils/memo"
;
import
{
convertVisibilityToString
}
from
"@/utils/memo"
;
import
Icon
from
"./Icon"
;
import
MemoActionMenu
from
"./MemoActionMenu"
;
import
MemoActionMenu
from
"./MemoActionMenu"
;
import
MemoContent
from
"./MemoContent"
;
import
MemoContent
from
"./MemoContent"
;
import
MemoEditor
from
"./MemoEditor"
;
import
MemoEditor
from
"./MemoEditor"
;
...
@@ -169,13 +169,13 @@ const MemoView: React.FC<Props> = (props: Props) => {
...
@@ -169,13 +169,13 @@ const MemoView: React.FC<Props> = (props: Props) => {
to=
{
`/m/${memo.uid}#comments`
}
to=
{
`/m/${memo.uid}#comments`
}
unstable_viewTransition
unstable_viewTransition
>
>
<
Icon
.
MessageCircleMore
className=
"w-4 h-4 mx-auto text-gray-500 dark:text-gray-400"
/>
<
MessageCircleMoreIcon
className=
"w-4 h-4 mx-auto text-gray-500 dark:text-gray-400"
/>
{
commentAmount
>
0
&&
<
span
className=
"text-xs text-gray-500 dark:text-gray-400"
>
{
commentAmount
}
</
span
>
}
{
commentAmount
>
0
&&
<
span
className=
"text-xs text-gray-500 dark:text-gray-400"
>
{
commentAmount
}
</
span
>
}
</
Link
>
</
Link
>
)
}
)
}
{
props
.
showPinned
&&
memo
.
pinned
&&
(
{
props
.
showPinned
&&
memo
.
pinned
&&
(
<
Tooltip
title=
{
t
(
"common.pinned"
)
}
placement=
"top"
>
<
Tooltip
title=
{
t
(
"common.pinned"
)
}
placement=
"top"
>
<
Icon
.
Bookmark
className=
"w-4 h-auto text-amber-500"
/>
<
BookmarkIcon
className=
"w-4 h-auto text-amber-500"
/>
</
Tooltip
>
</
Tooltip
>
)
}
)
}
{
!
readonly
&&
(
{
!
readonly
&&
(
...
...
web/src/components/Navigation.tsx
View file @
2dbf92f7
import
{
Tooltip
}
from
"@mui/joy"
;
import
{
Tooltip
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
{
ArchiveIcon
,
BellIcon
,
Globe2Icon
,
HomeIcon
,
LogInIcon
,
PaperclipIcon
,
SettingsIcon
,
SmileIcon
,
User2Icon
}
from
"lucide-react"
;
import
{
useEffect
}
from
"react"
;
import
{
useEffect
}
from
"react"
;
import
{
NavLink
}
from
"react-router-dom"
;
import
{
NavLink
}
from
"react-router-dom"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
...
@@ -7,7 +8,6 @@ import { Routes } from "@/router";
...
@@ -7,7 +8,6 @@ import { Routes } from "@/router";
import
{
useInboxStore
}
from
"@/store/v1"
;
import
{
useInboxStore
}
from
"@/store/v1"
;
import
{
Inbox_Status
}
from
"@/types/proto/api/v1/inbox_service"
;
import
{
Inbox_Status
}
from
"@/types/proto/api/v1/inbox_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Icon
from
"./Icon"
;
import
UserBanner
from
"./UserBanner"
;
import
UserBanner
from
"./UserBanner"
;
interface
NavLinkItem
{
interface
NavLinkItem
{
...
@@ -52,25 +52,25 @@ const Navigation = (props: Props) => {
...
@@ -52,25 +52,25 @@ const Navigation = (props: Props) => {
id
:
"header-home"
,
id
:
"header-home"
,
path
:
Routes
.
ROOT
,
path
:
Routes
.
ROOT
,
title
:
t
(
"common.home"
),
title
:
t
(
"common.home"
),
icon
:
<
Icon
.
Home
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
icon
:
<
HomeIcon
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
};
};
const
resourcesNavLink
:
NavLinkItem
=
{
const
resourcesNavLink
:
NavLinkItem
=
{
id
:
"header-resources"
,
id
:
"header-resources"
,
path
:
Routes
.
RESOURCES
,
path
:
Routes
.
RESOURCES
,
title
:
t
(
"common.resources"
),
title
:
t
(
"common.resources"
),
icon
:
<
Icon
.
Paperclip
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
icon
:
<
PaperclipIcon
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
};
};
const
exploreNavLink
:
NavLinkItem
=
{
const
exploreNavLink
:
NavLinkItem
=
{
id
:
"header-explore"
,
id
:
"header-explore"
,
path
:
Routes
.
EXPLORE
,
path
:
Routes
.
EXPLORE
,
title
:
t
(
"common.explore"
),
title
:
t
(
"common.explore"
),
icon
:
<
Icon
.
Globe2
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
icon
:
<
Globe2Icon
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
};
};
const
profileNavLink
:
NavLinkItem
=
{
const
profileNavLink
:
NavLinkItem
=
{
id
:
"header-profile"
,
id
:
"header-profile"
,
path
:
user
?
`/u/
${
encodeURIComponent
(
user
.
username
)}
`
:
""
,
path
:
user
?
`/u/
${
encodeURIComponent
(
user
.
username
)}
`
:
""
,
title
:
t
(
"common.profile"
),
title
:
t
(
"common.profile"
),
icon
:
<
Icon
.
User2
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
icon
:
<
User2Icon
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
};
};
const
inboxNavLink
:
NavLinkItem
=
{
const
inboxNavLink
:
NavLinkItem
=
{
id
:
"header-inbox"
,
id
:
"header-inbox"
,
...
@@ -79,7 +79,7 @@ const Navigation = (props: Props) => {
...
@@ -79,7 +79,7 @@ const Navigation = (props: Props) => {
icon
:
(
icon
:
(
<>
<>
<
div
className=
"relative"
>
<
div
className=
"relative"
>
<
Icon
.
Bell
className=
"w-6 h-auto opacity-70 shrink-0"
/>
<
BellIcon
className=
"w-6 h-auto opacity-70 shrink-0"
/>
{
hasUnreadInbox
&&
<
div
className=
"absolute top-0 left-5 w-2 h-2 rounded-full bg-blue-500"
></
div
>
}
{
hasUnreadInbox
&&
<
div
className=
"absolute top-0 left-5 w-2 h-2 rounded-full bg-blue-500"
></
div
>
}
</
div
>
</
div
>
</>
</>
...
@@ -89,25 +89,25 @@ const Navigation = (props: Props) => {
...
@@ -89,25 +89,25 @@ const Navigation = (props: Props) => {
id
:
"header-archived"
,
id
:
"header-archived"
,
path
:
Routes
.
ARCHIVED
,
path
:
Routes
.
ARCHIVED
,
title
:
t
(
"common.archived"
),
title
:
t
(
"common.archived"
),
icon
:
<
Icon
.
Archive
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
icon
:
<
ArchiveIcon
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
};
};
const
settingNavLink
:
NavLinkItem
=
{
const
settingNavLink
:
NavLinkItem
=
{
id
:
"header-setting"
,
id
:
"header-setting"
,
path
:
Routes
.
SETTING
,
path
:
Routes
.
SETTING
,
title
:
t
(
"common.settings"
),
title
:
t
(
"common.settings"
),
icon
:
<
Icon
.
Settings
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
icon
:
<
SettingsIcon
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
};
};
const
signInNavLink
:
NavLinkItem
=
{
const
signInNavLink
:
NavLinkItem
=
{
id
:
"header-auth"
,
id
:
"header-auth"
,
path
:
Routes
.
AUTH
,
path
:
Routes
.
AUTH
,
title
:
t
(
"common.sign-in"
),
title
:
t
(
"common.sign-in"
),
icon
:
<
Icon
.
LogI
n
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
icon
:
<
LogInIco
n
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
};
};
const
aboutNavLink
:
NavLinkItem
=
{
const
aboutNavLink
:
NavLinkItem
=
{
id
:
"header-about"
,
id
:
"header-about"
,
path
:
Routes
.
ABOUT
,
path
:
Routes
.
ABOUT
,
title
:
t
(
"common.about"
),
title
:
t
(
"common.about"
),
icon
:
<
Icon
.
Smile
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
icon
:
<
SmileIcon
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
};
};
const
navLinks
:
NavLinkItem
[]
=
user
const
navLinks
:
NavLinkItem
[]
=
user
...
...
web/src/components/NavigationDrawer.tsx
View file @
2dbf92f7
import
{
Drawer
,
IconButton
}
from
"@mui/joy"
;
import
{
Drawer
,
IconButton
}
from
"@mui/joy"
;
import
{
MenuIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
{
useLocation
}
from
"react-router-dom"
;
import
Icon
from
"./Icon"
;
import
Navigation
from
"./Navigation"
;
import
Navigation
from
"./Navigation"
;
const
NavigationDrawer
=
()
=>
{
const
NavigationDrawer
=
()
=>
{
...
@@ -23,7 +23,7 @@ const NavigationDrawer = () => {
...
@@ -23,7 +23,7 @@ const NavigationDrawer = () => {
return
(
return
(
<>
<>
<
IconButton
onClick=
{
toggleDrawer
(
true
)
}
>
<
IconButton
onClick=
{
toggleDrawer
(
true
)
}
>
<
Icon
.
Menu
className=
"w-5 h-auto dark:text-gray-400"
/>
<
MenuIcon
className=
"w-5 h-auto dark:text-gray-400"
/>
</
IconButton
>
</
IconButton
>
<
Drawer
anchor=
"left"
size=
"sm"
open=
{
open
}
onClose=
{
toggleDrawer
(
false
)
}
>
<
Drawer
anchor=
"left"
size=
"sm"
open=
{
open
}
onClose=
{
toggleDrawer
(
false
)
}
>
<
div
className=
"w-full h-full overflow-auto px-4 bg-zinc-100 dark:bg-zinc-900"
>
<
div
className=
"w-full h-full overflow-auto px-4 bg-zinc-100 dark:bg-zinc-900"
>
...
...
web/src/components/PreviewImageDialog.tsx
View file @
2dbf92f7
import
{
XIcon
}
from
"lucide-react"
;
import
React
,
{
useState
}
from
"react"
;
import
React
,
{
useState
}
from
"react"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
Icon
from
"./Icon"
;
import
"@/less/preview-image-dialog.less"
;
import
"@/less/preview-image-dialog.less"
;
const
MIN_SCALE
=
0.5
;
const
MIN_SCALE
=
0.5
;
...
@@ -116,7 +116,7 @@ const PreviewImageDialog: React.FC<Props> = ({ destroy, imgUrls, initialIndex }:
...
@@ -116,7 +116,7 @@ const PreviewImageDialog: React.FC<Props> = ({ destroy, imgUrls, initialIndex }:
<>
<>
<
div
className=
"btns-container"
>
<
div
className=
"btns-container"
>
<
button
className=
"btn"
onClick=
{
handleCloseBtnClick
}
>
<
button
className=
"btn"
onClick=
{
handleCloseBtnClick
}
>
<
Icon
.
X
className=
"icon-img"
/>
<
XIcon
className=
"icon-img"
/>
</
button
>
</
button
>
</
div
>
</
div
>
<
div
className=
"img-container"
onClick=
{
handleImgContainerClick
}
>
<
div
className=
"img-container"
onClick=
{
handleImgContainerClick
}
>
...
...
web/src/components/ReactionSelector.tsx
View file @
2dbf92f7
import
{
Dropdown
,
Menu
,
MenuButton
}
from
"@mui/joy"
;
import
{
Dropdown
,
Menu
,
MenuButton
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
{
SmilePlusIcon
}
from
"lucide-react"
;
import
{
useRef
,
useState
}
from
"react"
;
import
{
useRef
,
useState
}
from
"react"
;
import
useClickAway
from
"react-use/lib/useClickAway"
;
import
useClickAway
from
"react-use/lib/useClickAway"
;
import
Icon
from
"@/components/Icon"
;
import
{
memoServiceClient
}
from
"@/grpcweb"
;
import
{
memoServiceClient
}
from
"@/grpcweb"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
import
{
useMemoStore
}
from
"@/store/v1"
;
...
@@ -76,7 +76,7 @@ const ReactionSelector = (props: Props) => {
...
@@ -76,7 +76,7 @@ const ReactionSelector = (props: Props) => {
<
span
<
span
className=
{
clsx
(
"h-7 w-7 flex justify-center items-center rounded-full border dark:border-zinc-700 hover:opacity-70"
,
className
)
}
className=
{
clsx
(
"h-7 w-7 flex justify-center items-center rounded-full border dark:border-zinc-700 hover:opacity-70"
,
className
)
}
>
>
<
Icon
.
SmilePlus
className=
"w-4 h-4 mx-auto text-gray-500 dark:text-gray-400"
/>
<
SmilePlusIcon
className=
"w-4 h-4 mx-auto text-gray-500 dark:text-gray-400"
/>
</
span
>
</
span
>
</
MenuButton
>
</
MenuButton
>
<
Menu
className=
"relative text-sm"
component=
"div"
size=
"sm"
placement=
"bottom-start"
>
<
Menu
className=
"relative text-sm"
component=
"div"
size=
"sm"
placement=
"bottom-start"
>
...
...
web/src/components/RenameTagDialog.tsx
View file @
2dbf92f7
import
{
Button
,
IconButton
,
Input
,
List
,
ListItem
}
from
"@mui/joy"
;
import
{
Button
,
IconButton
,
Input
,
List
,
ListItem
}
from
"@mui/joy"
;
import
{
XIcon
}
from
"lucide-react"
;
import
React
,
{
useState
}
from
"react"
;
import
React
,
{
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
memoServiceClient
}
from
"@/grpcweb"
;
import
{
memoServiceClient
}
from
"@/grpcweb"
;
...
@@ -7,7 +8,6 @@ import useLoading from "@/hooks/useLoading";
...
@@ -7,7 +8,6 @@ import useLoading from "@/hooks/useLoading";
import
{
useTagStore
}
from
"@/store/v1"
;
import
{
useTagStore
}
from
"@/store/v1"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
Icon
from
"./Icon"
;
interface
Props
extends
DialogProps
{
interface
Props
extends
DialogProps
{
tag
:
string
;
tag
:
string
;
...
@@ -55,7 +55,7 @@ const RenameTagDialog: React.FC<Props> = (props: Props) => {
...
@@ -55,7 +55,7 @@ const RenameTagDialog: React.FC<Props> = (props: Props) => {
<
div
className=
"dialog-header-container"
>
<
div
className=
"dialog-header-container"
>
<
p
className=
"title-text"
>
{
"Rename tag"
}
</
p
>
<
p
className=
"title-text"
>
{
"Rename tag"
}
</
p
>
<
IconButton
size=
"sm"
onClick=
{
()
=>
destroy
()
}
>
<
IconButton
size=
"sm"
onClick=
{
()
=>
destroy
()
}
>
<
Icon
.
X
className=
"w-5 h-auto"
/>
<
XIcon
className=
"w-5 h-auto"
/>
</
IconButton
>
</
IconButton
>
</
div
>
</
div
>
<
div
className=
"dialog-content-container max-w-xs"
>
<
div
className=
"dialog-content-container max-w-xs"
>
...
...
web/src/components/ResourceIcon.tsx
View file @
2dbf92f7
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
{
BinaryIcon
,
BookIcon
,
FileArchiveIcon
,
FileAudioIcon
,
FileEditIcon
,
FileIcon
,
FileTextIcon
,
FileVideo2Icon
,
SheetIcon
,
}
from
"lucide-react"
;
import
React
from
"react"
;
import
React
from
"react"
;
import
{
Resource
}
from
"@/types/proto/api/v1/resource_service"
;
import
{
Resource
}
from
"@/types/proto/api/v1/resource_service"
;
import
{
getResourceType
,
getResourceUrl
}
from
"@/utils/resource"
;
import
{
getResourceType
,
getResourceUrl
}
from
"@/utils/resource"
;
import
Icon
from
"./Icon"
;
import
showPreviewImageDialog
from
"./PreviewImageDialog"
;
import
showPreviewImageDialog
from
"./PreviewImageDialog"
;
import
SquareDiv
from
"./kit/SquareDiv"
;
import
SquareDiv
from
"./kit/SquareDiv"
;
...
@@ -40,25 +50,25 @@ const ResourceIcon = (props: Props) => {
...
@@ -40,25 +50,25 @@ const ResourceIcon = (props: Props) => {
const
getResourceIcon
=
()
=>
{
const
getResourceIcon
=
()
=>
{
switch
(
resourceType
)
{
switch
(
resourceType
)
{
case
"video/*"
:
case
"video/*"
:
return
<
Icon
.
FileVideo2
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
return
<
FileVideo2Icon
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
case
"audio/*"
:
case
"audio/*"
:
return
<
Icon
.
FileAudio
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
return
<
FileAudioIcon
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
case
"text/*"
:
case
"text/*"
:
return
<
Icon
.
FileText
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
return
<
FileTextIcon
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
case
"application/epub+zip"
:
case
"application/epub+zip"
:
return
<
Icon
.
Book
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
return
<
BookIcon
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
case
"application/pdf"
:
case
"application/pdf"
:
return
<
Icon
.
Book
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
return
<
BookIcon
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
case
"application/msword"
:
case
"application/msword"
:
return
<
Icon
.
FileEdit
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
return
<
FileEditIcon
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
case
"application/msexcel"
:
case
"application/msexcel"
:
return
<
Icon
.
SheetIcon
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
return
<
SheetIcon
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
case
"application/zip"
:
case
"application/zip"
:
return
<
Icon
.
FileArchiveIcon
onClick=
{
previewResource
}
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
return
<
FileArchiveIcon
onClick=
{
previewResource
}
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
case
"application/x-java-archive"
:
case
"application/x-java-archive"
:
return
<
Icon
.
BinaryIcon
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
return
<
BinaryIcon
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
default
:
default
:
return
<
Icon
.
File
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
return
<
FileIcon
strokeWidth=
{
strokeWidth
}
className=
"w-full h-auto"
/>;
}
}
};
};
...
...
web/src/components/SearchBar.tsx
View file @
2dbf92f7
import
{
SearchIcon
}
from
"lucide-react"
;
import
{
useState
}
from
"react"
;
import
{
useState
}
from
"react"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Icon
from
"./Icon"
;
import
MemoDisplaySettingMenu
from
"./MemoDisplaySettingMenu"
;
import
MemoDisplaySettingMenu
from
"./MemoDisplaySettingMenu"
;
const
SearchBar
=
()
=>
{
const
SearchBar
=
()
=>
{
...
@@ -29,7 +29,7 @@ const SearchBar = () => {
...
@@ -29,7 +29,7 @@ const SearchBar = () => {
return
(
return
(
<
div
className=
"relative w-full h-auto flex flex-row justify-start items-center"
>
<
div
className=
"relative w-full h-auto flex flex-row justify-start items-center"
>
<
Icon
.
Search
className=
"absolute left-3 w-4 h-auto opacity-40"
/>
<
SearchIcon
className=
"absolute left-3 w-4 h-auto opacity-40"
/>
<
input
<
input
className=
"w-full text-gray-500 dark:text-gray-400 bg-zinc-50 dark:bg-zinc-900 border dark:border-zinc-800 text-sm leading-7 rounded-lg p-1 pl-8 outline-none"
className=
"w-full text-gray-500 dark:text-gray-400 bg-zinc-50 dark:bg-zinc-900 border dark:border-zinc-800 text-sm leading-7 rounded-lg p-1 pl-8 outline-none"
placeholder=
{
t
(
"memo.search-placeholder"
)
}
placeholder=
{
t
(
"memo.search-placeholder"
)
}
...
...
web/src/components/Settings/AccessTokenSection.tsx
View file @
2dbf92f7
import
{
Button
,
IconButton
}
from
"@mui/joy"
;
import
{
Button
,
IconButton
}
from
"@mui/joy"
;
import
copy
from
"copy-to-clipboard"
;
import
copy
from
"copy-to-clipboard"
;
import
{
ClipboardIcon
,
TrashIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
userServiceClient
}
from
"@/grpcweb"
;
import
{
userServiceClient
}
from
"@/grpcweb"
;
...
@@ -7,7 +8,6 @@ import useCurrentUser from "@/hooks/useCurrentUser";
...
@@ -7,7 +8,6 @@ import useCurrentUser from "@/hooks/useCurrentUser";
import
{
UserAccessToken
}
from
"@/types/proto/api/v1/user_service"
;
import
{
UserAccessToken
}
from
"@/types/proto/api/v1/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
showCreateAccessTokenDialog
from
"../CreateAccessTokenDialog"
;
import
showCreateAccessTokenDialog
from
"../CreateAccessTokenDialog"
;
import
Icon
from
"../Icon"
;
import
LearnMore
from
"../LearnMore"
;
import
LearnMore
from
"../LearnMore"
;
const
listAccessTokens
=
async
(
name
:
string
)
=>
{
const
listAccessTokens
=
async
(
name
:
string
)
=>
{
...
@@ -102,7 +102,7 @@ const AccessTokenSection = () => {
...
@@ -102,7 +102,7 @@ const AccessTokenSection = () => {
<
td
className=
"whitespace-nowrap px-3 py-2 text-sm text-gray-900 dark:text-gray-400 flex flex-row justify-start items-center gap-x-1"
>
<
td
className=
"whitespace-nowrap px-3 py-2 text-sm text-gray-900 dark:text-gray-400 flex flex-row justify-start items-center gap-x-1"
>
<
span
className=
"font-mono"
>
{
getFormatedAccessToken
(
userAccessToken
.
accessToken
)
}
</
span
>
<
span
className=
"font-mono"
>
{
getFormatedAccessToken
(
userAccessToken
.
accessToken
)
}
</
span
>
<
IconButton
color=
"neutral"
variant=
"plain"
size=
"sm"
onClick=
{
()
=>
copyAccessToken
(
userAccessToken
.
accessToken
)
}
>
<
IconButton
color=
"neutral"
variant=
"plain"
size=
"sm"
onClick=
{
()
=>
copyAccessToken
(
userAccessToken
.
accessToken
)
}
>
<
Icon
.
Clipboard
className=
"w-4 h-auto text-gray-400"
/>
<
ClipboardIcon
className=
"w-4 h-auto text-gray-400"
/>
</
IconButton
>
</
IconButton
>
</
td
>
</
td
>
<
td
className=
"whitespace-nowrap py-2 pl-4 pr-3 text-sm text-gray-900 dark:text-gray-400"
>
<
td
className=
"whitespace-nowrap py-2 pl-4 pr-3 text-sm text-gray-900 dark:text-gray-400"
>
...
@@ -123,7 +123,7 @@ const AccessTokenSection = () => {
...
@@ -123,7 +123,7 @@ const AccessTokenSection = () => {
handleDeleteAccessToken
(
userAccessToken
.
accessToken
);
handleDeleteAccessToken
(
userAccessToken
.
accessToken
);
}
}
}
}
>
>
<
Icon
.
Trash
className=
"w-4 h-auto"
/>
<
TrashIcon
className=
"w-4 h-auto"
/>
</
IconButton
>
</
IconButton
>
</
td
>
</
td
>
</
tr
>
</
tr
>
...
...
web/src/components/Settings/MemberSection.tsx
View file @
2dbf92f7
import
{
Button
,
Dropdown
,
Input
,
Menu
,
MenuButton
,
MenuItem
,
Radio
,
RadioGroup
}
from
"@mui/joy"
;
import
{
Button
,
Dropdown
,
Input
,
Menu
,
MenuButton
,
MenuItem
,
Radio
,
RadioGroup
}
from
"@mui/joy"
;
import
{
sortBy
}
from
"lodash-es"
;
import
{
sortBy
}
from
"lodash-es"
;
import
{
MoreVerticalIcon
}
from
"lucide-react"
;
import
React
,
{
useEffect
,
useState
}
from
"react"
;
import
React
,
{
useEffect
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
userServiceClient
}
from
"@/grpcweb"
;
import
{
userServiceClient
}
from
"@/grpcweb"
;
...
@@ -9,7 +10,6 @@ import { RowStatus } from "@/types/proto/api/v1/common";
...
@@ -9,7 +10,6 @@ import { RowStatus } from "@/types/proto/api/v1/common";
import
{
User
,
User_Role
}
from
"@/types/proto/api/v1/user_service"
;
import
{
User
,
User_Role
}
from
"@/types/proto/api/v1/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
showChangeMemberPasswordDialog
from
"../ChangeMemberPasswordDialog"
;
import
showChangeMemberPasswordDialog
from
"../ChangeMemberPasswordDialog"
;
import
Icon
from
"../Icon"
;
interface
State
{
interface
State
{
creatingUser
:
User
;
creatingUser
:
User
;
...
@@ -204,7 +204,7 @@ const MemberSection = () => {
...
@@ -204,7 +204,7 @@ const MemberSection = () => {
)
:
(
)
:
(
<
Dropdown
>
<
Dropdown
>
<
MenuButton
size=
"sm"
>
<
MenuButton
size=
"sm"
>
<
Icon
.
MoreVertical
className=
"w-4 h-auto"
/>
<
MoreVerticalIcon
className=
"w-4 h-auto"
/>
</
MenuButton
>
</
MenuButton
>
<
Menu
placement=
"bottom-end"
size=
"sm"
>
<
Menu
placement=
"bottom-end"
size=
"sm"
>
<
MenuItem
onClick=
{
()
=>
handleChangePasswordClick
(
user
)
}
>
<
MenuItem
onClick=
{
()
=>
handleChangePasswordClick
(
user
)
}
>
...
...
web/src/components/Settings/MyAccountSection.tsx
View file @
2dbf92f7
import
{
Button
,
Dropdown
,
Menu
,
MenuButton
,
MenuItem
}
from
"@mui/joy"
;
import
{
Button
,
Dropdown
,
Menu
,
MenuButton
,
MenuItem
}
from
"@mui/joy"
;
import
{
MoreVerticalIcon
,
PenLineIcon
}
from
"lucide-react"
;
import
{
memoServiceClient
}
from
"@/grpcweb"
;
import
{
memoServiceClient
}
from
"@/grpcweb"
;
import
{
downloadFileFromUrl
}
from
"@/helpers/utils"
;
import
{
downloadFileFromUrl
}
from
"@/helpers/utils"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
showChangePasswordDialog
from
"../ChangePasswordDialog"
;
import
showChangePasswordDialog
from
"../ChangePasswordDialog"
;
import
Icon
from
"../Icon"
;
import
showUpdateAccountDialog
from
"../UpdateAccountDialog"
;
import
showUpdateAccountDialog
from
"../UpdateAccountDialog"
;
import
UserAvatar
from
"../UserAvatar"
;
import
UserAvatar
from
"../UserAvatar"
;
import
AccessTokenSection
from
"./AccessTokenSection"
;
import
AccessTokenSection
from
"./AccessTokenSection"
;
...
@@ -35,13 +35,13 @@ const MyAccountSection = () => {
...
@@ -35,13 +35,13 @@ const MyAccountSection = () => {
</
div
>
</
div
>
<
div
className=
"w-full flex flex-row justify-start items-center mt-2 space-x-2"
>
<
div
className=
"w-full flex flex-row justify-start items-center mt-2 space-x-2"
>
<
Button
variant=
"outlined"
color=
"neutral"
size=
"sm"
onClick=
{
showUpdateAccountDialog
}
>
<
Button
variant=
"outlined"
color=
"neutral"
size=
"sm"
onClick=
{
showUpdateAccountDialog
}
>
<
Icon
.
PenLine
className=
"w-4 h-4 mx-auto mr-1"
/>
<
PenLineIcon
className=
"w-4 h-4 mx-auto mr-1"
/>
{
t
(
"common.edit"
)
}
{
t
(
"common.edit"
)
}
</
Button
>
</
Button
>
<
Dropdown
>
<
Dropdown
>
<
MenuButton
slots=
{
{
root
:
"div"
}
}
>
<
MenuButton
slots=
{
{
root
:
"div"
}
}
>
<
Button
variant=
"outlined"
color=
"neutral"
size=
"sm"
>
<
Button
variant=
"outlined"
color=
"neutral"
size=
"sm"
>
<
Icon
.
MoreVertical
className=
"w-4 h-4 mx-auto"
/>
<
MoreVerticalIcon
className=
"w-4 h-4 mx-auto"
/>
</
Button
>
</
Button
>
</
MenuButton
>
</
MenuButton
>
<
Menu
className=
"text-sm"
size=
"sm"
placement=
"bottom"
>
<
Menu
className=
"text-sm"
size=
"sm"
placement=
"bottom"
>
...
...
web/src/components/Settings/SSOSection.tsx
View file @
2dbf92f7
import
{
Button
,
Divider
,
Dropdown
,
List
,
ListItem
,
Menu
,
MenuButton
,
MenuItem
}
from
"@mui/joy"
;
import
{
Button
,
Divider
,
Dropdown
,
List
,
ListItem
,
Menu
,
MenuButton
,
MenuItem
}
from
"@mui/joy"
;
import
{
MoreVerticalIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
Link
}
from
"react-router-dom"
;
import
{
Link
}
from
"react-router-dom"
;
...
@@ -6,7 +7,6 @@ import { identityProviderServiceClient } from "@/grpcweb";
...
@@ -6,7 +7,6 @@ import { identityProviderServiceClient } from "@/grpcweb";
import
{
IdentityProvider
}
from
"@/types/proto/api/v1/idp_service"
;
import
{
IdentityProvider
}
from
"@/types/proto/api/v1/idp_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
showCreateIdentityProviderDialog
from
"../CreateIdentityProviderDialog"
;
import
showCreateIdentityProviderDialog
from
"../CreateIdentityProviderDialog"
;
import
Icon
from
"../Icon"
;
import
LearnMore
from
"../LearnMore"
;
import
LearnMore
from
"../LearnMore"
;
const
SSOSection
=
()
=>
{
const
SSOSection
=
()
=>
{
...
@@ -59,7 +59,7 @@ const SSOSection = () => {
...
@@ -59,7 +59,7 @@ const SSOSection = () => {
<
div
className=
"flex flex-row items-center"
>
<
div
className=
"flex flex-row items-center"
>
<
Dropdown
>
<
Dropdown
>
<
MenuButton
size=
"sm"
>
<
MenuButton
size=
"sm"
>
<
Icon
.
MoreVertical
className=
"w-4 h-auto"
/>
<
MoreVerticalIcon
className=
"w-4 h-auto"
/>
</
MenuButton
>
</
MenuButton
>
<
Menu
placement=
"bottom-end"
size=
"sm"
>
<
Menu
placement=
"bottom-end"
size=
"sm"
>
<
MenuItem
onClick=
{
()
=>
showCreateIdentityProviderDialog
(
identityProvider
,
fetchIdentityProviderList
)
}
>
<
MenuItem
onClick=
{
()
=>
showCreateIdentityProviderDialog
(
identityProvider
,
fetchIdentityProviderList
)
}
>
...
...
web/src/components/Settings/StorageSection.tsx
View file @
2dbf92f7
import
{
Button
,
Divider
,
Input
,
List
,
ListItem
,
Radio
,
RadioGroup
,
Tooltip
}
from
"@mui/joy"
;
import
{
Button
,
Divider
,
Input
,
List
,
ListItem
,
Radio
,
RadioGroup
,
Tooltip
}
from
"@mui/joy"
;
import
{
isEqual
}
from
"lodash-es"
;
import
{
isEqual
}
from
"lodash-es"
;
import
{
HelpCircleIcon
}
from
"lucide-react"
;
import
{
useMemo
,
useState
}
from
"react"
;
import
{
useMemo
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
Link
}
from
"react-router-dom"
;
import
{
Link
}
from
"react-router-dom"
;
...
@@ -11,7 +12,6 @@ import {
...
@@ -11,7 +12,6 @@ import {
}
from
"@/types/proto/api/v1/workspace_setting_service"
;
}
from
"@/types/proto/api/v1/workspace_setting_service"
;
import
{
WorkspaceSettingKey
}
from
"@/types/proto/store/workspace_setting"
;
import
{
WorkspaceSettingKey
}
from
"@/types/proto/store/workspace_setting"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Icon
from
"../Icon"
;
const
StorageSection
=
()
=>
{
const
StorageSection
=
()
=>
{
const
t
=
useTranslate
();
const
t
=
useTranslate
();
...
@@ -132,7 +132,7 @@ const StorageSection = () => {
...
@@ -132,7 +132,7 @@ const StorageSection = () => {
<
div
className=
"flex flex-row items-center"
>
<
div
className=
"flex flex-row items-center"
>
<
span
className=
"text-gray-700 dark:text-gray-500 mr-1"
>
{
t
(
"setting.system-section.max-upload-size"
)
}
</
span
>
<
span
className=
"text-gray-700 dark:text-gray-500 mr-1"
>
{
t
(
"setting.system-section.max-upload-size"
)
}
</
span
>
<
Tooltip
title=
{
t
(
"setting.system-section.max-upload-size-hint"
)
}
placement=
"top"
>
<
Tooltip
title=
{
t
(
"setting.system-section.max-upload-size-hint"
)
}
placement=
"top"
>
<
Icon
.
HelpCircle
className=
"w-4 h-auto"
/>
<
HelpCircleIcon
className=
"w-4 h-auto"
/>
</
Tooltip
>
</
Tooltip
>
</
div
>
</
div
>
<
Input
<
Input
...
...
web/src/components/Settings/WebhookSection.tsx
View file @
2dbf92f7
import
{
Button
,
IconButton
}
from
"@mui/joy"
;
import
{
Button
,
IconButton
}
from
"@mui/joy"
;
import
{
ExternalLinkIcon
,
TrashIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
Link
}
from
"react-router-dom"
;
import
{
Link
}
from
"react-router-dom"
;
import
{
webhookServiceClient
}
from
"@/grpcweb"
;
import
{
webhookServiceClient
}
from
"@/grpcweb"
;
...
@@ -6,7 +7,6 @@ import useCurrentUser from "@/hooks/useCurrentUser";
...
@@ -6,7 +7,6 @@ import useCurrentUser from "@/hooks/useCurrentUser";
import
{
Webhook
}
from
"@/types/proto/api/v1/webhook_service"
;
import
{
Webhook
}
from
"@/types/proto/api/v1/webhook_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
showCreateWebhookDialog
from
"../CreateWebhookDialog"
;
import
showCreateWebhookDialog
from
"../CreateWebhookDialog"
;
import
Icon
from
"../Icon"
;
const
listWebhooks
=
async
(
userId
:
number
)
=>
{
const
listWebhooks
=
async
(
userId
:
number
)
=>
{
const
{
webhooks
}
=
await
webhookServiceClient
.
listWebhooks
({
const
{
webhooks
}
=
await
webhookServiceClient
.
listWebhooks
({
...
@@ -88,7 +88,7 @@ const WebhookSection = () => {
...
@@ -88,7 +88,7 @@ const WebhookSection = () => {
handleDeleteWebhook
(
webhook
);
handleDeleteWebhook
(
webhook
);
}
}
}
}
>
>
<
Icon
.
Trash
className=
"w-4 h-auto"
/>
<
TrashIcon
className=
"w-4 h-auto"
/>
</
IconButton
>
</
IconButton
>
</
td
>
</
td
>
</
tr
>
</
tr
>
...
@@ -113,7 +113,7 @@ const WebhookSection = () => {
...
@@ -113,7 +113,7 @@ const WebhookSection = () => {
target=
"_blank"
target=
"_blank"
>
>
{
t
(
"common.learn-more"
)
}
{
t
(
"common.learn-more"
)
}
<
Icon
.
ExternalLink
className=
"inline w-4 h-auto ml-1"
/>
<
ExternalLinkIcon
className=
"inline w-4 h-auto ml-1"
/>
</
Link
>
</
Link
>
</
div
>
</
div
>
</
div
>
</
div
>
...
...
web/src/components/Settings/WorkspaceSection.tsx
View file @
2dbf92f7
import
{
Button
,
Select
,
Textarea
,
Option
,
Divider
}
from
"@mui/joy"
;
import
{
Button
,
Select
,
Textarea
,
Option
,
Divider
}
from
"@mui/joy"
;
import
{
ExternalLinkIcon
}
from
"lucide-react"
;
import
{
useState
}
from
"react"
;
import
{
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
Link
}
from
"react-router-dom"
;
import
{
Link
}
from
"react-router-dom"
;
...
@@ -7,7 +8,6 @@ import { workspaceSettingNamePrefix, useWorkspaceSettingStore } from "@/store/v1
...
@@ -7,7 +8,6 @@ import { workspaceSettingNamePrefix, useWorkspaceSettingStore } from "@/store/v1
import
{
WorkspaceGeneralSetting
}
from
"@/types/proto/api/v1/workspace_setting_service"
;
import
{
WorkspaceGeneralSetting
}
from
"@/types/proto/api/v1/workspace_setting_service"
;
import
{
WorkspaceSettingKey
}
from
"@/types/proto/store/workspace_setting"
;
import
{
WorkspaceSettingKey
}
from
"@/types/proto/store/workspace_setting"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Icon
from
"../Icon"
;
import
showUpdateCustomizedProfileDialog
from
"../UpdateCustomizedProfileDialog"
;
import
showUpdateCustomizedProfileDialog
from
"../UpdateCustomizedProfileDialog"
;
const
WorkspaceSection
=
()
=>
{
const
WorkspaceSection
=
()
=>
{
...
@@ -101,7 +101,7 @@ const WorkspaceSection = () => {
...
@@ -101,7 +101,7 @@ const WorkspaceSection = () => {
target=
"_blank"
target=
"_blank"
>
>
{
t
(
"common.learn-more"
)
}
{
t
(
"common.learn-more"
)
}
<
Icon
.
ExternalLink
className=
"inline w-4 h-auto ml-1"
/>
<
ExternalLinkIcon
className=
"inline w-4 h-auto ml-1"
/>
</
Link
>
</
Link
>
</
div
>
</
div
>
<
div
className=
"w-full flex flex-row justify-between items-center"
>
<
div
className=
"w-full flex flex-row justify-between items-center"
>
...
...
web/src/components/TagTree.tsx
View file @
2dbf92f7
import
{
ChevronRightIcon
,
HashIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
useToggle
from
"react-use/lib/useToggle"
;
import
useToggle
from
"react-use/lib/useToggle"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
{
useMemoFilterStore
}
from
"@/store/v1"
;
import
Icon
from
"./Icon"
;
interface
Tag
{
interface
Tag
{
key
:
string
;
key
:
string
;
...
@@ -108,7 +108,7 @@ const TagItemContainer: React.FC<TagItemContainerProps> = (props: TagItemContain
...
@@ -108,7 +108,7 @@ const TagItemContainer: React.FC<TagItemContainerProps> = (props: TagItemContain
}`
}
}`
}
>
>
<
div
className=
"shrink-0"
>
<
div
className=
"shrink-0"
>
<
Icon
.
Hash
className=
"w-4 h-auto shrink-0 mr-1 text-gray-400 dark:text-gray-500"
/>
<
HashIcon
className=
"w-4 h-auto shrink-0 mr-1 text-gray-400 dark:text-gray-500"
/>
</
div
>
</
div
>
<
span
className=
"truncate cursor-pointer hover:opacity-80"
onClick=
{
handleTagClick
}
>
<
span
className=
"truncate cursor-pointer hover:opacity-80"
onClick=
{
handleTagClick
}
>
{
tag
.
key
}
{
tag
.
key
}
...
@@ -120,7 +120,7 @@ const TagItemContainer: React.FC<TagItemContainerProps> = (props: TagItemContain
...
@@ -120,7 +120,7 @@ const TagItemContainer: React.FC<TagItemContainerProps> = (props: TagItemContain
className=
{
`flex flex-row justify-center items-center w-6 h-6 shrink-0 transition-all rotate-0 ${showSubTags && "rotate-90"}`
}
className=
{
`flex flex-row justify-center items-center w-6 h-6 shrink-0 transition-all rotate-0 ${showSubTags && "rotate-90"}`
}
onClick=
{
handleToggleBtnClick
}
onClick=
{
handleToggleBtnClick
}
>
>
<
Icon
.
ChevronRight
className=
"w-5 h-5 cursor-pointer text-gray-400 dark:text-gray-500"
/>
<
ChevronRightIcon
className=
"w-5 h-5 cursor-pointer text-gray-400 dark:text-gray-500"
/>
</
span
>
</
span
>
)
:
null
}
)
:
null
}
</
div
>
</
div
>
...
...
web/src/components/UpdateAccountDialog.tsx
View file @
2dbf92f7
import
{
Button
,
IconButton
,
Input
,
Textarea
}
from
"@mui/joy"
;
import
{
Button
,
IconButton
,
Input
,
Textarea
}
from
"@mui/joy"
;
import
{
isEqual
}
from
"lodash-es"
;
import
{
isEqual
}
from
"lodash-es"
;
import
{
XIcon
}
from
"lucide-react"
;
import
{
useState
}
from
"react"
;
import
{
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
convertFileToBase64
}
from
"@/helpers/utils"
;
import
{
convertFileToBase64
}
from
"@/helpers/utils"
;
...
@@ -8,7 +9,6 @@ import { userNamePrefix, useUserStore } from "@/store/v1";
...
@@ -8,7 +9,6 @@ import { userNamePrefix, useUserStore } from "@/store/v1";
import
{
User
as
UserPb
}
from
"@/types/proto/api/v1/user_service"
;
import
{
User
as
UserPb
}
from
"@/types/proto/api/v1/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
Icon
from
"./Icon"
;
import
UserAvatar
from
"./UserAvatar"
;
import
UserAvatar
from
"./UserAvatar"
;
type
Props
=
DialogProps
;
type
Props
=
DialogProps
;
...
@@ -143,7 +143,7 @@ const UpdateAccountDialog: React.FC<Props> = ({ destroy }: Props) => {
...
@@ -143,7 +143,7 @@ const UpdateAccountDialog: React.FC<Props> = ({ destroy }: Props) => {
<
div
className=
"dialog-header-container !w-64"
>
<
div
className=
"dialog-header-container !w-64"
>
<
p
className=
"title-text"
>
{
t
(
"setting.account-section.update-information"
)
}
</
p
>
<
p
className=
"title-text"
>
{
t
(
"setting.account-section.update-information"
)
}
</
p
>
<
IconButton
size=
"sm"
onClick=
{
handleCloseBtnClick
}
>
<
IconButton
size=
"sm"
onClick=
{
handleCloseBtnClick
}
>
<
Icon
.
X
className=
"w-5 h-auto"
/>
<
XIcon
className=
"w-5 h-auto"
/>
</
IconButton
>
</
IconButton
>
</
div
>
</
div
>
<
div
className=
"dialog-content-container space-y-2"
>
<
div
className=
"dialog-content-container space-y-2"
>
...
@@ -154,7 +154,7 @@ const UpdateAccountDialog: React.FC<Props> = ({ destroy }: Props) => {
...
@@ -154,7 +154,7 @@ const UpdateAccountDialog: React.FC<Props> = ({ destroy }: Props) => {
<
input
type=
"file"
accept=
"image/*"
className=
"absolute invisible w-full h-full inset-0"
onChange=
{
handleAvatarChanged
}
/>
<
input
type=
"file"
accept=
"image/*"
className=
"absolute invisible w-full h-full inset-0"
onChange=
{
handleAvatarChanged
}
/>
</
label
>
</
label
>
{
state
.
avatarUrl
&&
(
{
state
.
avatarUrl
&&
(
<
Icon
.
X
<
XIcon
className=
"w-4 h-auto ml-1 cursor-pointer opacity-60 hover:opacity-80"
className=
"w-4 h-auto ml-1 cursor-pointer opacity-60 hover:opacity-80"
onClick=
{
()
=>
onClick=
{
()
=>
setPartialState
({
setPartialState
({
...
...
web/src/components/UpdateCustomizedProfileDialog.tsx
View file @
2dbf92f7
import
{
Button
,
IconButton
,
Input
}
from
"@mui/joy"
;
import
{
Button
,
IconButton
,
Input
}
from
"@mui/joy"
;
import
Textarea
from
"@mui/joy/Textarea/Textarea"
;
import
Textarea
from
"@mui/joy/Textarea/Textarea"
;
import
{
XIcon
}
from
"lucide-react"
;
import
{
useState
}
from
"react"
;
import
{
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
workspaceSettingNamePrefix
,
useWorkspaceSettingStore
}
from
"@/store/v1"
;
import
{
workspaceSettingNamePrefix
,
useWorkspaceSettingStore
}
from
"@/store/v1"
;
...
@@ -8,7 +9,6 @@ import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
...
@@ -8,7 +9,6 @@ import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting";
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
AppearanceSelect
from
"./AppearanceSelect"
;
import
AppearanceSelect
from
"./AppearanceSelect"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
Icon
from
"./Icon"
;
import
LocaleSelect
from
"./LocaleSelect"
;
import
LocaleSelect
from
"./LocaleSelect"
;
type
Props
=
DialogProps
;
type
Props
=
DialogProps
;
...
@@ -103,7 +103,7 @@ const UpdateCustomizedProfileDialog: React.FC<Props> = ({ destroy }: Props) => {
...
@@ -103,7 +103,7 @@ const UpdateCustomizedProfileDialog: React.FC<Props> = ({ destroy }: Props) => {
<
div
className=
"dialog-header-container"
>
<
div
className=
"dialog-header-container"
>
<
p
className=
"title-text"
>
{
t
(
"setting.system-section.customize-server.title"
)
}
</
p
>
<
p
className=
"title-text"
>
{
t
(
"setting.system-section.customize-server.title"
)
}
</
p
>
<
IconButton
size=
"sm"
onClick=
{
handleCloseButtonClick
}
>
<
IconButton
size=
"sm"
onClick=
{
handleCloseButtonClick
}
>
<
Icon
.
X
className=
"w-5 h-auto"
/>
<
XIcon
className=
"w-5 h-auto"
/>
</
IconButton
>
</
IconButton
>
</
div
>
</
div
>
<
div
className=
"dialog-content-container min-w-[16rem]"
>
<
div
className=
"dialog-content-container min-w-[16rem]"
>
...
...
web/src/components/UserBanner.tsx
View file @
2dbf92f7
import
{
Dropdown
,
Menu
,
MenuButton
,
MenuItem
}
from
"@mui/joy"
;
import
{
Dropdown
,
Menu
,
MenuButton
,
MenuItem
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
{
LogOutIcon
,
SmileIcon
}
from
"lucide-react"
;
import
{
authServiceClient
}
from
"@/grpcweb"
;
import
{
authServiceClient
}
from
"@/grpcweb"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
{
Routes
}
from
"@/router"
;
import
{
Routes
}
from
"@/router"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
Icon
from
"./Icon"
;
import
UserAvatar
from
"./UserAvatar"
;
import
UserAvatar
from
"./UserAvatar"
;
interface
Props
{
interface
Props
{
...
@@ -41,11 +41,11 @@ const UserBanner = (props: Props) => {
...
@@ -41,11 +41,11 @@ const UserBanner = (props: Props) => {
</
MenuButton
>
</
MenuButton
>
<
Menu
placement=
"bottom-start"
style=
{
{
zIndex
:
"9999"
}
}
>
<
Menu
placement=
"bottom-start"
style=
{
{
zIndex
:
"9999"
}
}
>
<
MenuItem
onClick=
{
handleSignOut
}
>
<
MenuItem
onClick=
{
handleSignOut
}
>
<
Icon
.
LogOut
className=
"w-4 h-auto opacity-60"
/>
<
LogOutIcon
className=
"w-4 h-auto opacity-60"
/>
<
span
className=
"truncate"
>
{
t
(
"common.sign-out"
)
}
</
span
>
<
span
className=
"truncate"
>
{
t
(
"common.sign-out"
)
}
</
span
>
</
MenuItem
>
</
MenuItem
>
<
MenuItem
onClick=
{
()
=>
navigateTo
(
Routes
.
ABOUT
)
}
>
<
MenuItem
onClick=
{
()
=>
navigateTo
(
Routes
.
ABOUT
)
}
>
<
Icon
.
Smile
className=
"w-4 h-auto opacity-60"
/>
<
SmileIcon
className=
"w-4 h-auto opacity-60"
/>
<
span
className=
"truncate"
>
{
t
(
"common.about"
)
}
</
span
>
<
span
className=
"truncate"
>
{
t
(
"common.about"
)
}
</
span
>
</
MenuItem
>
</
MenuItem
>
</
Menu
>
</
Menu
>
...
...
web/src/components/UserStatisticsView.tsx
View file @
2dbf92f7
...
@@ -2,6 +2,7 @@ import { Divider, Tooltip } from "@mui/joy";
...
@@ -2,6 +2,7 @@ import { Divider, Tooltip } from "@mui/joy";
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
{
countBy
}
from
"lodash-es"
;
import
{
countBy
}
from
"lodash-es"
;
import
{
CalendarDaysIcon
,
CheckCircleIcon
,
Code2Icon
,
LinkIcon
,
ListTodoIcon
,
MoreVerticalIcon
,
RefreshCcwIcon
}
from
"lucide-react"
;
import
{
useState
}
from
"react"
;
import
{
useState
}
from
"react"
;
import
toast
from
"react-hot-toast"
;
import
toast
from
"react-hot-toast"
;
import
{
memoServiceClient
}
from
"@/grpcweb"
;
import
{
memoServiceClient
}
from
"@/grpcweb"
;
...
@@ -11,7 +12,6 @@ import i18n from "@/i18n";
...
@@ -11,7 +12,6 @@ import i18n from "@/i18n";
import
{
useMemoFilterStore
,
useMemoStore
}
from
"@/store/v1"
;
import
{
useMemoFilterStore
,
useMemoStore
}
from
"@/store/v1"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
ActivityCalendar
from
"./ActivityCalendar"
;
import
ActivityCalendar
from
"./ActivityCalendar"
;
import
Icon
from
"./Icon"
;
import
{
Popover
,
PopoverContent
,
PopoverTrigger
}
from
"./ui/Popover"
;
import
{
Popover
,
PopoverContent
,
PopoverTrigger
}
from
"./ui/Popover"
;
interface
UserMemoStats
{
interface
UserMemoStats
{
...
@@ -75,7 +75,7 @@ const UserStatisticsView = () => {
...
@@ -75,7 +75,7 @@ const UserStatisticsView = () => {
<
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=
"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"
>
<
div
className=
"w-full mb-1 flex flex-row justify-between items-center"
>
<
div
className=
"relative text-base font-medium leading-6 flex flex-row items-center dark:text-gray-400"
>
<
div
className=
"relative text-base font-medium leading-6 flex flex-row items-center dark:text-gray-400"
>
<
Icon
.
CalendarDays
className=
"w-5 h-auto mr-1 opacity-60"
strokeWidth=
{
1.5
}
/>
<
CalendarDaysIcon
className=
"w-5 h-auto mr-1 opacity-60"
strokeWidth=
{
1.5
}
/>
<
span
>
{
dayjs
(
monthString
).
toDate
().
toLocaleString
(
i18n
.
language
,
{
year
:
"numeric"
,
month
:
"long"
})
}
</
span
>
<
span
>
{
dayjs
(
monthString
).
toDate
().
toLocaleString
(
i18n
.
language
,
{
year
:
"numeric"
,
month
:
"long"
})
}
</
span
>
<
input
<
input
className=
"inset-0 absolute z-1 opacity-0"
className=
"inset-0 absolute z-1 opacity-0"
...
@@ -88,11 +88,11 @@ const UserStatisticsView = () => {
...
@@ -88,11 +88,11 @@ const UserStatisticsView = () => {
<
div
className=
"invisible group-hover:visible flex justify-end items-center"
>
<
div
className=
"invisible group-hover:visible flex justify-end items-center"
>
<
Popover
>
<
Popover
>
<
PopoverTrigger
>
<
PopoverTrigger
>
<
Icon
.
MoreVertical
className=
"w-4 h-auto shrink-0 opacity-60"
/>
<
MoreVerticalIcon
className=
"w-4 h-auto shrink-0 opacity-60"
/>
</
PopoverTrigger
>
</
PopoverTrigger
>
<
PopoverContent
align=
"end"
alignOffset=
{
-
12
}
>
<
PopoverContent
align=
"end"
alignOffset=
{
-
12
}
>
<
button
className=
"w-auto flex flex-row justify-between items-center gap-2 hover:opacity-80"
onClick=
{
rebuildMemoTags
}
>
<
button
className=
"w-auto flex flex-row justify-between items-center gap-2 hover:opacity-80"
onClick=
{
rebuildMemoTags
}
>
<
Icon
.
RefreshCcw
className=
"text-gray-400 w-4 h-auto cursor-pointer opacity-60"
/>
<
RefreshCcwIcon
className=
"text-gray-400 w-4 h-auto cursor-pointer opacity-60"
/>
<
span
className=
"text-sm shrink-0 text-gray-500 dark:text-gray-400"
>
Refresh
</
span
>
<
span
className=
"text-sm shrink-0 text-gray-500 dark:text-gray-400"
>
Refresh
</
span
>
</
button
>
</
button
>
</
PopoverContent
>
</
PopoverContent
>
...
@@ -114,7 +114,7 @@ const UserStatisticsView = () => {
...
@@ -114,7 +114,7 @@ const UserStatisticsView = () => {
onClick=
{
()
=>
memoFilterStore
.
addFilter
({
factor
:
"property.hasLink"
,
value
:
""
})
}
onClick=
{
()
=>
memoFilterStore
.
addFilter
({
factor
:
"property.hasLink"
,
value
:
""
})
}
>
>
<
div
className=
"w-auto flex justify-start items-center mr-1"
>
<
div
className=
"w-auto flex justify-start items-center mr-1"
>
<
Icon
.
Link
className=
"w-4 h-auto mr-1"
/>
<
LinkIcon
className=
"w-4 h-auto mr-1"
/>
<
span
className=
"block text-sm"
>
{
t
(
"memo.links"
)
}
</
span
>
<
span
className=
"block text-sm"
>
{
t
(
"memo.links"
)
}
</
span
>
</
div
>
</
div
>
<
span
className=
"text-sm truncate"
>
{
memoStats
.
link
}
</
span
>
<
span
className=
"text-sm truncate"
>
{
memoStats
.
link
}
</
span
>
...
@@ -124,11 +124,7 @@ const UserStatisticsView = () => {
...
@@ -124,11 +124,7 @@ const UserStatisticsView = () => {
onClick=
{
()
=>
memoFilterStore
.
addFilter
({
factor
:
"property.hasTaskList"
,
value
:
""
})
}
onClick=
{
()
=>
memoFilterStore
.
addFilter
({
factor
:
"property.hasTaskList"
,
value
:
""
})
}
>
>
<
div
className=
"w-auto flex justify-start items-center mr-1"
>
<
div
className=
"w-auto flex justify-start items-center mr-1"
>
{
memoStats
.
incompleteTasks
>
0
?
(
{
memoStats
.
incompleteTasks
>
0
?
<
ListTodoIcon
className=
"w-4 h-auto mr-1"
/>
:
<
CheckCircleIcon
className=
"w-4 h-auto mr-1"
/>
}
<
Icon
.
ListTodo
className=
"w-4 h-auto mr-1"
/>
)
:
(
<
Icon
.
CheckCircle
className=
"w-4 h-auto mr-1"
/>
)
}
<
span
className=
"block text-sm"
>
{
t
(
"memo.to-do"
)
}
</
span
>
<
span
className=
"block text-sm"
>
{
t
(
"memo.to-do"
)
}
</
span
>
</
div
>
</
div
>
{
memoStats
.
incompleteTasks
>
0
?
(
{
memoStats
.
incompleteTasks
>
0
?
(
...
@@ -148,7 +144,7 @@ const UserStatisticsView = () => {
...
@@ -148,7 +144,7 @@ const UserStatisticsView = () => {
onClick=
{
()
=>
memoFilterStore
.
addFilter
({
factor
:
"property.hasCode"
,
value
:
""
})
}
onClick=
{
()
=>
memoFilterStore
.
addFilter
({
factor
:
"property.hasCode"
,
value
:
""
})
}
>
>
<
div
className=
"w-auto flex justify-start items-center mr-1"
>
<
div
className=
"w-auto flex justify-start items-center mr-1"
>
<
Icon
.
Code2
className=
"w-4 h-auto mr-1"
/>
<
Code2Icon
className=
"w-4 h-auto mr-1"
/>
<
span
className=
"block text-sm"
>
{
t
(
"memo.code"
)
}
</
span
>
<
span
className=
"block text-sm"
>
{
t
(
"memo.code"
)
}
</
span
>
</
div
>
</
div
>
<
span
className=
"text-sm truncate"
>
{
memoStats
.
code
}
</
span
>
<
span
className=
"text-sm truncate"
>
{
memoStats
.
code
}
</
span
>
...
...
web/src/components/VisibilityIcon.tsx
View file @
2dbf92f7
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
{
Globe2Icon
,
LockIcon
,
UsersIcon
}
from
"lucide-react"
;
import
{
Visibility
}
from
"@/types/proto/api/v1/memo_service"
;
import
{
Visibility
}
from
"@/types/proto/api/v1/memo_service"
;
import
Icon
from
"./Icon"
;
interface
Props
{
interface
Props
{
visibility
:
Visibility
;
visibility
:
Visibility
;
...
@@ -11,11 +11,11 @@ const VisibilityIcon = (props: Props) => {
...
@@ -11,11 +11,11 @@ const VisibilityIcon = (props: Props) => {
let
VIcon
=
null
;
let
VIcon
=
null
;
if
(
visibility
===
Visibility
.
PRIVATE
)
{
if
(
visibility
===
Visibility
.
PRIVATE
)
{
VIcon
=
Icon
.
Lock
;
VIcon
=
LockIcon
;
}
else
if
(
visibility
===
Visibility
.
PROTECTED
)
{
}
else
if
(
visibility
===
Visibility
.
PROTECTED
)
{
VIcon
=
Icon
.
Users
;
VIcon
=
UsersIcon
;
}
else
if
(
visibility
===
Visibility
.
PUBLIC
)
{
}
else
if
(
visibility
===
Visibility
.
PUBLIC
)
{
VIcon
=
Icon
.
Globe2
;
VIcon
=
Globe2Icon
;
}
}
if
(
!
VIcon
)
{
if
(
!
VIcon
)
{
return
null
;
return
null
;
...
...
web/src/layouts/RootLayout.tsx
View file @
2dbf92f7
import
{
Button
,
IconButton
,
Tooltip
}
from
"@mui/joy"
;
import
{
Button
,
IconButton
,
Tooltip
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
{
ChevronLeftIcon
,
ChevronRightIcon
}
from
"lucide-react"
;
import
{
Suspense
,
useEffect
,
useState
}
from
"react"
;
import
{
Suspense
,
useEffect
,
useState
}
from
"react"
;
import
{
Outlet
,
useLocation
}
from
"react-router-dom"
;
import
{
Outlet
,
useLocation
}
from
"react-router-dom"
;
import
useLocalStorage
from
"react-use/lib/useLocalStorage"
;
import
useLocalStorage
from
"react-use/lib/useLocalStorage"
;
import
Icon
from
"@/components/Icon"
;
import
Navigation
from
"@/components/Navigation"
;
import
Navigation
from
"@/components/Navigation"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useResponsiveWidth
from
"@/hooks/useResponsiveWidth"
;
import
useResponsiveWidth
from
"@/hooks/useResponsiveWidth"
;
...
@@ -55,13 +55,13 @@ const RootLayout = () => {
...
@@ -55,13 +55,13 @@ const RootLayout = () => {
onClick=
{
()
=>
setCollapsed
(
!
collapsed
)
}
onClick=
{
()
=>
setCollapsed
(
!
collapsed
)
}
>
>
{
!
collapsed
?
(
{
!
collapsed
?
(
<
Button
variant=
"plain"
color=
"neutral"
startDecorator=
{
<
Icon
.
ChevronLeft
className=
"w-5 h-auto opacity-70"
/>
}
>
<
Button
variant=
"plain"
color=
"neutral"
startDecorator=
{
<
ChevronLeftIcon
className=
"w-5 h-auto opacity-70"
/>
}
>
{
t
(
"common.collapse"
)
}
{
t
(
"common.collapse"
)
}
</
Button
>
</
Button
>
)
:
(
)
:
(
<
Tooltip
title=
{
t
(
"common.expand"
)
}
placement=
"right"
arrow
>
<
Tooltip
title=
{
t
(
"common.expand"
)
}
placement=
"right"
arrow
>
<
IconButton
>
<
IconButton
>
<
Icon
.
ChevronRight
className=
"w-5 h-auto opacity-70"
/>
<
ChevronRightIcon
className=
"w-5 h-auto opacity-70"
/>
</
IconButton
>
</
IconButton
>
</
Tooltip
>
</
Tooltip
>
)
}
)
}
...
...
web/src/pages/About.tsx
View file @
2dbf92f7
import
{
Link
}
from
"@mui/joy"
;
import
{
Link
}
from
"@mui/joy"
;
import
Icon
from
"@/components/Icon
"
;
import
{
DotIcon
}
from
"lucide-react
"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
const
About
=
()
=>
{
const
About
=
()
=>
{
...
@@ -16,15 +16,15 @@ const About = () => {
...
@@ -16,15 +16,15 @@ const About = () => {
<
Link
underline=
"always"
href=
"https://www.github.com/usememos/memos"
target=
"_blank"
>
<
Link
underline=
"always"
href=
"https://www.github.com/usememos/memos"
target=
"_blank"
>
GitHub Repo
GitHub Repo
</
Link
>
</
Link
>
<
Icon
.
Dot
className=
"w-4 h-auto opacity-60"
/>
<
DotIcon
className=
"w-4 h-auto opacity-60"
/>
<
Link
underline=
"always"
href=
"https://www.usememos.com/"
target=
"_blank"
>
<
Link
underline=
"always"
href=
"https://www.usememos.com/"
target=
"_blank"
>
Official Website
Official Website
</
Link
>
</
Link
>
<
Icon
.
Dot
className=
"w-4 h-auto opacity-60"
/>
<
DotIcon
className=
"w-4 h-auto opacity-60"
/>
<
Link
underline=
"always"
href=
"https://www.usememos.com/blog"
target=
"_blank"
>
<
Link
underline=
"always"
href=
"https://www.usememos.com/blog"
target=
"_blank"
>
Blogs
Blogs
</
Link
>
</
Link
>
<
Icon
.
Dot
className=
"w-4 h-auto opacity-60"
/>
<
DotIcon
className=
"w-4 h-auto opacity-60"
/>
<
Link
underline=
"always"
href=
"https://www.usememos.com/docs"
target=
"_blank"
>
<
Link
underline=
"always"
href=
"https://www.usememos.com/docs"
target=
"_blank"
>
Documents
Documents
</
Link
>
</
Link
>
...
...
web/src/pages/Archived.tsx
View file @
2dbf92f7
import
{
Button
,
Tooltip
}
from
"@mui/joy"
;
import
{
Button
,
Tooltip
}
from
"@mui/joy"
;
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
{
ArchiveIcon
,
ArchiveRestoreIcon
,
ArrowDownIcon
,
TrashIcon
}
from
"lucide-react"
;
import
{
ClientError
}
from
"nice-grpc-web"
;
import
{
ClientError
}
from
"nice-grpc-web"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
toast
from
"react-hot-toast"
;
import
toast
from
"react-hot-toast"
;
import
Empty
from
"@/components/Empty"
;
import
Empty
from
"@/components/Empty"
;
import
Icon
from
"@/components/Icon"
;
import
MemoContent
from
"@/components/MemoContent"
;
import
MemoContent
from
"@/components/MemoContent"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
...
@@ -97,7 +97,7 @@ const Archived = () => {
...
@@ -97,7 +97,7 @@ const Archived = () => {
<
div
className=
"w-full flex flex-col justify-start items-start"
>
<
div
className=
"w-full flex flex-col justify-start items-start"
>
<
div
className=
"w-full flex flex-row justify-between items-center mb-2"
>
<
div
className=
"w-full flex flex-row justify-between items-center mb-2"
>
<
div
className=
"flex flex-row justify-start items-center gap-1"
>
<
div
className=
"flex flex-row justify-start items-center gap-1"
>
<
Icon
.
Archive
className=
"w-5 h-auto opacity-70 shrink-0"
/>
<
ArchiveIcon
className=
"w-5 h-auto opacity-70 shrink-0"
/>
<
span
>
{
t
(
"common.archived"
)
}
</
span
>
<
span
>
{
t
(
"common.archived"
)
}
</
span
>
</
div
>
</
div
>
<
div
className=
"w-44"
>
<
div
className=
"w-44"
>
...
@@ -119,12 +119,12 @@ const Archived = () => {
...
@@ -119,12 +119,12 @@ const Archived = () => {
<
div
className=
"flex flex-row justify-end items-center gap-x-2"
>
<
div
className=
"flex flex-row justify-end items-center gap-x-2"
>
<
Tooltip
title=
{
t
(
"common.restore"
)
}
placement=
"top"
>
<
Tooltip
title=
{
t
(
"common.restore"
)
}
placement=
"top"
>
<
button
onClick=
{
()
=>
handleRestoreMemoClick
(
memo
)
}
>
<
button
onClick=
{
()
=>
handleRestoreMemoClick
(
memo
)
}
>
<
Icon
.
ArchiveRestore
className=
"w-4 h-auto cursor-pointer text-gray-500 dark:text-gray-400"
/>
<
ArchiveRestoreIcon
className=
"w-4 h-auto cursor-pointer text-gray-500 dark:text-gray-400"
/>
</
button
>
</
button
>
</
Tooltip
>
</
Tooltip
>
<
Tooltip
title=
{
t
(
"common.delete"
)
}
placement=
"top"
>
<
Tooltip
title=
{
t
(
"common.delete"
)
}
placement=
"top"
>
<
button
onClick=
{
()
=>
handleDeleteMemoClick
(
memo
)
}
className=
"text-gray-500 dark:text-gray-400"
>
<
button
onClick=
{
()
=>
handleDeleteMemoClick
(
memo
)
}
className=
"text-gray-500 dark:text-gray-400"
>
<
Icon
.
Trash
className=
"w-4 h-auto cursor-pointer"
/>
<
TrashIcon
className=
"w-4 h-auto cursor-pointer"
/>
</
button
>
</
button
>
</
Tooltip
>
</
Tooltip
>
</
div
>
</
div
>
...
@@ -138,7 +138,7 @@ const Archived = () => {
...
@@ -138,7 +138,7 @@ const Archived = () => {
variant=
"plain"
variant=
"plain"
color=
"neutral"
color=
"neutral"
loading=
{
isRequesting
}
loading=
{
isRequesting
}
endDecorator=
{
<
Icon
.
ArrowDow
n
className=
"w-4 h-auto"
/>
}
endDecorator=
{
<
ArrowDownIco
n
className=
"w-4 h-auto"
/>
}
onClick=
{
()
=>
fetchMemos
(
nextPageToken
)
}
onClick=
{
()
=>
fetchMemos
(
nextPageToken
)
}
>
>
{
t
(
"memo.load-more"
)
}
{
t
(
"memo.load-more"
)
}
...
...
web/src/pages/AuthCallback.tsx
View file @
2dbf92f7
import
{
last
}
from
"lodash-es"
;
import
{
last
}
from
"lodash-es"
;
import
{
LoaderIcon
}
from
"lucide-react"
;
import
{
ClientError
}
from
"nice-grpc-web"
;
import
{
ClientError
}
from
"nice-grpc-web"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useSearchParams
}
from
"react-router-dom"
;
import
{
useSearchParams
}
from
"react-router-dom"
;
import
Icon
from
"@/components/Icon"
;
import
{
authServiceClient
}
from
"@/grpcweb"
;
import
{
authServiceClient
}
from
"@/grpcweb"
;
import
{
absolutifyLink
}
from
"@/helpers/utils"
;
import
{
absolutifyLink
}
from
"@/helpers/utils"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
...
@@ -70,7 +70,7 @@ const AuthCallback = () => {
...
@@ -70,7 +70,7 @@ const AuthCallback = () => {
return
(
return
(
<
div
className=
"p-4 py-24 w-full h-full flex justify-center items-center"
>
<
div
className=
"p-4 py-24 w-full h-full flex justify-center items-center"
>
{
state
.
loading
?
(
{
state
.
loading
?
(
<
Icon
.
Loader
className=
"animate-spin dark:text-gray-200"
/>
<
LoaderIcon
className=
"animate-spin dark:text-gray-200"
/>
)
:
(
)
:
(
<
div
className=
"max-w-lg font-mono whitespace-pre-wrap opacity-80"
>
{
state
.
errorMessage
}
</
div
>
<
div
className=
"max-w-lg font-mono whitespace-pre-wrap opacity-80"
>
{
state
.
errorMessage
}
</
div
>
)
}
)
}
...
...
web/src/pages/Explore.tsx
View file @
2dbf92f7
import
{
Button
}
from
"@mui/joy"
;
import
{
Button
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
{
ArrowDownIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
Empty
from
"@/components/Empty"
;
import
Empty
from
"@/components/Empty"
;
import
{
ExploreSidebar
,
ExploreSidebarDrawer
}
from
"@/components/ExploreSidebar"
;
import
{
ExploreSidebar
,
ExploreSidebarDrawer
}
from
"@/components/ExploreSidebar"
;
import
Icon
from
"@/components/Icon"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MemoView
from
"@/components/MemoView"
;
import
MemoView
from
"@/components/MemoView"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
...
@@ -84,7 +84,7 @@ const Explore = () => {
...
@@ -84,7 +84,7 @@ const Explore = () => {
variant=
"plain"
variant=
"plain"
color=
"neutral"
color=
"neutral"
loading=
{
isRequesting
}
loading=
{
isRequesting
}
endDecorator=
{
<
Icon
.
ArrowDow
n
className=
"w-4 h-auto"
/>
}
endDecorator=
{
<
ArrowDownIco
n
className=
"w-4 h-auto"
/>
}
onClick=
{
()
=>
fetchMemos
(
nextPageToken
)
}
onClick=
{
()
=>
fetchMemos
(
nextPageToken
)
}
>
>
{
t
(
"memo.load-more"
)
}
{
t
(
"memo.load-more"
)
}
...
...
web/src/pages/Home.tsx
View file @
2dbf92f7
import
{
Button
}
from
"@mui/joy"
;
import
{
Button
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
{
ArrowDownIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
Empty
from
"@/components/Empty"
;
import
Empty
from
"@/components/Empty"
;
import
{
HomeSidebar
,
HomeSidebarDrawer
}
from
"@/components/HomeSidebar"
;
import
{
HomeSidebar
,
HomeSidebarDrawer
}
from
"@/components/HomeSidebar"
;
import
Icon
from
"@/components/Icon"
;
import
MemoEditor
from
"@/components/MemoEditor"
;
import
MemoEditor
from
"@/components/MemoEditor"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MemoView
from
"@/components/MemoView"
;
import
MemoView
from
"@/components/MemoView"
;
...
@@ -100,7 +100,7 @@ const Home = () => {
...
@@ -100,7 +100,7 @@ const Home = () => {
variant=
"plain"
variant=
"plain"
color=
"neutral"
color=
"neutral"
loading=
{
isRequesting
}
loading=
{
isRequesting
}
endDecorator=
{
<
Icon
.
ArrowDow
n
className=
"w-4 h-auto"
/>
}
endDecorator=
{
<
ArrowDownIco
n
className=
"w-4 h-auto"
/>
}
onClick=
{
()
=>
fetchMemos
(
nextPageToken
)
}
onClick=
{
()
=>
fetchMemos
(
nextPageToken
)
}
>
>
{
t
(
"memo.load-more"
)
}
{
t
(
"memo.load-more"
)
}
...
...
web/src/pages/Inboxes.tsx
View file @
2dbf92f7
import
{
BellIcon
}
from
"lucide-react"
;
import
{
useEffect
}
from
"react"
;
import
{
useEffect
}
from
"react"
;
import
Empty
from
"@/components/Empty"
;
import
Empty
from
"@/components/Empty"
;
import
Icon
from
"@/components/Icon"
;
import
MemoCommentMessage
from
"@/components/Inbox/MemoCommentMessage"
;
import
MemoCommentMessage
from
"@/components/Inbox/MemoCommentMessage"
;
import
VersionUpdateMessage
from
"@/components/Inbox/VersionUpdateMessage"
;
import
VersionUpdateMessage
from
"@/components/Inbox/VersionUpdateMessage"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
...
@@ -29,7 +29,7 @@ const Inboxes = () => {
...
@@ -29,7 +29,7 @@ const Inboxes = () => {
<
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=
"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
className=
"relative w-full flex flex-row justify-between items-center"
>
<
p
className=
"py-1 flex flex-row justify-start items-center select-none opacity-80"
>
<
p
className=
"py-1 flex flex-row justify-start items-center select-none opacity-80"
>
<
Icon
.
Bell
className=
"w-6 h-auto mr-1 opacity-80"
/>
<
BellIcon
className=
"w-6 h-auto mr-1 opacity-80"
/>
<
span
className=
"text-lg"
>
{
t
(
"common.inbox"
)
}
</
span
>
<
span
className=
"text-lg"
>
{
t
(
"common.inbox"
)
}
</
span
>
</
p
>
</
p
>
</
div
>
</
div
>
...
...
web/src/pages/Loading.tsx
View file @
2dbf92f7
import
Icon
from
"@/components/Icon
"
;
import
{
LoaderIcon
}
from
"lucide-react
"
;
function
Loading
()
{
function
Loading
()
{
return
(
return
(
<
div
className=
"fixed w-full h-full flex flex-row justify-center items-center"
>
<
div
className=
"fixed w-full h-full flex flex-row justify-center items-center"
>
<
div
className=
"w-80 max-w-full h-full py-4 flex flex-col justify-center items-center"
>
<
div
className=
"w-80 max-w-full h-full py-4 flex flex-col justify-center items-center"
>
<
Icon
.
Loader
className=
"animate-spin dark:text-gray-200"
/>
<
LoaderIcon
className=
"animate-spin dark:text-gray-200"
/>
</
div
>
</
div
>
</
div
>
</
div
>
);
);
...
...
web/src/pages/MemoDetail.tsx
View file @
2dbf92f7
import
{
Button
}
from
"@mui/joy"
;
import
{
Button
}
from
"@mui/joy"
;
import
clsx
from
"clsx"
;
import
clsx
from
"clsx"
;
import
{
ArrowUpLeftFromCircleIcon
,
MessageCircleIcon
}
from
"lucide-react"
;
import
{
ClientError
}
from
"nice-grpc-web"
;
import
{
ClientError
}
from
"nice-grpc-web"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
Link
,
useParams
}
from
"react-router-dom"
;
import
{
Link
,
useParams
}
from
"react-router-dom"
;
import
Icon
from
"@/components/Icon"
;
import
{
MemoDetailSidebar
,
MemoDetailSidebarDrawer
}
from
"@/components/MemoDetailSidebar"
;
import
{
MemoDetailSidebar
,
MemoDetailSidebarDrawer
}
from
"@/components/MemoDetailSidebar"
;
import
MemoEditor
from
"@/components/MemoEditor"
;
import
MemoEditor
from
"@/components/MemoEditor"
;
import
MemoView
from
"@/components/MemoView"
;
import
MemoView
from
"@/components/MemoView"
;
...
@@ -98,7 +98,7 @@ const MemoDetail = () => {
...
@@ -98,7 +98,7 @@ const MemoDetail = () => {
to=
{
`/m/${parentMemo.uid}`
}
to=
{
`/m/${parentMemo.uid}`
}
unstable_viewTransition
unstable_viewTransition
>
>
<
Icon
.
ArrowUpLeftFromCircle
className=
"w-4 h-auto shrink-0 opacity-60 mr-2"
/>
<
ArrowUpLeftFromCircleIcon
className=
"w-4 h-auto shrink-0 opacity-60 mr-2"
/>
<
span
className=
"truncate"
>
{
parentMemo
.
content
}
</
span
>
<
span
className=
"truncate"
>
{
parentMemo
.
content
}
</
span
>
</
Link
>
</
Link
>
</
div
>
</
div
>
...
@@ -123,7 +123,7 @@ const MemoDetail = () => {
...
@@ -123,7 +123,7 @@ const MemoDetail = () => {
<
Button
<
Button
variant=
"plain"
variant=
"plain"
color=
"neutral"
color=
"neutral"
endDecorator=
{
<
Icon
.
MessageCircle
className=
"w-5 h-auto text-gray-500"
/>
}
endDecorator=
{
<
MessageCircleIcon
className=
"w-5 h-auto text-gray-500"
/>
}
onClick=
{
handleShowCommentEditor
}
onClick=
{
handleShowCommentEditor
}
>
>
<
span
className=
"font-normal text-gray-500"
>
{
t
(
"memo.comment.write-a-comment"
)
}
</
span
>
<
span
className=
"font-normal text-gray-500"
>
{
t
(
"memo.comment.write-a-comment"
)
}
</
span
>
...
@@ -134,7 +134,7 @@ const MemoDetail = () => {
...
@@ -134,7 +134,7 @@ const MemoDetail = () => {
<>
<>
<
div
className=
"w-full flex flex-row justify-between items-center px-3 mb-2"
>
<
div
className=
"w-full flex flex-row justify-between items-center px-3 mb-2"
>
<
div
className=
"flex flex-row justify-start items-center"
>
<
div
className=
"flex flex-row justify-start items-center"
>
<
Icon
.
MessageCircle
className=
"w-5 h-auto text-gray-400 mr-1"
/>
<
MessageCircleIcon
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"
>
{
t
(
"memo.comment.self"
)
}
</
span
>
<
span
className=
"text-gray-400 text-sm ml-1"
>
(
{
comments
.
length
}
)
</
span
>
<
span
className=
"text-gray-400 text-sm ml-1"
>
(
{
comments
.
length
}
)
</
span
>
</
div
>
</
div
>
...
...
web/src/pages/Resources.tsx
View file @
2dbf92f7
import
{
Divider
,
IconButton
,
Input
,
Tooltip
}
from
"@mui/joy"
;
import
{
Divider
,
IconButton
,
Input
,
Tooltip
}
from
"@mui/joy"
;
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
{
includes
}
from
"lodash-es"
;
import
{
includes
}
from
"lodash-es"
;
import
{
PaperclipIcon
,
SearchIcon
,
TrashIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
Empty
from
"@/components/Empty"
;
import
Empty
from
"@/components/Empty"
;
import
Icon
from
"@/components/Icon"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
ResourceIcon
from
"@/components/ResourceIcon"
;
import
ResourceIcon
from
"@/components/ResourceIcon"
;
import
{
resourceServiceClient
}
from
"@/grpcweb"
;
import
{
resourceServiceClient
}
from
"@/grpcweb"
;
...
@@ -68,14 +68,14 @@ const Resources = () => {
...
@@ -68,14 +68,14 @@ const Resources = () => {
<
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=
"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
className=
"relative w-full flex flex-row justify-between items-center"
>
<
p
className=
"py-1 flex flex-row justify-start items-center select-none opacity-80"
>
<
p
className=
"py-1 flex flex-row justify-start items-center select-none opacity-80"
>
<
Icon
.
Paperclip
className=
"w-6 h-auto mr-1 opacity-80"
/>
<
PaperclipIcon
className=
"w-6 h-auto mr-1 opacity-80"
/>
<
span
className=
"text-lg"
>
{
t
(
"common.resources"
)
}
</
span
>
<
span
className=
"text-lg"
>
{
t
(
"common.resources"
)
}
</
span
>
</
p
>
</
p
>
<
div
>
<
div
>
<
Input
<
Input
className=
"max-w-[8rem]"
className=
"max-w-[8rem]"
placeholder=
{
t
(
"common.search"
)
}
placeholder=
{
t
(
"common.search"
)
}
startDecorator=
{
<
Icon
.
Search
className=
"w-4 h-auto"
/>
}
startDecorator=
{
<
SearchIcon
className=
"w-4 h-auto"
/>
}
value=
{
state
.
searchQuery
}
value=
{
state
.
searchQuery
}
onChange=
{
(
e
)
=>
setState
({
...
state
,
searchQuery
:
e
.
target
.
value
})
}
onChange=
{
(
e
)
=>
setState
({
...
state
,
searchQuery
:
e
.
target
.
value
})
}
/>
/>
...
@@ -133,7 +133,7 @@ const Resources = () => {
...
@@ -133,7 +133,7 @@ const Resources = () => {
<
span
className=
"text-gray-500 dark:text-gray-500 opacity-80"
>
(
{
unusedResources
.
length
}
)
</
span
>
<
span
className=
"text-gray-500 dark:text-gray-500 opacity-80"
>
(
{
unusedResources
.
length
}
)
</
span
>
<
Tooltip
title=
"Delete all"
placement=
"top"
>
<
Tooltip
title=
"Delete all"
placement=
"top"
>
<
IconButton
size=
"sm"
onClick=
{
handleDeleteUnusedResources
}
>
<
IconButton
size=
"sm"
onClick=
{
handleDeleteUnusedResources
}
>
<
Icon
.
Trash
className=
"w-4 h-auto opacity-60"
/>
<
TrashIcon
className=
"w-4 h-auto opacity-60"
/>
</
IconButton
>
</
IconButton
>
</
Tooltip
>
</
Tooltip
>
</
div
>
</
div
>
...
...
web/src/pages/Setting.tsx
View file @
2dbf92f7
import
{
Option
,
Select
}
from
"@mui/joy"
;
import
{
Option
,
Select
}
from
"@mui/joy"
;
import
{
Lucide
Icon
}
from
"lucide-react"
;
import
{
CogIcon
,
DatabaseIcon
,
KeyIcon
,
LibraryIcon
,
LucideIcon
,
Settings2Icon
,
UserIcon
,
Users
Icon
}
from
"lucide-react"
;
import
{
useCallback
,
useEffect
,
useMemo
,
useState
}
from
"react"
;
import
{
useCallback
,
useEffect
,
useMemo
,
useState
}
from
"react"
;
import
Icon
from
"@/components/Icon"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
MemberSection
from
"@/components/Settings/MemberSection"
;
import
MemberSection
from
"@/components/Settings/MemberSection"
;
import
MemoRelatedSettings
from
"@/components/Settings/MemoRelatedSettings"
;
import
MemoRelatedSettings
from
"@/components/Settings/MemoRelatedSettings"
;
...
@@ -27,13 +26,13 @@ interface State {
...
@@ -27,13 +26,13 @@ interface State {
const
BASIC_SECTIONS
:
SettingSection
[]
=
[
"my-account"
,
"preference"
];
const
BASIC_SECTIONS
:
SettingSection
[]
=
[
"my-account"
,
"preference"
];
const
ADMIN_SECTIONS
:
SettingSection
[]
=
[
"member"
,
"system"
,
"memo-related"
,
"storage"
,
"sso"
];
const
ADMIN_SECTIONS
:
SettingSection
[]
=
[
"member"
,
"system"
,
"memo-related"
,
"storage"
,
"sso"
];
const
SECTION_ICON_MAP
:
Record
<
SettingSection
,
LucideIcon
>
=
{
const
SECTION_ICON_MAP
:
Record
<
SettingSection
,
LucideIcon
>
=
{
"my-account"
:
Icon
.
User
,
"my-account"
:
UserIcon
,
preference
:
Icon
.
Cog
,
preference
:
CogIcon
,
member
:
Icon
.
Users
,
member
:
UsersIcon
,
system
:
Icon
.
Settings2
,
system
:
Settings2Icon
,
"memo-related"
:
Icon
.
Library
,
"memo-related"
:
LibraryIcon
,
storage
:
Icon
.
Database
,
storage
:
DatabaseIcon
,
sso
:
Icon
.
Key
,
sso
:
KeyIcon
,
};
};
const
Setting
=
()
=>
{
const
Setting
=
()
=>
{
...
...
web/src/pages/UserProfile.tsx
View file @
2dbf92f7
import
{
Button
}
from
"@mui/joy"
;
import
{
Button
}
from
"@mui/joy"
;
import
copy
from
"copy-to-clipboard"
;
import
copy
from
"copy-to-clipboard"
;
import
dayjs
from
"dayjs"
;
import
dayjs
from
"dayjs"
;
import
{
ArrowDownIcon
,
ExternalLinkIcon
}
from
"lucide-react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
useParams
}
from
"react-router-dom"
;
import
{
useParams
}
from
"react-router-dom"
;
import
Empty
from
"@/components/Empty"
;
import
Empty
from
"@/components/Empty"
;
import
Icon
from
"@/components/Icon"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MemoFilters
from
"@/components/MemoFilters"
;
import
MemoView
from
"@/components/MemoView"
;
import
MemoView
from
"@/components/MemoView"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
...
@@ -113,7 +113,7 @@ const UserProfile = () => {
...
@@ -113,7 +113,7 @@ const UserProfile = () => {
<
Button
<
Button
color=
"neutral"
color=
"neutral"
variant=
"outlined"
variant=
"outlined"
endDecorator=
{
<
Icon
.
ExternalLink
className=
"w-4 h-auto opacity-60"
/>
}
endDecorator=
{
<
ExternalLinkIcon
className=
"w-4 h-auto opacity-60"
/>
}
onClick=
{
handleCopyProfileLink
}
onClick=
{
handleCopyProfileLink
}
>
>
{
t
(
"common.share"
)
}
{
t
(
"common.share"
)
}
...
@@ -140,7 +140,7 @@ const UserProfile = () => {
...
@@ -140,7 +140,7 @@ const UserProfile = () => {
variant=
"plain"
variant=
"plain"
color=
"neutral"
color=
"neutral"
loading=
{
isRequesting
}
loading=
{
isRequesting
}
endDecorator=
{
<
Icon
.
ArrowDow
n
className=
"w-4 h-auto"
/>
}
endDecorator=
{
<
ArrowDownIco
n
className=
"w-4 h-auto"
/>
}
onClick=
{
()
=>
fetchMemos
(
nextPageToken
)
}
onClick=
{
()
=>
fetchMemos
(
nextPageToken
)
}
>
>
{
t
(
"memo.load-more"
)
}
{
t
(
"memo.load-more"
)
}
...
...
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