diff --git a/src/client/App.tsx b/src/client/App.tsx
index 4049574..ef9055c 100644
--- a/src/client/App.tsx
+++ b/src/client/App.tsx
@@ -23,6 +23,7 @@ import { isDev } from './utils/env';
import { RouterProvider, createRouter } from '@tanstack/react-router';
import { routeTree } from './routeTree.gen';
import { DefaultNotFound } from './components/DefaultNotFound';
+import { TooltipProvider } from './components/ui/tooltip';
const router = createRouter({
routeTree,
@@ -95,7 +96,9 @@ export const App: React.FC = React.memo(() => {
{isDev ? (
// Compatible with old routes
-
+
+
+
) : (
diff --git a/src/client/pages/Layout/DesktopLayout.tsx b/src/client/pages/Layout/DesktopLayout.tsx
index 1d4b597..e8a24b7 100644
--- a/src/client/pages/Layout/DesktopLayout.tsx
+++ b/src/client/pages/Layout/DesktopLayout.tsx
@@ -22,6 +22,7 @@ import { Outlet } from '@tanstack/react-router';
import { trpc } from '@/api/trpc';
import { useUserStore } from '@/store/user';
import { LayoutProps } from './types';
+import { useTranslation } from '@i18next-toolkit/react';
const defaultLayout: [number, number, number] = [265, 440, 655];
@@ -45,6 +46,7 @@ export const DesktopLayout: React.FC = React.memo((props) => {
enabled: !!workspaceId,
}
);
+ const { t } = useTranslation();
const navbar = (
<>
@@ -61,31 +63,31 @@ export const DesktopLayout: React.FC = React.memo((props) => {
isCollapsed={isCollapsed}
links={[
{
- title: 'Website',
+ title: t('Website'),
label: String(serviceCount?.website ?? ''),
icon: LuAreaChart,
to: '/website',
},
{
- title: 'Monitor',
+ title: t('Monitor'),
label: String(serviceCount?.monitor ?? ''),
icon: LuMonitorDot,
to: '/monitor',
},
{
- title: 'Servers',
+ title: t('Servers'),
label: '',
icon: LuServer,
to: '/server',
},
{
- title: 'Telemetry',
+ title: t('Telemetry'),
label: String(serviceCount?.telemetry ?? ''),
icon: LuWifi,
to: '/telemetry',
},
{
- title: 'Pages',
+ title: t('Pages'),
label: String(serviceCount?.page ?? ''),
icon: LuFilePieChart,
to: '/page',
@@ -103,60 +105,57 @@ export const DesktopLayout: React.FC = React.memo((props) => {
);
return (
-
- {
- if (sizes.length === 3) {
- setLayout(sizes as typeof defaultLayout);
- } else if (sizes.length === 2) {
- const listSize = layout[1];
- const rest = 100 - sizes[0] - listSize;
- setLayout([sizes[0], listSize, rest]);
- }
+ {
+ if (sizes.length === 3) {
+ setLayout(sizes as typeof defaultLayout);
+ } else if (sizes.length === 2) {
+ const listSize = layout[1];
+ const rest = 100 - sizes[0] - listSize;
+ setLayout([sizes[0], listSize, rest]);
+ }
+ }}
+ className="h-full items-stretch"
+ >
+ {
+ setIsCollapsed(true);
}}
- className="h-full items-stretch"
- >
- {
- setIsCollapsed(true);
- }}
- onExpand={() => {
- setIsCollapsed(false);
- }}
- className={cn(
- 'flex flex-col',
- isCollapsed &&
- 'min-w-[50px] transition-all duration-300 ease-in-out'
- )}
- >
- {navbar}
-
-
- {props.list && (
- <>
-
-
- {props.list}
-
- >
+ onExpand={() => {
+ setIsCollapsed(false);
+ }}
+ className={cn(
+ 'flex flex-col',
+ isCollapsed && 'min-w-[50px] transition-all duration-300 ease-in-out'
)}
+ >
+ {navbar}
+
-
-
-
- {props.children ?? }
-
-
-
-
+ {props.list && (
+ <>
+
+
+ {props.list}
+
+ >
+ )}
+
+
+
+
+ {props.children ?? }
+
+
+
);
});
DesktopLayout.displayName = 'DesktopLayout';
diff --git a/src/client/pages/Layout/MobileLayout.tsx b/src/client/pages/Layout/MobileLayout.tsx
index 793e88f..faa64b3 100644
--- a/src/client/pages/Layout/MobileLayout.tsx
+++ b/src/client/pages/Layout/MobileLayout.tsx
@@ -1,6 +1,105 @@
import React from 'react';
+import {
+ LuAreaChart,
+ LuFilePieChart,
+ LuMenu,
+ LuMonitorDot,
+ LuServer,
+ LuWifi,
+} from 'react-icons/lu';
+import { useTranslation } from '@i18next-toolkit/react';
+import { IconType } from 'react-icons';
+import { useRouterState, Link, Outlet } from '@tanstack/react-router';
+import { cn } from '@/utils/style';
+import { Separator } from '@/components/ui/separator';
+import { LayoutProps } from './types';
+import { UserConfig } from './UserConfig';
+import { ScrollArea } from '@/components/ui/scroll-area';
+import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet';
+import { Button } from '@/components/ui/button';
-export const MobileLayout: React.FC = React.memo(() => {
- return Mobile
;
+export const MobileLayout: React.FC = React.memo((props) => {
+ const { t } = useTranslation();
+
+ return (
+
+
+
+
+
+
+
+ {props.list}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {props.children ?? }
+
+
+
+
+
+
+ );
});
MobileLayout.displayName = 'MobileLayout';
+
+const MobileNavItem: React.FC<{
+ title: string;
+ icon: IconType;
+ to: string;
+}> = React.memo((props) => {
+ const pathname = useRouterState({
+ select: (state) => state.location.pathname,
+ });
+
+ const isSelect = pathname.startsWith(props.to);
+
+ return (
+
+
+
+ {props.title}
+
+
+ );
+});
+MobileNavItem.displayName = 'MobileNavItem';
diff --git a/src/client/pages/Layout/UserConfig.tsx b/src/client/pages/Layout/UserConfig.tsx
index 3027581..89364c1 100644
--- a/src/client/pages/Layout/UserConfig.tsx
+++ b/src/client/pages/Layout/UserConfig.tsx
@@ -16,7 +16,7 @@ import {
} from '@/components/ui/dropdown-menu';
import { useEvent } from '@/hooks/useEvent';
import { useSettingsStore } from '@/store/settings';
-import { useUserInfo } from '@/store/user';
+import { useCurrentWorkspaceId, useUserInfo, useUserStore } from '@/store/user';
import { languages } from '@/utils/constants';
import { useTranslation, setLanguage } from '@i18next-toolkit/react';
import { useNavigate } from '@tanstack/react-router';
@@ -32,6 +32,20 @@ export const UserConfig: React.FC = React.memo((props) => {
const { i18n, t } = useTranslation();
const navigate = useNavigate();
const colorScheme = useSettingsStore((state) => state.colorScheme);
+ const workspaceId = useCurrentWorkspaceId();
+ const workspaces = useUserStore((state) => {
+ const userInfo = state.info;
+ if (userInfo) {
+ return userInfo.workspaces.map((w) => ({
+ id: w.workspace.id,
+ name: w.workspace.name,
+ role: w.role,
+ current: userInfo.currentWorkspace?.id === w.workspace.id,
+ }));
+ }
+
+ return [];
+ });
const handleChangeColorSchema = useEvent((colorScheme) => {
useSettingsStore.setState({
@@ -97,6 +111,25 @@ export const UserConfig: React.FC = React.memo((props) => {
{t('Notifications')}
+
+ {t('Workspaces')}
+
+
+
+ {workspaces.map((workspace) => (
+
+ {workspace.name}
+
+ ))}
+
+
+
+
+
{t('Language')}
diff --git a/src/client/pages/LayoutV2.tsx b/src/client/pages/LayoutV2.tsx
index 98b6b24..80601de 100644
--- a/src/client/pages/LayoutV2.tsx
+++ b/src/client/pages/LayoutV2.tsx
@@ -8,7 +8,7 @@ export const LayoutV2: React.FC = React.memo((props) => {
const isMobile = useIsMobile();
if (isMobile) {
- return ;
+ return ;
}
return ;