mirror of https://github.com/buster-so/buster.git
start making filter user button
This commit is contained in:
parent
285f14c24d
commit
55bdd865c1
|
@ -0,0 +1,18 @@
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { FilterDashboardButton } from './FilterDashboardButton';
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: 'Features/Buttons/FilterDashboardButton',
|
||||||
|
component: FilterDashboardButton,
|
||||||
|
parameters: {
|
||||||
|
layout: 'centered'
|
||||||
|
},
|
||||||
|
tags: ['autodocs']
|
||||||
|
} satisfies Meta<typeof FilterDashboardButton>;
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof meta>;
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
args: {}
|
||||||
|
};
|
|
@ -0,0 +1,80 @@
|
||||||
|
import React, { useMemo, useState } from 'react';
|
||||||
|
import { Button } from '@/components/ui/buttons';
|
||||||
|
import { BarsFilter } from '@/components/ui/icons';
|
||||||
|
import { Dropdown, DropdownItems } from '@/components/ui/dropdown';
|
||||||
|
import { Input } from '@/components/ui/inputs';
|
||||||
|
import { MagnifierSparkle } from '@/components/ui/icons';
|
||||||
|
import { Text } from '@/components/ui/typography';
|
||||||
|
import { faker } from '@faker-js/faker';
|
||||||
|
import { cn } from '@/lib/classMerge';
|
||||||
|
|
||||||
|
const filterItems = Array.from({ length: 100 }, (_, index) => {
|
||||||
|
const randomWord = faker.commerce.productAdjective() + ' ' + faker.commerce.productMaterial();
|
||||||
|
return {
|
||||||
|
label: randomWord,
|
||||||
|
value: randomWord + index
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export const FilterDashboardButton: React.FC = React.memo(() => {
|
||||||
|
const [filterText, setFilterText] = useState('');
|
||||||
|
|
||||||
|
const allDropdownItems: DropdownItems = useMemo(() => {
|
||||||
|
return [
|
||||||
|
...filterItems.filter((item) => item.label.toLowerCase().includes(filterText.toLowerCase()))
|
||||||
|
];
|
||||||
|
}, [filterText]);
|
||||||
|
|
||||||
|
const menuHeader = useMemo(() => {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<div className="flex items-center gap-x-2 p-1">
|
||||||
|
<Input
|
||||||
|
placeholder="Filters..."
|
||||||
|
autoFocus
|
||||||
|
variant={'ghost'}
|
||||||
|
value={filterText}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
// e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
onChange={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
setFilterText(e.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex border-t p-1">
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'hover:bg-item-select flex w-full cursor-pointer items-center gap-x-1.5 rounded p-1',
|
||||||
|
filterText && 'bg-item-select'
|
||||||
|
)}>
|
||||||
|
<span className="text-icon-color">
|
||||||
|
<MagnifierSparkle />
|
||||||
|
</span>
|
||||||
|
<Text className="whitespace-nowrap" variant="default">
|
||||||
|
AI Filter
|
||||||
|
</Text>
|
||||||
|
{filterText && (
|
||||||
|
<Text truncate variant="tertiary">
|
||||||
|
"{filterText}"
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}, [filterText]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown items={allDropdownItems} menuHeader={menuHeader} menuHeaderClassName="p-0!">
|
||||||
|
<Button variant="ghost" prefix={<BarsFilter />}>
|
||||||
|
Filter
|
||||||
|
</Button>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
FilterDashboardButton.displayName = 'FilterDashboardButton';
|
|
@ -66,6 +66,7 @@ export interface DropdownProps<T = string> extends DropdownMenuProps {
|
||||||
footerClassName?: string;
|
footerClassName?: string;
|
||||||
sideOffset?: number;
|
sideOffset?: number;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
menuHeaderClassName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DropdownContentProps<T = string>
|
export interface DropdownContentProps<T = string>
|
||||||
|
@ -94,6 +95,7 @@ export const DropdownBase = <T,>({
|
||||||
footerContent,
|
footerContent,
|
||||||
dir,
|
dir,
|
||||||
modal,
|
modal,
|
||||||
|
menuHeaderClassName,
|
||||||
sideOffset,
|
sideOffset,
|
||||||
footerClassName = '',
|
footerClassName = '',
|
||||||
showIndex = false,
|
showIndex = false,
|
||||||
|
@ -125,6 +127,7 @@ export const DropdownBase = <T,>({
|
||||||
footerContent={footerContent}
|
footerContent={footerContent}
|
||||||
className={contentClassName}
|
className={contentClassName}
|
||||||
footerClassName={footerClassName}
|
footerClassName={footerClassName}
|
||||||
|
menuHeaderClassName={menuHeaderClassName}
|
||||||
/>
|
/>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
@ -142,6 +145,7 @@ export const DropdownContent = <T,>({
|
||||||
emptyStateText = 'No items found',
|
emptyStateText = 'No items found',
|
||||||
footerContent,
|
footerContent,
|
||||||
className,
|
className,
|
||||||
|
menuHeaderClassName,
|
||||||
footerClassName,
|
footerClassName,
|
||||||
onSelect
|
onSelect
|
||||||
}: DropdownContentProps<T>) => {
|
}: DropdownContentProps<T>) => {
|
||||||
|
@ -213,7 +217,7 @@ export const DropdownContent = <T,>({
|
||||||
<>
|
<>
|
||||||
{menuHeader && (
|
{menuHeader && (
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<div className="p-1">
|
<div className={cn('p-1', menuHeaderClassName)}>
|
||||||
<DropdownMenuHeaderSelector
|
<DropdownMenuHeaderSelector
|
||||||
menuHeader={menuHeader}
|
menuHeader={menuHeader}
|
||||||
onChange={handleSearchChange}
|
onChange={handleSearchChange}
|
||||||
|
|
Loading…
Reference in New Issue