Skip to content

Commit

Permalink
feat: add breadcrumb component
Browse files Browse the repository at this point in the history
Signed-off-by: Lukas.J.Han <[email protected]>
  • Loading branch information
lukasjhan committed Aug 10, 2024
1 parent 0d7e8e4 commit 246d114
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 1 deletion.
97 changes: 97 additions & 0 deletions packages/core/lib/components/Breadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react';
import { Label } from './Label';

interface BreadcrumbItem {
label: string;
onClick: () => void;
}

interface BreadcrumbProps {
items: BreadcrumbItem[];
maxLength?: number;
}

const ChevronIcon: React.FC = () => (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<path
d="M6 4L10 8L6 12"
stroke="currentColor"
strokeWidth="1"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);

const EllipsisIcon: React.FC = () => (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
>
<circle cx="3" cy="8" r="1" fill="currentColor" />
<circle cx="8" cy="8" r="1" fill="currentColor" />
<circle cx="13" cy="8" r="1" fill="currentColor" />
</svg>
);

export const Breadcrumb: React.FC<BreadcrumbProps> = ({
items,
maxLength = 3,
}) => {
const maxItems = Math.max(2, maxLength);
const renderItems = () => {
if (items.length <= maxItems) {
return items;
}

const visibleItems = [];
visibleItems.push(items[0]);

if (maxItems > 2) {
for (let i = 1; i < maxItems - 1; i++) {
visibleItems.push(items[items.length - maxItems + i]);
}
}

visibleItems.push(items[items.length - 1]);

return visibleItems;
};

return (
<nav aria-label="브레드크럼" className="py-2">
<ol className="flex items-center">
{renderItems().map((item, index) => (
<li key={index} className="flex items-center m-0">
{index > 0 && <ChevronIcon />}
{index === 1 && items.length > maxItems && (
<>
<EllipsisIcon />
<ChevronIcon />
</>
)}
<Label
onClick={item.onClick}
color={'gray-90'}
size="xs"
className="hover:underline focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary cursor-pointer"
>
{item.label}
</Label>
</li>
))}
</ol>
</nav>
);
};
3 changes: 2 additions & 1 deletion packages/core/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { LinkButton } from './components/LinkButton';
import { Tag } from './components/Tag';
import { Spinner } from './components/Spinner';
import { Badge } from './components/Badge';
import { Breadcrumb } from './components/Breadcrumb';

export { Display, Heading, Title, Body, Detail, Label, Link, colors };
export { Button, LinkButton, Tag, Spinner, Badge };
export { Button, LinkButton, Tag, Spinner, Badge, Breadcrumb };
63 changes: 63 additions & 0 deletions stories/core/Breadcrumb.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';
import { Breadcrumb } from '../../packages/core/lib';

const meta = {
title: 'Components/Breadcrumb',
component: Breadcrumb,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {},
} satisfies Meta<typeof Breadcrumb>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
items: [
{ label: '홈', onClick: () => console.log('홈') },
{ label: '문서', onClick: () => console.log('문서') },
{ label: '서적', onClick: () => console.log('서적') },
{ label: '서적 서적', onClick: () => console.log('서적 서적') },
],
},
};

export const MaxItems: Story = {
args: {
items: [
{ label: '홈', onClick: () => console.log('홈') },
{ label: '문서', onClick: () => console.log('문서') },
{ label: '서적', onClick: () => console.log('서적') },
{ label: '서적 서적', onClick: () => console.log('서적 서적') },
],
maxLength: 2,
},
};

export const WithoutEllipsis: Story = {
args: {
items: [
{ label: '홈', onClick: () => console.log('홈') },
{ label: '문서', onClick: () => console.log('문서') },
{ label: '서적', onClick: () => console.log('서적') },
{ label: '서적 서적', onClick: () => console.log('서적 서적') },
],
maxLength: 5,
},
};

export const maxLengthIsLessThan2: Story = {
args: {
items: [
{ label: '홈', onClick: () => console.log('홈') },
{ label: '문서', onClick: () => console.log('문서') },
{ label: '서적', onClick: () => console.log('서적') },
{ label: '서적 서적', onClick: () => console.log('서적 서적') },
],
maxLength: 1,
},
};

0 comments on commit 246d114

Please sign in to comment.