Skip to content

Commit 8a24c32

Browse files
authored
Feat: add highlight animation for recently moved filter checkboxes (#1180)
This PR adds a highlight animation for recently moved filter checkboxes. ### Why? When filters are moved, users can easily lose track of checkboxees, especially when labels have similar texts. This PR highlights recently moved checkboxes to make changes immediately visible. | Before | After | |--------|-------| | <video src="https://github.com/user-attachments/assets/689556e6-8a10-4c3e-b188-043ebcfa0cea" autoplay loop muted width="200"></video> | <video src="https://github.com/user-attachments/assets/c7edb5a3-5dd0-43d1-8672-a4d399269893" autoplay loop muted width="200"></video> |
1 parent 4ff55c0 commit 8a24c32

File tree

3 files changed

+66
-3
lines changed

3 files changed

+66
-3
lines changed

.changeset/spotty-suits-own.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@hyperdx/app": minor
3+
---
4+
5+
Feat: add highlight animation for recently moved filter checkboxes

packages/app/src/components/DBSearchPageFilters.tsx

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
import { memo, useCallback, useEffect, useId, useMemo, useState } from 'react';
1+
import {
2+
memo,
3+
useCallback,
4+
useEffect,
5+
useId,
6+
useMemo,
7+
useRef,
8+
useState,
9+
} from 'react';
10+
import cx from 'classnames';
211
import {
312
TableMetadata,
413
tcFromSource,
@@ -65,6 +74,7 @@ type FilterCheckboxProps = {
6574
onClickOnly?: VoidFunction;
6675
onClickExclude?: VoidFunction;
6776
onClickPin: VoidFunction;
77+
className?: string;
6878
};
6979

7080
export const TextButton = ({
@@ -103,10 +113,11 @@ export const FilterCheckbox = ({
103113
onClickOnly,
104114
onClickExclude,
105115
onClickPin,
116+
className,
106117
}: FilterCheckboxProps) => {
107118
return (
108119
<div
109-
className={classes.filterCheckbox}
120+
className={cx(classes.filterCheckbox, className)}
110121
data-testid={`filter-checkbox-${label}`}
111122
>
112123
<Group
@@ -224,6 +235,8 @@ export const FilterGroup = ({
224235
const [shouldShowMore, setShowMore] = useState(false);
225236
// Accordion expanded state
226237
const [isExpanded, setExpanded] = useState(isDefaultExpanded ?? false);
238+
// Track recently moved items for highlight animation
239+
const [recentlyMoved, setRecentlyMoved] = useState<Set<string>>(new Set());
227240

228241
useEffect(() => {
229242
if (isDefaultExpanded) {
@@ -298,6 +311,27 @@ export const FilterGroup = ({
298311
totalFiltersSize,
299312
]);
300313

314+
// Simple highlight animation when checkbox is checked
315+
const handleChange = useCallback(
316+
(value: string) => {
317+
const wasIncluded = selectedValues.included.has(value);
318+
319+
// If checking (not unchecking), trigger highlight animation
320+
if (!wasIncluded) {
321+
setRecentlyMoved(prev => new Set(prev).add(value));
322+
setTimeout(() => {
323+
setRecentlyMoved(prev => {
324+
const newSet = new Set(prev);
325+
newSet.delete(value);
326+
return newSet;
327+
});
328+
}, 600);
329+
}
330+
331+
onChange(value);
332+
},
333+
[onChange, selectedValues],
334+
);
301335
const showShowMoreButton =
302336
!search &&
303337
augmentedOptions.length > MAX_FILTER_GROUP_ITEMS &&
@@ -403,14 +437,17 @@ export const FilterGroup = ({
403437
key={option.value}
404438
label={option.label}
405439
pinned={isPinned(option.value)}
440+
className={
441+
recentlyMoved.has(option.value) ? classes.recentlyMoved : ''
442+
}
406443
value={
407444
selectedValues.included.has(option.value)
408445
? 'included'
409446
: selectedValues.excluded.has(option.value)
410447
? 'excluded'
411448
: false
412449
}
413-
onChange={() => onChange(option.value)}
450+
onChange={() => handleChange(option.value)}
414451
onClickOnly={() => onOnlyClick(option.value)}
415452
onClickExclude={() => onExcludeClick(option.value)}
416453
onClickPin={() => onPinClick(option.value)}

packages/app/styles/SearchPage.module.scss

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,24 @@
130130
transform: rotate(0deg);
131131
}
132132
}
133+
134+
.recentlyMoved {
135+
animation: highlight 0.6s ease-out;
136+
}
137+
138+
@keyframes highlight {
139+
0% {
140+
background-color: $slate-950;
141+
transform: scale(1.02);
142+
}
143+
144+
50% {
145+
background-color: $slate-900;
146+
transform: scale(1.01);
147+
}
148+
149+
100% {
150+
background-color: transparent;
151+
transform: scale(1);
152+
}
153+
}

0 commit comments

Comments
 (0)