Skip to content

Commit 2365ae9

Browse files
authored
Merge pull request #2 from bacali95/list-group-page
Add list group component
2 parents 16482e3 + da8ade4 commit 2365ae9

File tree

3 files changed

+151
-0
lines changed

3 files changed

+151
-0
lines changed

src/Root.tsx

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
HiBadgeCheck,
55
HiBell,
66
HiChevronDoubleRight,
7+
HiClipboardList,
78
HiCollection,
89
HiCreditCard,
910
HiDuplicate,
@@ -25,6 +26,7 @@ const ButtonsPage = lazy(() => import('./pages/ButtonsPage'));
2526
const ButtonGroupPage = lazy(() => import('./pages/ButtonGroupPage'));
2627
const CardPage = lazy(() => import('./pages/CardPage'));
2728
const CarouselPage = lazy(() => import('./pages/CarouselPage'));
29+
const ListGroupPage = lazy(() => import('./pages/ListGroupPage'));
2830
const SpinnersPage = lazy(() => import('./pages/SpinnersPage'));
2931
const TooltipsPage = lazy(() => import('./pages/TooltipsPage'));
3032

@@ -86,6 +88,12 @@ export const Root: FC = () => {
8688
title: 'Carousel',
8789
href: '/carousel',
8890
},
91+
{
92+
group: false,
93+
icon: HiClipboardList,
94+
title: 'List group',
95+
href: '/list-group',
96+
},
8997
{
9098
group: false,
9199
icon: FaSpinner,
@@ -143,6 +151,7 @@ export const Root: FC = () => {
143151
<Route path="button-group" element={<ButtonGroupPage />} />
144152
<Route path="card" element={<CardPage />} />
145153
<Route path="carousel" element={<CarouselPage />} />
154+
<Route path="list-group" element={<ListGroupPage />} />
146155
<Route path="spinners" element={<SpinnersPage />} />
147156
<Route path="tooltips" element={<TooltipsPage />} />
148157
</Routes>

src/components/ListGroup.tsx

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { ComponentProps, FC, Fragment, ReactNode } from 'react';
2+
import classNames from 'classnames';
3+
4+
export type ListGroupProps = {
5+
items: ListGroupItem[];
6+
};
7+
export type ListGroupItem = {
8+
title: ReactNode;
9+
link?: string;
10+
icon?: FC<ComponentProps<'svg'>>;
11+
active?: boolean;
12+
onClick?: () => void;
13+
disabled?: boolean;
14+
};
15+
16+
export const ListGroup: FC<ListGroupProps> = ({ items }) => {
17+
return (
18+
<div className="w-48 list-none divide-y divide-gray-200 rounded-lg border border-gray-200 bg-white text-sm font-medium text-gray-900 dark:divide-gray-600 dark:border-gray-600 dark:bg-gray-700 dark:text-white">
19+
{items.map((item, index) => (
20+
<Fragment key={index}>
21+
{!item.link ? (
22+
<button
23+
onClick={item.onClick}
24+
className={classNames(
25+
'flex w-full items-center gap-2 py-2 px-4 text-left text-sm font-medium first:rounded-t-lg last:rounded-b-lg',
26+
{
27+
'!bg-blue-700 text-white': item.active,
28+
'hover:bg-gray-100 hover:text-blue-700 dark:hover:bg-gray-600 dark:hover:text-white': !item.active,
29+
},
30+
)}
31+
type="button"
32+
>
33+
{item.icon && <item.icon />}
34+
{item.title}
35+
</button>
36+
) : (
37+
<a
38+
href={item.link}
39+
aria-current="false"
40+
className={classNames(
41+
'block w-full cursor-pointer py-2 px-4 first:rounded-t-lg last:rounded-b-lg focus:outline-none dark:bg-gray-800',
42+
{
43+
'!bg-blue-700 text-white': item.active,
44+
'hover:bg-gray-100 hover:text-blue-700 dark:hover:bg-gray-600 dark:hover:text-white': !item.active,
45+
},
46+
)}
47+
>
48+
{item.title}
49+
</a>
50+
)}
51+
</Fragment>
52+
))}
53+
</div>
54+
);
55+
};

src/pages/ListGroupPage.tsx

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { FC } from 'react';
2+
import { ListGroup, ListGroupItem } from '../components/ListGroup';
3+
import { CodeExample, DemoPage } from './DemoPage';
4+
import { HiCloudDownload, HiInbox, HiOutlineAdjustments, HiUserCircle } from 'react-icons/hi';
5+
6+
const ListGroupPage: FC = () => {
7+
const defaultItems: ListGroupItem[] = [
8+
{
9+
title: 'Profile',
10+
},
11+
{
12+
title: 'Settings',
13+
},
14+
{
15+
title: 'Messages',
16+
},
17+
{
18+
title: 'Download',
19+
},
20+
];
21+
22+
const itemsWithLinks: ListGroupItem[] = [
23+
{
24+
title: 'Profile',
25+
link: '#/list-group',
26+
active: true,
27+
},
28+
{
29+
title: 'Settings',
30+
link: '#/list-group',
31+
},
32+
{
33+
title: 'Messages',
34+
link: '#/list-group',
35+
},
36+
{
37+
title: 'Download',
38+
link: '#/list-group',
39+
},
40+
];
41+
42+
const itemsWithIcons: ListGroupItem[] = [
43+
{
44+
title: 'Profile',
45+
icon: HiUserCircle,
46+
onClick: () => alert('profile'),
47+
},
48+
{
49+
title: 'Settings',
50+
icon: HiOutlineAdjustments,
51+
},
52+
{
53+
title: 'Messages',
54+
icon: HiInbox,
55+
},
56+
{
57+
title: 'Download',
58+
icon: HiCloudDownload,
59+
},
60+
];
61+
62+
const examples: CodeExample[] = [
63+
{
64+
title: 'Default list',
65+
code: <ListGroup items={defaultItems} />,
66+
},
67+
{
68+
title: 'List group with links',
69+
code: <ListGroup items={itemsWithLinks} />,
70+
},
71+
{
72+
title: 'List group with buttons',
73+
code: <ListGroup items={itemsWithLinks} />,
74+
},
75+
{
76+
title: 'List group with icons',
77+
code: <ListGroup items={itemsWithIcons} />,
78+
codeStringifierOptions: {
79+
functionValue: (fn) => (fn.name === 'onClick' ? fn : fn.name),
80+
},
81+
},
82+
];
83+
84+
return <DemoPage examples={examples} />;
85+
};
86+
87+
export default ListGroupPage;

0 commit comments

Comments
 (0)