chore: update navigation

This commit is contained in:
Johnny
2025-02-25 23:13:48 +08:00
parent 3a7b24bd01
commit 8e4e745ba9
11 changed files with 82 additions and 53 deletions

View File

@@ -84,7 +84,7 @@ const ActivityCalendar = (props: Props) => {
const isToday = dayjs().format("YYYY-MM-DD") === date;
const tooltipText =
count === 0
? t("memo.no-memos")
? date
: t("memo.count-memos-in-date", {
count: count,
memos: count === 1 ? t("common.memo") : t("common.memos"),

View File

@@ -1,22 +1,55 @@
import { Globe2Icon, HomeIcon, LogInIcon } from "lucide-react";
import { NavLink } from "react-router-dom";
import useDebounce from "react-use/lib/useDebounce";
import SearchBar from "@/components/SearchBar";
import useCurrentUser from "@/hooks/useCurrentUser";
import { Routes } from "@/router";
import { useMemoList, useUserStatsStore } from "@/store/v1";
import { cn } from "@/utils";
import { useTranslate } from "@/utils/i18n";
import MemoFilters from "../MemoFilters";
import StatisticsView from "../StatisticsView";
import ShortcutsSection from "./ShortcutsSection";
import TagsSection from "./TagsSection";
interface NavLinkItem {
id: string;
path: string;
title: string;
icon: React.ReactNode;
}
interface Props {
className?: string;
}
const HomeSidebar = (props: Props) => {
const t = useTranslate();
const currentUser = useCurrentUser();
const memoList = useMemoList();
const userStatsStore = useUserStatsStore();
const homeNavLink: NavLinkItem = {
id: "header-home",
path: Routes.ROOT,
title: t("common.home"),
icon: <HomeIcon className="w-4 h-auto opacity-70 shrink-0" />,
};
const exploreNavLink: NavLinkItem = {
id: "header-explore",
path: Routes.EXPLORE,
title: t("common.explore"),
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];
useDebounce(
async () => {
await userStatsStore.listUserStats(currentUser.name);
@@ -26,12 +59,32 @@ const HomeSidebar = (props: Props) => {
);
return (
<aside className={cn("relative w-full h-full overflow-auto hide-scrollbar flex flex-col justify-start items-start", props.className)}>
<aside className={cn("relative w-full h-full overflow-auto flex flex-col justify-start items-start", props.className)}>
<SearchBar />
<div className="mt-2 w-full space-y-1">
{navLinks.map((navLink) => (
<NavLink
key={navLink.id}
className={({ isActive }) =>
cn(
"w-full px-2 rounded-xl border flex flex-row items-center text-sm text-zinc-600 dark:text-gray-400 hover:bg-white hover:border-gray-200 dark:hover:border-zinc-700 dark:hover:bg-zinc-800",
isActive ? "bg-white drop-shadow-sm dark:bg-zinc-800 border-gray-200 dark:border-zinc-700" : "border-transparent",
)
}
to={navLink.path}
viewTransition
>
{navLink.icon}
<span className="ml-2 truncate leading-8">{navLink.title}</span>
</NavLink>
))}
</div>
<MemoFilters />
<div className="px-2 w-full">
<StatisticsView />
{currentUser && <ShortcutsSection />}
<TagsSection />
</div>
</aside>
);
};

View File

@@ -27,8 +27,8 @@ const HomeSidebarDrawer = () => {
<SearchIcon className="w-5 h-auto dark:text-gray-400" />
</Button>
<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">
<HomeSidebar className="py-4" />
<div className="w-full h-full bg-zinc-100 dark:bg-zinc-900">
<HomeSidebar className="px-4 py-4" />
</div>
</Drawer>
</>

View File

@@ -72,7 +72,7 @@ const MemoFilters = () => {
}
return (
<div className="w-full mt-3 flex flex-row justify-start items-center flex-wrap gap-x-2 gap-y-1">
<div className="w-full mt-2 flex flex-row justify-start items-center flex-wrap gap-x-2 gap-y-1">
{filters.map((filter) => (
<div
key={getMemoFilterKey(filter)}

View File

@@ -1,5 +1,5 @@
import { Tooltip } from "@mui/joy";
import { ArchiveIcon, BellIcon, Globe2Icon, HomeIcon, LogInIcon, PaperclipIcon, SettingsIcon, SmileIcon, User2Icon } from "lucide-react";
import { ArchiveIcon, BellIcon, PaperclipIcon, SettingsIcon, SmileIcon } from "lucide-react";
import { observer } from "mobx-react-lite";
import { useEffect } from "react";
import { NavLink } from "react-router-dom";
@@ -37,30 +37,12 @@ const Navigation = observer((props: Props) => {
userStore.fetchInboxes();
}, []);
const homeNavLink: NavLinkItem = {
id: "header-home",
path: Routes.ROOT,
title: t("common.home"),
icon: <HomeIcon className="w-6 h-auto opacity-70 shrink-0" />,
};
const resourcesNavLink: NavLinkItem = {
id: "header-resources",
path: Routes.RESOURCES,
title: t("common.resources"),
icon: <PaperclipIcon className="w-6 h-auto opacity-70 shrink-0" />,
};
const exploreNavLink: NavLinkItem = {
id: "header-explore",
path: Routes.EXPLORE,
title: t("common.explore"),
icon: <Globe2Icon className="w-6 h-auto opacity-70 shrink-0" />,
};
const profileNavLink: NavLinkItem = {
id: "header-profile",
path: user ? `/u/${encodeURIComponent(user.username)}` : "",
title: t("common.profile"),
icon: <User2Icon className="w-6 h-auto opacity-70 shrink-0" />,
};
const inboxNavLink: NavLinkItem = {
id: "header-inbox",
path: Routes.INBOX,
@@ -86,12 +68,6 @@ const Navigation = observer((props: Props) => {
title: t("common.settings"),
icon: <SettingsIcon className="w-6 h-auto opacity-70 shrink-0" />,
};
const signInNavLink: NavLinkItem = {
id: "header-auth",
path: Routes.AUTH,
title: t("common.sign-in"),
icon: <LogInIcon className="w-6 h-auto opacity-70 shrink-0" />,
};
const aboutNavLink: NavLinkItem = {
id: "header-about",
path: Routes.ABOUT,
@@ -99,16 +75,14 @@ const Navigation = observer((props: Props) => {
icon: <SmileIcon className="w-6 h-auto opacity-70 shrink-0" />,
};
const navLinks: NavLinkItem[] = user
? [homeNavLink, resourcesNavLink, exploreNavLink, profileNavLink, inboxNavLink, archivedNavLink, settingNavLink]
: [exploreNavLink, signInNavLink, aboutNavLink];
const navLinks: NavLinkItem[] = user ? [resourcesNavLink, inboxNavLink, archivedNavLink, settingNavLink] : [aboutNavLink];
return (
<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)}
>
<UserBanner collapsed={collapsed} />
<div className="w-full px-1 py-2 flex flex-col justify-start items-start shrink-0 space-y-2">
<div className="w-full mt-2 px-1 py-2 flex flex-col justify-start items-start shrink-0 space-y-2">
{navLinks.map((navLink) => (
<NavLink
className={({ isActive }) =>

View File

@@ -27,7 +27,7 @@ const NavigationDrawer = () => {
<MenuIcon className="w-5 h-auto dark:text-gray-400" />
</Button>
<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-2 bg-zinc-100 dark:bg-zinc-900">
<Navigation />
</div>
</Drawer>

View File

@@ -31,15 +31,15 @@ const SearchBar = () => {
return (
<div className="relative w-full h-auto flex flex-row justify-start items-center">
<SearchIcon className="absolute left-3 w-4 h-auto opacity-40" />
<SearchIcon className="absolute left-2 w-4 h-auto opacity-40" />
<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 leading-6 dark:text-gray-400 bg-zinc-50 dark:bg-zinc-900 border dark:border-zinc-800 text-sm rounded-xl p-1 pl-8 outline-none"
placeholder={t("memo.search-placeholder")}
value={queryText}
onChange={onTextChange}
onKeyDown={onKeyDown}
/>
<MemoDisplaySettingMenu className="absolute right-3 top-3" />
<MemoDisplaySettingMenu className="absolute right-2 top-2.5" />
</div>
);
};

View File

@@ -60,7 +60,7 @@ const StatisticsView = () => {
showMonthYearPicker
showFullMonthYearPicker
customInput={
<span className="cursor-pointer text-base md:text-lg hover:text-gray-600 dark:hover:text-gray-300">
<span className="cursor-pointer text-base hover:text-gray-600 dark:hover:text-gray-300">
{dayjs(visibleMonthString).toDate().toLocaleString(i18n.language, { year: "numeric", month: "long" })}
</span>
}

View File

@@ -1,5 +1,5 @@
import { Dropdown, Menu, MenuButton, MenuItem } from "@mui/joy";
import { LogOutIcon, SmileIcon } from "lucide-react";
import { LogOutIcon, SmileIcon, User2Icon } from "lucide-react";
import { authServiceClient } from "@/grpcweb";
import useCurrentUser from "@/hooks/useCurrentUser";
import useNavigateTo from "@/hooks/useNavigateTo";
@@ -17,10 +17,10 @@ const UserBanner = (props: Props) => {
const { collapsed } = props;
const t = useTranslate();
const navigateTo = useNavigateTo();
const user = useCurrentUser();
const currentUser = useCurrentUser();
const workspaceGeneralSetting = workspaceStore.state.generalSetting;
const title = (user ? user.nickname || user.username : workspaceGeneralSetting.customProfile?.title) || "Memos";
const avatarUrl = (user ? user.avatarUrl : workspaceGeneralSetting.customProfile?.logoUrl) || "/full-logo.webp";
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 () => {
await authServiceClient.signOut({});
@@ -30,10 +30,10 @@ const UserBanner = (props: Props) => {
return (
<div className="relative w-full h-auto px-1 shrink-0">
<Dropdown>
<MenuButton disabled={!user} slots={{ root: "div" }}>
<MenuButton disabled={!currentUser} slots={{ root: "div" }}>
<div
className={cn(
"py-1 w-auto flex flex-row justify-start items-center cursor-pointer text-gray-800 dark:text-gray-400",
"w-auto flex flex-row justify-start items-center cursor-pointer text-gray-800 dark:text-gray-400",
collapsed ? "px-1" : "px-3",
)}
>
@@ -42,6 +42,10 @@ const UserBanner = (props: Props) => {
</div>
</MenuButton>
<Menu placement="bottom-start" style={{ zIndex: "9999" }}>
<MenuItem onClick={() => navigateTo(`/u/${encodeURIComponent(currentUser.username)}`)}>
<User2Icon className="w-4 h-auto opacity-60" />
<span className="truncate">{t("common.profile")}</span>
</MenuItem>
<MenuItem onClick={handleSignOut}>
<LogOutIcon className="w-4 h-auto opacity-60" />
<span className="truncate">{t("common.sign-out")}</span>

View File

@@ -21,10 +21,10 @@ const HomeLayout = observer(() => {
className={cn(
"sticky top-0 left-0 shrink-0 h-[100svh] transition-all",
"border-r border-gray-200 dark:border-zinc-800",
lg ? "px-5 w-72" : "px-4 w-56",
lg ? "w-72" : "w-56",
)}
>
<HomeSidebar className={cn("py-6")} />
<HomeSidebar className={cn("px-3 py-6")} />
</div>
)}
<div className={cn("w-full mx-auto px-4 sm:px-6 sm:pt-3 md:pt-6 pb-8", md && "max-w-3xl")}>

View File

@@ -7,7 +7,6 @@ import { toast } from "react-hot-toast";
import { useParams } from "react-router-dom";
import MemoFilters from "@/components/MemoFilters";
import MemoView from "@/components/MemoView";
import MobileHeader from "@/components/MobileHeader";
import PagedMemoList from "@/components/PagedMemoList";
import UserAvatar from "@/components/UserAvatar";
import useLoading from "@/hooks/useLoading";
@@ -77,8 +76,7 @@ const UserProfile = () => {
};
return (
<section className="w-full max-w-5xl min-h-full flex flex-col justify-start items-center sm:pt-3 md:pt-6 pb-8">
<MobileHeader />
<section className="w-full max-w-5xl min-h-full flex flex-col justify-start items-center pb-8">
<div className="w-full px-4 sm:px-6 flex flex-col justify-start items-center">
{!loadingState.isLoading &&
(user ? (