Skip to content

Commit 6df6423

Browse files
hemanandrclaude
andcommitted
feat: enhance TrendBlocks with heartbeat animation and improved layout
- Add heartbeat animation to rightmost (latest) status block - Change from 24 to 20 blocks for better visual balance - Show gray blocks for empty slots when data < 20 points - Latest data always appears on the right (chronological order) - Add proper spacing and overflow handling Animation creates visual indicator of most recent status check with smooth scaling from 0.9x to 1.1x every 1.5s. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent beba291 commit 6df6423

File tree

1 file changed

+51
-14
lines changed

1 file changed

+51
-14
lines changed

thingconnect.pulse.client/src/components/status/TrendBlocks.tsx

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,59 @@ import { HStack, Box } from '@chakra-ui/react';
22
import type { SparklinePoint } from '@/api/types';
33

44
const TrendBlocks = ({ data }: { data: SparklinePoint[] }) => {
5-
// Limit to last 24 points (2 minutes of data)
6-
const displayData = data.slice(-24);
5+
const maxBlocks = 20;
6+
// Take the last 20 points, but maintain order (oldest to newest)
7+
const recentData = data.slice(-maxBlocks);
8+
9+
// Create array of 20 blocks, fill empty ones with null
10+
const displayBlocks = Array(maxBlocks).fill(null).map((_, idx) => {
11+
const dataIdx = idx - (maxBlocks - recentData.length);
12+
return dataIdx >= 0 ? recentData[dataIdx] : null;
13+
});
714

815
return (
9-
<HStack gap={1}>
10-
{displayData.map((point, idx) => (
11-
<Box
12-
key={idx}
13-
w='3'
14-
h='5'
15-
borderRadius='sm'
16-
bg={point.s === 'd' ? 'red.500' : 'green.500'}
17-
_dark={{ bg: point.s === 'd' ? 'red.600' : 'green.600' }}
18-
/>
19-
))}
20-
</HStack>
16+
<>
17+
<style>
18+
{`
19+
@keyframes heartbeat {
20+
0% { transform: scale(0.9); }
21+
50% { transform: scale(1.10); }
22+
100% { transform: scale(0.9); }
23+
}
24+
.heartbeat-animation {
25+
animation: heartbeat 1.5s ease-in-out infinite;
26+
}
27+
`}
28+
</style>
29+
<HStack gap={1} alignItems="center" overflow="hidden" py={"2px"} pr={"2px"}>
30+
{displayBlocks.map((point, idx) => {
31+
const isLastElement = idx === displayBlocks.length - 1 && point !== null;
32+
const isEmpty = point === null;
33+
34+
return (
35+
<Box
36+
key={idx}
37+
w='3'
38+
h='5'
39+
borderRadius='sm'
40+
bg={isEmpty
41+
? 'gray.200'
42+
: point.s === 'd' ? 'red.500' : 'green.500'
43+
}
44+
_dark={{
45+
bg: isEmpty
46+
? 'gray.700'
47+
: point.s === 'd' ? 'red.600' : 'green.600'
48+
}}
49+
className={isLastElement ? 'heartbeat-animation' : undefined}
50+
transformOrigin="center"
51+
position="relative"
52+
zIndex={isLastElement ? 2 : 1}
53+
/>
54+
);
55+
})}
56+
</HStack>
57+
</>
2158
);
2259
};
2360

0 commit comments

Comments
 (0)