perf: improve mobile display

This commit is contained in:
moonrailgun 2024-05-12 17:02:03 +08:00
parent 6606b253d8
commit b2fb1832e1
11 changed files with 130 additions and 47 deletions

View File

@ -4,12 +4,22 @@ import { DateUnit } from '@tianji/shared';
import React from 'react';
import { formatDate, formatDateWithUnit } from '../utils/date';
import { Column, ColumnConfig } from '@ant-design/charts';
import { useIsMobile } from '@/hooks/useIsMobile';
import { useTranslation } from '@i18next-toolkit/react';
export const TimeEventChart: React.FC<{
labelMapping?: Record<string, string>;
data: { x: string; y: number; type: string }[];
unit: DateUnit;
}> = React.memo((props) => {
const { colors } = useTheme();
const isMobile = useIsMobile();
const { t } = useTranslation();
const labelMapping = props.labelMapping ?? {
pageview: t('pageview'),
session: t('session'),
};
const config = useMemo(
() =>
@ -30,6 +40,13 @@ export const TimeEventChart: React.FC<{
title: (t) => formatDate(t),
},
color: [colors.chart.pv, colors.chart.uv],
legend: isMobile
? false
: {
itemName: {
formatter: (text) => labelMapping[text] ?? text,
},
},
xAxis: {
label: {
autoHide: true,
@ -38,7 +55,7 @@ export const TimeEventChart: React.FC<{
},
},
}) satisfies ColumnConfig,
[props.data, props.unit]
[props.data, props.unit, props.labelMapping]
);
return <Column {...config} />;

View File

@ -177,7 +177,7 @@ export const MonitorInfo: React.FC<MonitorInfoProps> = React.memo((props) => {
<div className="h-full w-full overflow-auto">
<Spin spinning={isLoading}>
<Space className="w-full" direction="vertical">
<div className="flex justify-between">
<div className="flex flex-col-reverse sm:flex-row sm:justify-between">
<Space direction="vertical">
<div>
<ColorTag label={monitorInfo.type} />

View File

@ -11,7 +11,7 @@ export const MonitorStatsBlock: React.FC<MonitorStatsBlockProps> = React.memo(
(props) => {
return (
<div>
<div className="mb-0.5 font-bold">
<div className="mb-0.5 text-xs font-bold sm:text-base">
{props.title}
{props.tooltip && (
<TipIcon className="ml-1" content={props.tooltip} />

View File

@ -17,7 +17,7 @@ export const WebsiteOnlineCount: React.FC<{
if (typeof count === 'number' && count > 0) {
return (
<div className="flex items-center space-x-2">
<div className="h-2.5 w-2.5 rounded-full bg-green-500" />
<div className="h-2.5 w-2.5 flex-shrink-0 rounded-full bg-green-500" />
<span>
{count} {t('current visitor')}
</span>

View File

@ -83,8 +83,8 @@ export const WebsiteOverview: React.FC<{
return (
<Spin spinning={loading}>
<div className="flex">
<div className="flex flex-1 items-center text-2xl font-bold">
<div className="flex flex-col-reverse sm:flex-row">
<div className="flex flex-1 flex-col gap-2 text-2xl font-bold sm:flex-row sm:items-center">
<span className="mr-2" title={website.domain ?? ''}>
{website.name}
</span>
@ -102,7 +102,7 @@ export const WebsiteOverview: React.FC<{
</Link>
)}
<div className="ml-4 text-base font-normal">
<div className="text-base font-normal">
<WebsiteOnlineCount
workspaceId={website.workspaceId}
websiteId={website.id}

View File

@ -0,0 +1,34 @@
import React, { useState } from 'react';
import { Sheet, SheetContent, SheetTrigger } from '@/components/ui/sheet';
import { LuMenu } from 'react-icons/lu';
import { Button } from '@/components/ui/button';
import { ScrollArea } from '@/components/ui/scroll-area';
import { useGlobalEventSubscribe } from '@/utils/event';
export const MobileLayoutMenu: React.FC<{
list?: React.ReactNode;
}> = React.memo((props) => {
const [open, setOpen] = useState(false);
useGlobalEventSubscribe('commonListSelected', () => {
setOpen(false);
});
if (!props.list) {
return <div />;
}
return (
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger>
<Button variant="outline" size="icon">
<LuMenu />
</Button>
</SheetTrigger>
<SheetContent side="left" className="w-11/12">
<ScrollArea className="h-full">{props.list}</ScrollArea>
</SheetContent>
</Sheet>
);
});
MobileLayoutMenu.displayName = 'MobileLayoutMenu';

View File

@ -2,7 +2,6 @@ import React from 'react';
import {
LuAreaChart,
LuFilePieChart,
LuMenu,
LuMonitorDot,
LuMoreVertical,
LuServer,
@ -16,19 +15,8 @@ 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';
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from '@/components/ui/drawer';
import { Drawer, DrawerContent, DrawerTrigger } from '@/components/ui/drawer';
import { MobileLayoutMenu } from './Menu';
export const MobileLayout: React.FC<LayoutProps> = React.memo((props) => {
const { t } = useTranslation();
@ -36,20 +24,7 @@ export const MobileLayout: React.FC<LayoutProps> = React.memo((props) => {
return (
<div className="flex h-svh flex-col">
<div className="flex h-[52px] items-center justify-between px-2">
<Sheet>
<SheetTrigger disabled={!Boolean(props.list)}>
<Button
variant="outline"
size="icon"
disabled={!Boolean(props.list)}
>
<LuMenu />
</Button>
</SheetTrigger>
<SheetContent side="left" className="w-11/12">
<ScrollArea className="h-full">{props.list}</ScrollArea>
</SheetContent>
</Sheet>
<MobileLayoutMenu list={props.list} />
<div className="rounded-md dark:bg-white/10">
<img className="m-auto h-8 w-8" src="/icon.svg" />

View File

@ -172,7 +172,10 @@ function TelemetryDetailComponent() {
/>
</Card.Grid>
<Card.Grid hoverable={false} className="min-h-[470px] !w-1/3">
<Card.Grid
hoverable={false}
className="min-h-[470px] !w-full sm:!w-1/3"
>
<TelemetryMetricsTable
telemetryId={telemetryId}
type="source"
@ -182,7 +185,10 @@ function TelemetryDetailComponent() {
/>
</Card.Grid>
<Card.Grid hoverable={false} className="min-h-[470px] !w-1/3">
<Card.Grid
hoverable={false}
className="min-h-[470px] !w-full sm:!w-1/3"
>
<TelemetryMetricsTable
telemetryId={telemetryId}
type="event"
@ -192,7 +198,10 @@ function TelemetryDetailComponent() {
/>
</Card.Grid>
<Card.Grid hoverable={false} className="min-h-[470px] !w-1/3">
<Card.Grid
hoverable={false}
className="min-h-[470px] !w-full sm:!w-1/3"
>
<TelemetryMetricsTable
telemetryId={telemetryId}
type="country"

View File

@ -83,7 +83,10 @@ function WebsiteDetailComponent() {
<Card.Grid hoverable={false} className="!w-full">
<WebsiteOverview website={website} showDateFilter={true} />
</Card.Grid>
<Card.Grid hoverable={false} className="min-h-[470px] !w-1/2">
<Card.Grid
hoverable={false}
className="!w-full sm:min-h-[470px] sm:!w-1/2"
>
<WebsiteMetricsTable
websiteId={websiteId}
type="url"
@ -92,7 +95,10 @@ function WebsiteDetailComponent() {
endAt={endAt}
/>
</Card.Grid>
<Card.Grid hoverable={false} className="min-h-[470px] !w-1/2">
<Card.Grid
hoverable={false}
className="!w-full sm:min-h-[470px] sm:!w-1/2"
>
<WebsiteMetricsTable
websiteId={websiteId}
type="referrer"
@ -101,7 +107,10 @@ function WebsiteDetailComponent() {
endAt={endAt}
/>
</Card.Grid>
<Card.Grid hoverable={false} className="min-h-[470px] !w-1/3">
<Card.Grid
hoverable={false}
className="!w-full sm:min-h-[470px] sm:!w-1/3"
>
<WebsiteMetricsTable
websiteId={websiteId}
type="browser"
@ -110,7 +119,10 @@ function WebsiteDetailComponent() {
endAt={endAt}
/>
</Card.Grid>
<Card.Grid hoverable={false} className="min-h-[470px] !w-1/3">
<Card.Grid
hoverable={false}
className="!w-full sm:min-h-[470px] sm:!w-1/3"
>
<WebsiteMetricsTable
websiteId={websiteId}
type="os"
@ -119,7 +131,10 @@ function WebsiteDetailComponent() {
endAt={endAt}
/>
</Card.Grid>
<Card.Grid hoverable={false} className="min-h-[470px] !w-1/3">
<Card.Grid
hoverable={false}
className="!w-full sm:min-h-[470px] sm:!w-1/3"
>
<WebsiteMetricsTable
websiteId={websiteId}
type="device"
@ -128,7 +143,10 @@ function WebsiteDetailComponent() {
endAt={endAt}
/>
</Card.Grid>
<Card.Grid hoverable={false} className="min-h-[470px] !w-1/3">
<Card.Grid
hoverable={false}
className="!w-full sm:min-h-[470px] sm:!w-1/3"
>
<WebsiteMetricsTable
websiteId={websiteId}
type="title"
@ -137,7 +155,10 @@ function WebsiteDetailComponent() {
endAt={endAt}
/>
</Card.Grid>
<Card.Grid hoverable={false} className="min-h-[470px] !w-1/3">
<Card.Grid
hoverable={false}
className="!w-full sm:min-h-[470px] sm:!w-1/3"
>
<WebsiteMetricsTable
websiteId={websiteId}
type="country"
@ -150,7 +171,10 @@ function WebsiteDetailComponent() {
<WebsiteVisitorMapBtn websiteId={websiteId} />
</div>
</Card.Grid>
<Card.Grid hoverable={false} className="min-h-[470px] !w-1/3">
<Card.Grid
hoverable={false}
className="!w-full sm:min-h-[470px] sm:!w-1/3"
>
<WebsiteMetricsTable
websiteId={websiteId}
type="event"

24
src/client/utils/event.ts Normal file
View File

@ -0,0 +1,24 @@
import { useEvent } from '@/hooks/useEvent';
import { EventEmitter } from 'eventemitter-strict';
import { useEffect } from 'react';
export interface GlobalEventMap {
commonListSelected: () => void;
}
export const globalEventBus = new EventEmitter<GlobalEventMap>();
export function useGlobalEventSubscribe<T extends keyof GlobalEventMap>(
eventName: T,
callback: GlobalEventMap[T]
) {
const fn = useEvent(callback);
useEffect(() => {
globalEventBus.on(eventName, fn);
return () => {
globalEventBus.off(eventName, fn);
};
}, [eventName]);
}

View File

@ -82,7 +82,7 @@ function HomepageMain() {
</div>
<div className="text-center">
<div className="rounded-lg border-8 border-solid border-gray-200 shadow-lg">
<div className="rounded-lg border-8 border-solid border-gray-200 shadow-lg dark:border-gray-800">
<Carousel
className="cursor-move"
showThumbs={false}