perf: improve healthbar display, will responsive with container size
This commit is contained in:
parent
6fecde0caa
commit
3990b0a872
@ -1,3 +1,4 @@
|
|||||||
|
import { useResizeObserver } from '@/hooks/useResizeObserver';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
@ -14,15 +15,28 @@ export interface HealthBarProps {
|
|||||||
}
|
}
|
||||||
export const HealthBar: React.FC<HealthBarProps> = React.memo((props) => {
|
export const HealthBar: React.FC<HealthBarProps> = React.memo((props) => {
|
||||||
const size = props.size ?? 'small';
|
const size = props.size ?? 'small';
|
||||||
|
const [containerRef, containerRect] = useResizeObserver();
|
||||||
|
|
||||||
|
const cellCount = props.beats.length;
|
||||||
|
const cellNeedWidth = size === 'small' ? 8 : 12; // include gap
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
ref={containerRef}
|
||||||
className={clsx('flex', {
|
className={clsx('flex', {
|
||||||
'gap-[3px]': size === 'small',
|
'gap-[3px]': size === 'small',
|
||||||
'gap-1': size === 'large',
|
'gap-1': size === 'large',
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{props.beats.map((beat, i) => (
|
{props.beats
|
||||||
|
.slice(
|
||||||
|
Math.floor(
|
||||||
|
Math.max(cellNeedWidth * cellCount - containerRect.width, 0) /
|
||||||
|
cellNeedWidth
|
||||||
|
),
|
||||||
|
cellCount
|
||||||
|
)
|
||||||
|
.map((beat, i) => (
|
||||||
<div
|
<div
|
||||||
key={i}
|
key={i}
|
||||||
title={beat.title}
|
title={beat.title}
|
||||||
|
@ -120,7 +120,7 @@ export const MonitorHealthBar: React.FC<MonitorHealthBarProps> = React.memo(
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex-1">
|
<div className="flex-1 overflow-hidden">
|
||||||
<HealthBar size={size} beats={beats} />
|
<HealthBar size={size} beats={beats} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ export const MonitorHealthBar: React.FC<MonitorHealthBarProps> = React.memo(
|
|||||||
{last(beats)?.status === 'health' ? (
|
{last(beats)?.status === 'health' ? (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'rounded-full bg-green-500 px-4 py-1 text-lg font-bold text-white',
|
'ml-2 rounded-full bg-green-500 px-4 py-1 text-lg font-bold text-white',
|
||||||
{
|
{
|
||||||
'text-sm': size === 'small',
|
'text-sm': size === 'small',
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@ export const MonitorHealthBar: React.FC<MonitorHealthBarProps> = React.memo(
|
|||||||
) : last(beats)?.status === 'error' ? (
|
) : last(beats)?.status === 'error' ? (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'rounded-full bg-red-600 px-4 py-1 text-lg font-bold text-white',
|
'ml-2 rounded-full bg-red-600 px-4 py-1 text-lg font-bold text-white',
|
||||||
{
|
{
|
||||||
'text-sm': size === 'small',
|
'text-sm': size === 'small',
|
||||||
}
|
}
|
||||||
@ -151,7 +151,7 @@ export const MonitorHealthBar: React.FC<MonitorHealthBarProps> = React.memo(
|
|||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'rounded-full bg-gray-400 px-4 py-1 text-lg font-bold text-white',
|
'ml-2 rounded-full bg-gray-400 px-4 py-1 text-lg font-bold text-white',
|
||||||
{
|
{
|
||||||
'text-sm': size === 'small',
|
'text-sm': size === 'small',
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { CalendarOutlined } from '@ant-design/icons';
|
|
||||||
import dayjs, { Dayjs } from 'dayjs';
|
import dayjs, { Dayjs } from 'dayjs';
|
||||||
import { useMemo, useReducer } from 'react';
|
import { useMemo, useReducer } from 'react';
|
||||||
import { getMinimumUnit } from '@tianji/shared';
|
import { getMinimumUnit } from '@tianji/shared';
|
||||||
|
70
src/client/hooks/useResizeObserver.ts
Normal file
70
src/client/hooks/useResizeObserver.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* Copy from https://github.com/mantinedev/mantine/blob/master/packages/@mantine/hooks/src/use-resize-observer/use-resize-observer.ts
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useRef, useState, useMemo, useEffect } from 'react';
|
||||||
|
|
||||||
|
type ObserverRect = Omit<DOMRectReadOnly, 'toJSON'>;
|
||||||
|
|
||||||
|
const defaultState: ObserverRect = {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
bottom: 0,
|
||||||
|
right: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useResizeObserver<T extends HTMLElement = any>(
|
||||||
|
options?: ResizeObserverOptions
|
||||||
|
) {
|
||||||
|
const frameID = useRef(0);
|
||||||
|
const ref = useRef<T>(null);
|
||||||
|
|
||||||
|
const [rect, setRect] = useState<ObserverRect>(defaultState);
|
||||||
|
|
||||||
|
const observer = useMemo(
|
||||||
|
() =>
|
||||||
|
typeof window !== 'undefined'
|
||||||
|
? new ResizeObserver((entries: any) => {
|
||||||
|
const entry = entries[0];
|
||||||
|
|
||||||
|
if (entry) {
|
||||||
|
cancelAnimationFrame(frameID.current);
|
||||||
|
|
||||||
|
frameID.current = requestAnimationFrame(() => {
|
||||||
|
if (ref.current) {
|
||||||
|
setRect(entry.contentRect);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
: null,
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (ref.current) {
|
||||||
|
observer?.observe(ref.current, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
observer?.disconnect();
|
||||||
|
|
||||||
|
if (frameID.current) {
|
||||||
|
cancelAnimationFrame(frameID.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [ref.current]);
|
||||||
|
|
||||||
|
return [ref, rect] as const;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useElementSize<T extends HTMLElement = any>(
|
||||||
|
options?: ResizeObserverOptions
|
||||||
|
) {
|
||||||
|
const [ref, { width, height }] = useResizeObserver<T>(options);
|
||||||
|
return { ref, width, height };
|
||||||
|
}
|
@ -133,6 +133,7 @@ export const workspaceRouter = router({
|
|||||||
workspaceId: z.string(),
|
workspaceId: z.string(),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
.output(z.void())
|
||||||
.mutation(async ({ input, ctx }) => {
|
.mutation(async ({ input, ctx }) => {
|
||||||
const { workspaceId } = input;
|
const { workspaceId } = input;
|
||||||
const userId = ctx.user.id;
|
const userId = ctx.user.id;
|
||||||
|
Loading…
Reference in New Issue
Block a user