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 React from 'react';
|
||||
|
||||
@ -14,15 +15,28 @@ export interface HealthBarProps {
|
||||
}
|
||||
export const HealthBar: React.FC<HealthBarProps> = React.memo((props) => {
|
||||
const size = props.size ?? 'small';
|
||||
const [containerRef, containerRect] = useResizeObserver();
|
||||
|
||||
const cellCount = props.beats.length;
|
||||
const cellNeedWidth = size === 'small' ? 8 : 12; // include gap
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
className={clsx('flex', {
|
||||
'gap-[3px]': size === 'small',
|
||||
'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
|
||||
key={i}
|
||||
title={beat.title}
|
||||
|
@ -120,7 +120,7 @@ export const MonitorHealthBar: React.FC<MonitorHealthBarProps> = React.memo(
|
||||
</span>
|
||||
)}
|
||||
|
||||
<div className="flex-1">
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<HealthBar size={size} beats={beats} />
|
||||
</div>
|
||||
|
||||
@ -129,7 +129,7 @@ export const MonitorHealthBar: React.FC<MonitorHealthBarProps> = React.memo(
|
||||
{last(beats)?.status === 'health' ? (
|
||||
<div
|
||||
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',
|
||||
}
|
||||
@ -140,7 +140,7 @@ export const MonitorHealthBar: React.FC<MonitorHealthBarProps> = React.memo(
|
||||
) : last(beats)?.status === 'error' ? (
|
||||
<div
|
||||
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',
|
||||
}
|
||||
@ -151,7 +151,7 @@ export const MonitorHealthBar: React.FC<MonitorHealthBarProps> = React.memo(
|
||||
) : (
|
||||
<div
|
||||
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',
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { CalendarOutlined } from '@ant-design/icons';
|
||||
import dayjs, { Dayjs } from 'dayjs';
|
||||
import { useMemo, useReducer } from 'react';
|
||||
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(),
|
||||
})
|
||||
)
|
||||
.output(z.void())
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const { workspaceId } = input;
|
||||
const userId = ctx.user.id;
|
||||
|
Loading…
Reference in New Issue
Block a user