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
5d1075a6
Commit
5d1075a6
authored
Feb 26, 2025
by
Johnny
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: update home layout
parent
0da38598
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
79 additions
and
97 deletions
+79
-97
BrandBanner.tsx
web/src/components/BrandBanner.tsx
+34
-0
HomeSidebar.tsx
web/src/components/HomeSidebar/HomeSidebar.tsx
+2
-8
Navigation.tsx
web/src/components/Navigation.tsx
+17
-12
UserBanner.tsx
web/src/components/UserBanner.tsx
+13
-13
HomeLayout.tsx
web/src/layouts/HomeLayout.tsx
+13
-13
About.tsx
web/src/pages/About.tsx
+0
-41
index.tsx
web/src/router/index.tsx
+0
-10
No files found.
web/src/components/BrandBanner.tsx
0 → 100644
View file @
5d1075a6
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
{
Routes
}
from
"@/router"
;
import
{
workspaceStore
}
from
"@/store/v2"
;
import
{
cn
}
from
"@/utils"
;
import
UserAvatar
from
"./UserAvatar"
;
interface
Props
{
className
?:
string
;
collapsed
?:
boolean
;
}
const
BrandBanner
=
(
props
:
Props
)
=>
{
const
{
collapsed
}
=
props
;
const
navigateTo
=
useNavigateTo
();
const
currentUser
=
useCurrentUser
();
const
workspaceGeneralSetting
=
workspaceStore
.
state
.
generalSetting
;
const
title
=
workspaceGeneralSetting
.
customProfile
?.
title
||
"Memos"
;
const
avatarUrl
=
workspaceGeneralSetting
.
customProfile
?.
logoUrl
||
"/full-logo.webp"
;
return
(
<
div
className=
{
cn
(
"relative w-full h-auto shrink-0"
,
props
.
className
)
}
>
<
div
className=
{
cn
(
"w-auto flex flex-row justify-start items-center text-gray-800 dark:text-gray-400"
,
collapsed
?
"px-1"
:
"px-3"
)
}
onClick=
{
()
=>
navigateTo
(
currentUser
?
Routes
.
ROOT
:
Routes
.
EXPLORE
)
}
>
<
UserAvatar
className=
"shrink-0"
avatarUrl=
{
avatarUrl
}
/>
{
!
collapsed
&&
<
span
className=
"ml-2 text-lg font-medium text-slate-800 dark:text-gray-300 shrink truncate"
>
{
title
}
</
span
>
}
</
div
>
</
div
>
);
};
export
default
BrandBanner
;
web/src/components/HomeSidebar/HomeSidebar.tsx
View file @
5d1075a6
import
{
Globe2Icon
,
HomeIcon
,
LogInIcon
}
from
"lucide-react"
;
import
{
Globe2Icon
,
HomeIcon
}
from
"lucide-react"
;
import
{
NavLink
}
from
"react-router-dom"
;
import
{
NavLink
}
from
"react-router-dom"
;
import
useDebounce
from
"react-use/lib/useDebounce"
;
import
useDebounce
from
"react-use/lib/useDebounce"
;
import
SearchBar
from
"@/components/SearchBar"
;
import
SearchBar
from
"@/components/SearchBar"
;
...
@@ -41,14 +41,8 @@ const HomeSidebar = (props: Props) => {
...
@@ -41,14 +41,8 @@ const HomeSidebar = (props: Props) => {
title
:
t
(
"common.explore"
),
title
:
t
(
"common.explore"
),
icon
:
<
Globe2Icon
className=
"w-4 h-auto opacity-70 shrink-0"
/>,
icon
:
<
Globe2Icon
className=
"w-4 h-auto opacity-70 shrink-0"
/>,
};
};
const
signInNavLink
:
NavLinkItem
=
{
id
:
"header-auth"
,
path
:
Routes
.
AUTH
,
title
:
t
(
"common.sign-in"
),
icon
:
<
LogInIcon
className=
"w-4 h-auto opacity-70 shrink-0"
/>,
};
const
navLinks
:
NavLinkItem
[]
=
currentUser
?
[
homeNavLink
,
exploreNavLink
]
:
[
exploreNavLink
,
signInNavLink
];
const
navLinks
:
NavLinkItem
[]
=
currentUser
?
[
homeNavLink
,
exploreNavLink
]
:
[
exploreNavLink
];
useDebounce
(
useDebounce
(
async
()
=>
{
async
()
=>
{
...
...
web/src/components/Navigation.tsx
View file @
5d1075a6
import
{
Tooltip
}
from
"@mui/joy"
;
import
{
Tooltip
}
from
"@mui/joy"
;
import
{
ArchiveIcon
,
BellIcon
,
PaperclipIcon
,
SettingsIcon
,
Smi
leIcon
}
from
"lucide-react"
;
import
{
ArchiveIcon
,
BellIcon
,
PaperclipIcon
,
SettingsIcon
,
UserCirc
leIcon
}
from
"lucide-react"
;
import
{
observer
}
from
"mobx-react-lite"
;
import
{
observer
}
from
"mobx-react-lite"
;
import
{
useEffect
}
from
"react"
;
import
{
useEffect
}
from
"react"
;
import
{
NavLink
}
from
"react-router-dom"
;
import
{
NavLink
}
from
"react-router-dom"
;
...
@@ -9,6 +9,7 @@ import { userStore } from "@/store/v2";
...
@@ -9,6 +9,7 @@ import { userStore } from "@/store/v2";
import
{
Inbox_Status
}
from
"@/types/proto/api/v1/inbox_service"
;
import
{
Inbox_Status
}
from
"@/types/proto/api/v1/inbox_service"
;
import
{
cn
}
from
"@/utils"
;
import
{
cn
}
from
"@/utils"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
BrandBanner
from
"./BrandBanner"
;
import
UserBanner
from
"./UserBanner"
;
import
UserBanner
from
"./UserBanner"
;
interface
NavLinkItem
{
interface
NavLinkItem
{
...
@@ -26,11 +27,11 @@ interface Props {
...
@@ -26,11 +27,11 @@ interface Props {
const
Navigation
=
observer
((
props
:
Props
)
=>
{
const
Navigation
=
observer
((
props
:
Props
)
=>
{
const
{
collapsed
,
className
}
=
props
;
const
{
collapsed
,
className
}
=
props
;
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
u
ser
=
useCurrentUser
();
const
currentU
ser
=
useCurrentUser
();
const
hasUnreadInbox
=
userStore
.
state
.
inboxes
.
some
((
inbox
)
=>
inbox
.
status
===
Inbox_Status
.
UNREAD
);
const
hasUnreadInbox
=
userStore
.
state
.
inboxes
.
some
((
inbox
)
=>
inbox
.
status
===
Inbox_Status
.
UNREAD
);
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
!
u
ser
)
{
if
(
!
currentU
ser
)
{
return
;
return
;
}
}
...
@@ -68,21 +69,24 @@ const Navigation = observer((props: Props) => {
...
@@ -68,21 +69,24 @@ const Navigation = observer((props: Props) => {
title
:
t
(
"common.settings"
),
title
:
t
(
"common.settings"
),
icon
:
<
SettingsIcon
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
icon
:
<
SettingsIcon
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
};
};
const
about
NavLink
:
NavLinkItem
=
{
const
signIn
NavLink
:
NavLinkItem
=
{
id
:
"header-a
bout
"
,
id
:
"header-a
uth
"
,
path
:
Routes
.
A
BOUT
,
path
:
Routes
.
A
UTH
,
title
:
t
(
"common.
about
"
),
title
:
t
(
"common.
sign-in
"
),
icon
:
<
Smi
leIcon
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
icon
:
<
UserCirc
leIcon
className=
"w-6 h-auto opacity-70 shrink-0"
/>,
};
};
const
navLinks
:
NavLinkItem
[]
=
user
?
[
resourcesNavLink
,
inboxNavLink
,
archivedNavLink
,
settingNavLink
]
:
[
about
NavLink
];
const
navLinks
:
NavLinkItem
[]
=
currentUser
?
[
resourcesNavLink
,
inboxNavLink
,
archivedNavLink
,
settingNavLink
]
:
[
signIn
NavLink
];
return
(
return
(
<
header
<
header
className=
{
cn
(
"w-full h-full overflow-auto flex flex-col justify-start items-start py-4 md:pt-6 z-30 hide-scrollbar"
,
className
)
}
className=
{
cn
(
"w-full h-full overflow-auto flex flex-col justify-between items-start gap-4 py-4 md:pt-6 z-30 hide-scrollbar"
,
className
,
)
}
>
>
<
UserBanner
collapsed=
{
collapsed
}
/
>
<
div
className=
"w-full px-1 py-2 flex flex-col justify-start items-start space-y-2 overflow-auto hide-scrollbar shrink"
>
<
div
className=
"w-full mt-2 px-1 py-2 flex flex-col justify-start items-start shrink-0 space-y-2"
>
<
BrandBanner
className=
"mb-2"
collapsed=
{
collapsed
}
/
>
{
navLinks
.
map
((
navLink
)
=>
(
{
navLinks
.
map
((
navLink
)
=>
(
<
NavLink
<
NavLink
className=
{
({
isActive
})
=>
className=
{
({
isActive
})
=>
...
@@ -108,6 +112,7 @@ const Navigation = observer((props: Props) => {
...
@@ -108,6 +112,7 @@ const Navigation = observer((props: Props) => {
</
NavLink
>
</
NavLink
>
))
}
))
}
</
div
>
</
div
>
{
currentUser
&&
<
UserBanner
collapsed=
{
collapsed
}
/>
}
</
header
>
</
header
>
);
);
});
});
...
...
web/src/components/UserBanner.tsx
View file @
5d1075a6
import
{
Dropdown
,
Menu
,
MenuButton
,
MenuItem
}
from
"@mui/joy"
;
import
{
Dropdown
,
Menu
,
MenuButton
,
MenuItem
}
from
"@mui/joy"
;
import
{
LogOutIcon
,
SmileIcon
,
User2
Icon
}
from
"lucide-react"
;
import
{
LogOutIcon
,
User2Icon
,
Smile
Icon
}
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
{
workspaceStore
}
from
"@/store/v2"
;
import
{
cn
}
from
"@/utils"
;
import
{
cn
}
from
"@/utils"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
UserAvatar
from
"./UserAvatar"
;
import
UserAvatar
from
"./UserAvatar"
;
...
@@ -18,13 +17,10 @@ const UserBanner = (props: Props) => {
...
@@ -18,13 +17,10 @@ const UserBanner = (props: Props) => {
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
navigateTo
=
useNavigateTo
();
const
navigateTo
=
useNavigateTo
();
const
currentUser
=
useCurrentUser
();
const
currentUser
=
useCurrentUser
();
const
workspaceGeneralSetting
=
workspaceStore
.
state
.
generalSetting
;
const
title
=
(
currentUser
?
currentUser
.
nickname
||
currentUser
.
username
:
workspaceGeneralSetting
.
customProfile
?.
title
)
||
"Memos"
;
const
avatarUrl
=
(
currentUser
?
currentUser
.
avatarUrl
:
workspaceGeneralSetting
.
customProfile
?.
logoUrl
)
||
"/full-logo.webp"
;
const
handleSignOut
=
async
()
=>
{
const
handleSignOut
=
async
()
=>
{
await
authServiceClient
.
signOut
({});
await
authServiceClient
.
signOut
({});
window
.
location
.
href
=
"/auth"
;
window
.
location
.
href
=
Routes
.
AUTH
;
};
};
return
(
return
(
...
@@ -38,23 +34,27 @@ const UserBanner = (props: Props) => {
...
@@ -38,23 +34,27 @@ const UserBanner = (props: Props) => {
)
}
)
}
onClick=
{
()
=>
navigateTo
(
currentUser
?
Routes
.
ROOT
:
Routes
.
EXPLORE
)
}
onClick=
{
()
=>
navigateTo
(
currentUser
?
Routes
.
ROOT
:
Routes
.
EXPLORE
)
}
>
>
<
UserAvatar
className=
"shrink-0"
avatarUrl=
{
avatarUrl
}
/>
{
currentUser
.
avatarUrl
?
(
{
!
collapsed
&&
<
span
className=
"ml-2 text-lg font-medium text-slate-800 dark:text-gray-300 shrink truncate"
>
{
title
}
</
span
>
}
<
UserAvatar
className=
"shrink-0"
avatarUrl=
{
currentUser
.
avatarUrl
}
/>
)
:
(
<
User2Icon
className=
"w-6 mx-auto h-auto opacity-60"
/>
)
}
{
!
collapsed
&&
(
<
span
className=
"ml-2 text-lg font-medium text-slate-800 dark:text-gray-300 grow truncate"
>
{
currentUser
.
nickname
||
currentUser
.
username
}
</
span
>
)
}
</
div
>
</
div
>
</
MenuButton
>
</
MenuButton
>
<
Menu
placement=
"bottom-start"
style=
{
{
zIndex
:
"9999"
}
}
>
<
Menu
placement=
"bottom-start"
style=
{
{
zIndex
:
"9999"
}
}
>
<
MenuItem
onClick=
{
()
=>
navigateTo
(
`/u/${encodeURIComponent(currentUser.username)}`
)
}
>
<
MenuItem
onClick=
{
()
=>
navigateTo
(
`/u/${encodeURIComponent(currentUser.username)}`
)
}
>
<
User2
Icon
className=
"w-4 h-auto opacity-60"
/>
<
Smile
Icon
className=
"w-4 h-auto opacity-60"
/>
<
span
className=
"truncate"
>
{
t
(
"common.profile"
)
}
</
span
>
<
span
className=
"truncate"
>
{
t
(
"common.profile"
)
}
</
span
>
</
MenuItem
>
</
MenuItem
>
<
MenuItem
onClick=
{
handleSignOut
}
>
<
MenuItem
onClick=
{
handleSignOut
}
>
<
LogOutIcon
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
)
}
>
<
SmileIcon
className=
"w-4 h-auto opacity-60"
/>
<
span
className=
"truncate"
>
{
t
(
"common.about"
)
}
</
span
>
</
MenuItem
>
</
Menu
>
</
Menu
>
</
Dropdown
>
</
Dropdown
>
</
div
>
</
div
>
...
...
web/src/layouts/HomeLayout.tsx
View file @
5d1075a6
...
@@ -15,19 +15,19 @@ const HomeLayout = observer(() => {
...
@@ -15,19 +15,19 @@ const HomeLayout = observer(() => {
<
HomeSidebarDrawer
/>
<
HomeSidebarDrawer
/>
</
MobileHeader
>
</
MobileHeader
>
)
}
)
}
<
div
className=
{
cn
(
"w-full min-h-full flex flex-row justify-start items-start"
)
}
>
{
md
&&
(
{
md
&&
(
<
div
<
div
className=
{
cn
(
className=
{
cn
(
"fixed top-0 left-16 shrink-0 h-[100svh] transition-all"
,
"sticky top-0 left-0 shrink-0 h-[100svh] transition-all
"
,
"border-r border-gray-200 dark:border-zinc-800
"
,
"border-r border-gray-200 dark:border-zinc-800
"
,
lg
?
"w-72"
:
"w-56
"
,
lg
?
"w-72"
:
"w-56"
,
)
}
)
}
>
>
<
HomeSidebar
className=
{
cn
(
"px-3 py-6"
)
}
/
>
<
HomeSidebar
className=
{
cn
(
"px-3 py-6"
)
}
/
>
</
div
>
</
div
>
)
}
)
}
<
div
className=
{
cn
(
"w-full min-h-full"
,
lg
?
"pl-72"
:
md
?
"pl-56"
:
""
)
}
>
<
div
className=
{
cn
(
"w-full mx-auto px-4 sm:px-6
sm:pt-3
md:pt-6 pb-8"
,
md
&&
"max-w-3xl"
)
}
>
<
div
className=
{
cn
(
"w-full mx-auto px-4 sm:px-6 md:pt-6 pb-8"
,
md
&&
"max-w-3xl"
)
}
>
<
Outlet
/>
<
Outlet
/>
</
div
>
</
div
>
</
div
>
</
div
>
...
...
web/src/pages/About.tsx
deleted
100644 → 0
View file @
0da38598
import
{
Link
}
from
"@mui/joy"
;
import
{
DotIcon
}
from
"lucide-react"
;
import
MobileHeader
from
"@/components/MobileHeader"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
const
About
=
()
=>
{
const
t
=
useTranslate
();
return
(
<
section
className=
"@container w-full max-w-5xl min-h-full flex flex-col justify-start items-center sm:pt-3 md:pt-6 pb-8"
>
<
MobileHeader
/>
<
div
className=
"w-full px-4 sm:px-6"
>
<
div
className=
"w-full shadow flex flex-col justify-start items-start px-4 py-3 rounded-xl bg-white dark:bg-zinc-800 text-black dark:text-gray-300"
>
<
a
href=
"https://www.usememos.com"
target=
"_blank"
>
<
img
className=
"w-auto h-12"
src=
"https://www.usememos.com/full-logo-landscape.png"
alt=
"memos"
/>
</
a
>
<
p
className=
"text-base"
>
{
t
(
"about.description"
)
}
</
p
>
<
div
className=
"mt-1 flex flex-row items-center flex-wrap"
>
<
Link
underline=
"always"
href=
"https://www.github.com/usememos/memos"
target=
"_blank"
>
{
t
(
"about.github-repository"
)
}
</
Link
>
<
DotIcon
className=
"w-4 h-auto opacity-60"
/>
<
Link
underline=
"always"
href=
"https://www.usememos.com/"
target=
"_blank"
>
{
t
(
"about.official-website"
)
}
</
Link
>
<
DotIcon
className=
"w-4 h-auto opacity-60"
/>
<
Link
underline=
"always"
href=
"https://www.usememos.com/blog"
target=
"_blank"
>
{
t
(
"about.blogs"
)
}
</
Link
>
<
DotIcon
className=
"w-4 h-auto opacity-60"
/>
<
Link
underline=
"always"
href=
"https://www.usememos.com/docs"
target=
"_blank"
>
{
t
(
"about.documents"
)
}
</
Link
>
</
div
>
</
div
>
</
div
>
</
section
>
);
};
export
default
About
;
web/src/router/index.tsx
View file @
5d1075a6
...
@@ -6,7 +6,6 @@ import RootLayout from "@/layouts/RootLayout";
...
@@ -6,7 +6,6 @@ import RootLayout from "@/layouts/RootLayout";
import
Home
from
"@/pages/Home"
;
import
Home
from
"@/pages/Home"
;
import
Loading
from
"@/pages/Loading"
;
import
Loading
from
"@/pages/Loading"
;
const
About
=
lazy
(()
=>
import
(
"@/pages/About"
));
const
AdminSignIn
=
lazy
(()
=>
import
(
"@/pages/AdminSignIn"
));
const
AdminSignIn
=
lazy
(()
=>
import
(
"@/pages/AdminSignIn"
));
const
Archived
=
lazy
(()
=>
import
(
"@/pages/Archived"
));
const
Archived
=
lazy
(()
=>
import
(
"@/pages/Archived"
));
const
AuthCallback
=
lazy
(()
=>
import
(
"@/pages/AuthCallback"
));
const
AuthCallback
=
lazy
(()
=>
import
(
"@/pages/AuthCallback"
));
...
@@ -29,7 +28,6 @@ export enum Routes {
...
@@ -29,7 +28,6 @@ export enum Routes {
ARCHIVED
=
"/archived"
,
ARCHIVED
=
"/archived"
,
SETTING
=
"/setting"
,
SETTING
=
"/setting"
,
EXPLORE
=
"/explore"
,
EXPLORE
=
"/explore"
,
ABOUT
=
"/about"
,
AUTH
=
"/auth"
,
AUTH
=
"/auth"
,
}
}
...
@@ -144,14 +142,6 @@ const router = createBrowserRouter([
...
@@ -144,14 +142,6 @@ const router = createBrowserRouter([
</
Suspense
>
</
Suspense
>
),
),
},
},
{
path
:
Routes
.
ABOUT
,
element
:
(
<
Suspense
fallback=
{
<
Loading
/>
}
>
<
About
/>
</
Suspense
>
),
},
// Redirect old path to new path.
// Redirect old path to new path.
{
{
path
:
"m/:uid"
,
path
:
"m/:uid"
,
...
...
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