Skip to content

Commit 1cfef2d

Browse files
authored
Indicate extra filters count on triple dot menu hover (#5219)
1 parent b51d188 commit 1cfef2d

File tree

2 files changed

+85
-53
lines changed

2 files changed

+85
-53
lines changed

assets/js/dashboard/nav-menu/filters-bar.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ test('user can see expected filters and clear them one by one or all together',
7878
await userEvent.click(
7979
screen.getByRole('button', {
8080
hidden: false,
81-
name: 'See more'
81+
name: 'See 3 more filters and actions'
8282
})
8383
)
8484

assets/js/dashboard/nav-menu/filters-bar.tsx

Lines changed: 84 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { EllipsisHorizontalIcon } from '@heroicons/react/24/solid'
44
import classNames from 'classnames'
5-
import React, { useRef, useState, useLayoutEffect } from 'react'
5+
import React, { useRef, useState, useLayoutEffect, ReactNode } from 'react'
66
import { AppliedFilterPillsList, PILL_X_GAP_PX } from './filter-pills-list'
77
import { useQueryContext } from '../query-context'
88
import { AppNavigationLink } from '../navigation/use-app-navigate'
@@ -109,21 +109,21 @@ interface FiltersBarProps {
109109
}
110110
}
111111

112-
const canShowClearAllAction = ({ filters }: Pick<DashboardQuery, 'filters'>) =>
113-
filters.length >= 2
112+
const canShowClearAllAction = ({
113+
filters
114+
}: Pick<DashboardQuery, 'filters'>): boolean => filters.length >= 2
114115

115116
const canShowSaveAsSegmentAction = ({
116117
filters,
117118
isEditingSegment
118-
}: Pick<DashboardQuery, 'filters'> & { isEditingSegment: boolean }) =>
119+
}: Pick<DashboardQuery, 'filters'> & { isEditingSegment: boolean }): boolean =>
119120
filters.length >= 1 && !filters.some(isSegmentFilter) && !isEditingSegment
120121

121122
export const FiltersBar = ({ accessors }: FiltersBarProps) => {
122123
const containerRef = useRef<HTMLDivElement>(null)
123124
const pillsRef = useRef<HTMLDivElement>(null)
124125
const [visibility, setVisibility] = useState<null | VisibilityState>(null)
125126
const { query, expandedSegment } = useQueryContext()
126-
const seeMoreRef = useRef<HTMLButtonElement>(null)
127127

128128
const showingClearAll = canShowClearAllAction({ filters: query.filters })
129129
const showingSaveAsSegment = canShowSaveAsSegmentAction({
@@ -203,58 +203,90 @@ export const FiltersBar = ({ accessors }: FiltersBarProps) => {
203203
{visibility !== null &&
204204
(query.filters.length !== visibility.visibleCount ||
205205
mustShowSeeMoreMenu) && (
206-
<Popover className="md:relative">
207-
<BlurMenuButtonOnEscape targetRef={seeMoreRef} />
208-
<Popover.Button
209-
title="See more"
210-
ref={seeMoreRef}
211-
className={classNames(
212-
popover.toggleButton.classNames.rounded,
213-
popover.toggleButton.classNames.shadow,
214-
'justify-center'
215-
)}
216-
style={{
217-
height: SEE_MORE_WIDTH_PX,
218-
width: SEE_MORE_WIDTH_PX,
219-
marginLeft: SEE_MORE_LEFT_MARGIN_PX,
220-
marginRight: SEE_MORE_RIGHT_MARGIN_PX
221-
}}
222-
>
223-
<EllipsisHorizontalIcon className="block h-5 w-5" />
224-
</Popover.Button>
225-
<Transition
226-
{...popover.transition.props}
227-
className={classNames(
228-
'mt-2',
229-
popover.transition.classNames.fullwidth,
230-
'md:right-auto'
231-
)}
232-
>
233-
<Popover.Panel
234-
className={classNames(
235-
popover.panel.classNames.roundedSheet,
236-
'flex flex-col p-4 gap-y-2'
237-
)}
238-
>
239-
{query.filters.length !== visibility.visibleCount && (
240-
<AppliedFilterPillsList
241-
direction="vertical"
242-
slice={{
243-
type: 'no-render-outside',
244-
start: visibility.visibleCount
245-
}}
246-
/>
247-
)}
248-
{showingClearAll && <ClearAction />}
249-
{showingSaveAsSegment && <SaveAsSegmentAction />}
250-
</Popover.Panel>
251-
</Transition>
252-
</Popover>
206+
<SeeMoreMenu
207+
className="md:relative"
208+
filtersCount={query.filters.length}
209+
visibleFiltersCount={visibility.visibleCount}
210+
>
211+
{showingClearAll && <ClearAction />}
212+
{showingSaveAsSegment && <SaveAsSegmentAction />}
213+
</SeeMoreMenu>
253214
)}
254215
</div>
255216
)
256217
}
257218

219+
const SeeMoreMenu = ({
220+
className,
221+
filtersCount,
222+
visibleFiltersCount,
223+
children
224+
}: {
225+
className?: string
226+
filtersCount: number
227+
visibleFiltersCount: number
228+
children: ReactNode
229+
}) => {
230+
const seeMoreRef = useRef<HTMLButtonElement>(null)
231+
const filtersInMenuCount = filtersCount - visibleFiltersCount
232+
233+
const title =
234+
filtersInMenuCount === 1
235+
? 'See 1 more filter and actions'
236+
: filtersInMenuCount > 1
237+
? `See ${filtersInMenuCount} more filters and actions`
238+
: 'See actions'
239+
240+
return (
241+
<Popover className={className}>
242+
<BlurMenuButtonOnEscape targetRef={seeMoreRef} />
243+
<Popover.Button
244+
title={title}
245+
ref={seeMoreRef}
246+
className={classNames(
247+
popover.toggleButton.classNames.rounded,
248+
popover.toggleButton.classNames.shadow,
249+
'justify-center'
250+
)}
251+
style={{
252+
height: SEE_MORE_WIDTH_PX,
253+
width: SEE_MORE_WIDTH_PX,
254+
marginLeft: SEE_MORE_LEFT_MARGIN_PX,
255+
marginRight: SEE_MORE_RIGHT_MARGIN_PX
256+
}}
257+
>
258+
<EllipsisHorizontalIcon className="block h-5 w-5" />
259+
</Popover.Button>
260+
<Transition
261+
{...popover.transition.props}
262+
className={classNames(
263+
'mt-2',
264+
popover.transition.classNames.fullwidth,
265+
'md:right-auto'
266+
)}
267+
>
268+
<Popover.Panel
269+
className={classNames(
270+
popover.panel.classNames.roundedSheet,
271+
'flex flex-col p-4 gap-y-2'
272+
)}
273+
>
274+
{filtersCount !== visibleFiltersCount && (
275+
<AppliedFilterPillsList
276+
direction="vertical"
277+
slice={{
278+
type: 'no-render-outside',
279+
start: visibleFiltersCount
280+
}}
281+
/>
282+
)}
283+
{children}
284+
</Popover.Panel>
285+
</Transition>
286+
</Popover>
287+
)
288+
}
289+
258290
const ClearAction = () => (
259291
<AppNavigationLink
260292
className={classNames(

0 commit comments

Comments
 (0)