Skip to content

Commit 3b23622

Browse files
committed
✨ Add Breadcrumb component
1 parent e807579 commit 3b23622

File tree

10 files changed

+293
-1
lines changed

10 files changed

+293
-1
lines changed

.vscode/tasks.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"tasks": [
77
{
88
"label": "🔍 Develop",
9-
"command": "npm run develop",
9+
"command": "npm run dev",
1010
},
1111
{
1212
"label": "🛠️ Build",

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ import { Accordion } from 'webcoreui/react'
198198
- [Alert](https://github.com/Frontendland/webcoreui/tree/main/src/components/Alert)
199199
- [Avatar](https://github.com/Frontendland/webcoreui/tree/main/src/components/Avatar)
200200
- [Badge](https://github.com/Frontendland/webcoreui/tree/main/src/components/Badge)
201+
- [Breadcrumb](https://github.com/Frontendland/webcoreui/tree/main/src/components/Breadcrumb)
201202
- [Button](https://github.com/Frontendland/webcoreui/tree/main/src/components/Button)
202203
- [Card](https://github.com/Frontendland/webcoreui/tree/main/src/components/Card)
203204
- [Carousel](https://github.com/Frontendland/webcoreui/tree/main/src/components/Carousel)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
import type { BreadcrumbProps } from './breadcrumb'
3+
4+
import ConditionalWrapper from '../ConditionalWrapper/ConditionalWrapper.astro'
5+
import Icon from '../Icon/Icon.astro'
6+
7+
import styles from './breadcrumb.module.scss'
8+
9+
import type { IconProps } from '../Icon/icon'
10+
11+
interface Props extends BreadcrumbProps {}
12+
13+
const {
14+
items,
15+
separator,
16+
className
17+
} = Astro.props
18+
19+
const classes = [
20+
styles.breadcrumb,
21+
className
22+
]
23+
---
24+
25+
<ul class:list={classes}>
26+
{items?.map((item, index) => (
27+
<li>
28+
<ConditionalWrapper condition={!!(item.href && index !== items.length - 1)}>
29+
<a href={item.href} target={item.target} slot="wrapper">
30+
children
31+
</a>
32+
{item.icon && (
33+
<Fragment>
34+
{item.icon.startsWith('<svg')
35+
? <Fragment set:html={item.icon} />
36+
: <Icon type={item.icon as IconProps['type']} />
37+
}
38+
</Fragment>
39+
)}
40+
{item.label}
41+
</ConditionalWrapper>
42+
</li>
43+
<Fragment>
44+
{index < items.length - 1 && (
45+
<li>
46+
{separator || <Icon type="arrow-right" />}
47+
</li>
48+
)}
49+
</Fragment>
50+
))}
51+
</ul>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<script lang="ts">
2+
import type { BreadcrumbProps } from './breadcrumb'
3+
4+
import ConditionalWrapper from '../ConditionalWrapper/ConditionalWrapper.svelte'
5+
6+
import { classNames } from '../../utils/classNames'
7+
8+
import ArrowRight from '../../icons/arrow-right.svg?raw'
9+
10+
import styles from './breadcrumb.module.scss'
11+
12+
export let items: BreadcrumbProps['items'] = []
13+
export let separator: BreadcrumbProps['separator'] = ''
14+
export let className: BreadcrumbProps['className'] = ''
15+
16+
const classes = classNames([
17+
styles.breadcrumb,
18+
className
19+
])
20+
</script>
21+
22+
<ul class={classes}>
23+
{#each items as item, index}
24+
<li>
25+
<ConditionalWrapper
26+
condition={!!(item.href && index !== items.length - 1)}
27+
element="a"
28+
href={item.href}
29+
target={item.target}
30+
>
31+
{#if item.icon}
32+
{@html item.icon}
33+
{/if}
34+
{#if item.label}
35+
{item.label}
36+
{/if}
37+
</ConditionalWrapper>
38+
</li>
39+
{#if index < items.length - 1 }
40+
<li>
41+
{@html separator || ArrowRight}
42+
</li>
43+
{/if}
44+
{/each}
45+
</ul>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React from 'react'
2+
import type { BreadcrumbProps } from './breadcrumb'
3+
4+
import ConditionalWrapper from '../ConditionalWrapper/ConditionalWrapper.tsx'
5+
6+
import { classNames } from '../../utils/classNames'
7+
8+
import ArrowRight from '../../icons/arrow-right.svg?raw'
9+
10+
import styles from './breadcrumb.module.scss'
11+
12+
const Breadcrumb = ({
13+
items,
14+
separator,
15+
className
16+
}: BreadcrumbProps) => {
17+
const classes = classNames([
18+
styles.breadcrumb,
19+
className
20+
])
21+
22+
return (
23+
<ul className={classes}>
24+
{items?.map((item, index) => (
25+
<React.Fragment key={index}>
26+
<li>
27+
<ConditionalWrapper
28+
condition={!!(item.href && index !== items.length - 1)}
29+
wrapper={children => (
30+
<a href={item.href} target={item.target}>{children}</a>
31+
)}
32+
>
33+
{item.icon && <span dangerouslySetInnerHTML={{ __html: item.icon }} />}
34+
{item.label}
35+
</ConditionalWrapper>
36+
</li>
37+
{index < items.length - 1 && (
38+
<li>
39+
{separator
40+
? separator
41+
: <span dangerouslySetInnerHTML={{ __html: ArrowRight }} />
42+
}
43+
</li>
44+
)}
45+
</React.Fragment>
46+
))}
47+
</ul>
48+
)
49+
}
50+
51+
export default Breadcrumb
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@import '../../scss/config.scss';
2+
3+
.breadcrumb {
4+
@include layout(flex, v-center, sm, wrap);
5+
@include spacing(0);
6+
7+
list-style-type: none;
8+
9+
li {
10+
@include layout(flex, v-center, xs);
11+
@include spacing(m0);
12+
13+
a {
14+
@include layout(flex, v-center, xs);
15+
@include typography(none, primary-20);
16+
17+
&:hover {
18+
@include typography(primary);
19+
}
20+
}
21+
}
22+
23+
svg {
24+
@include size(14px);
25+
}
26+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export type BreadcrumbProps = {
2+
items: {
3+
icon?: string
4+
label?: string
5+
href?: string
6+
target?: '_self' | '_blank' | '_parent' | '_top' | '_unfencedTop'
7+
}[]
8+
separator?: string
9+
className?: string
10+
}

src/data.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import successIcon from './icons/circle-check.svg?raw'
2+
import componentsIcon from './icons/components.svg?raw'
3+
import fileIcon from './icons/file.svg?raw'
24
import gitHubIcon from './icons/github.svg?raw'
5+
import homeIcon from './icons/home.svg?raw'
36
import infoIcon from './icons/info.svg?raw'
47
import moonIcon from './icons/moon.svg?raw'
58

@@ -235,3 +238,27 @@ export const dataTableEntries = [
235238
['#11', '121', 'inactive'],
236239
['#12', '160', 'inactive']
237240
]
241+
242+
export const breadcrumbs = [
243+
{ label: 'Home', href: '/' },
244+
{ label: 'Docs', href: '/docs' },
245+
{ label: 'Components', href: '/docs/components' }
246+
]
247+
248+
export const breadcrumbsWithIcon = [
249+
{ icon: homeIcon, href: '/' },
250+
{ label: 'Docs', href: '/docs' },
251+
{ label: 'Components', href: '/docs/components' }
252+
]
253+
254+
export const breadcrumbsWithIcons = [
255+
{ icon: homeIcon, label: 'Home', href: '/' },
256+
{ icon: fileIcon, label: 'Docs', href: '/docs' },
257+
{ icon: componentsIcon, label: 'Components', href: '/docs/components' }
258+
]
259+
260+
export const breadcrumbsWithIconsOnly = [
261+
{ icon: homeIcon, href: '/' },
262+
{ icon: fileIcon, href: '/docs' },
263+
{ icon: componentsIcon, href: '/docs/components' }
264+
]

src/pages/breadcrumb.astro

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
---
2+
import ComponentWrapper from '@static/ComponentWrapper.astro'
3+
import Layout from '@static/Layout.astro'
4+
5+
import AstroBreadcrumb from '@components/Breadcrumb/Breadcrumb.astro'
6+
import SvelteBreadcrumb from '@components/Breadcrumb/Breadcrumb.svelte'
7+
import ReactBreadcrumb from '@components/Breadcrumb/Breadcrumb.tsx'
8+
9+
import { getSections } from '@helpers'
10+
import {
11+
breadcrumbs,
12+
breadcrumbsWithIcon,
13+
breadcrumbsWithIcons,
14+
breadcrumbsWithIconsOnly
15+
} from '@data'
16+
17+
const sections = getSections({
18+
title: 'breadcrumbs',
19+
components: [AstroBreadcrumb, SvelteBreadcrumb, ReactBreadcrumb]
20+
})
21+
---
22+
23+
<Layout>
24+
<h1>Breadcrumb</h1>
25+
<div class="grid md-2 lg-3">
26+
<ComponentWrapper type="Astro">
27+
<AstroBreadcrumb items={[
28+
{ icon: 'home', href: '/' },
29+
breadcrumbsWithIcon[1],
30+
breadcrumbsWithIcon[2]
31+
]} />
32+
</ComponentWrapper>
33+
34+
<ComponentWrapper type="Svelte">
35+
<SvelteBreadcrumb items={breadcrumbsWithIcon} />
36+
</ComponentWrapper>
37+
38+
<ComponentWrapper type="React">
39+
<ReactBreadcrumb items={breadcrumbsWithIcon} />
40+
</ComponentWrapper>
41+
</div>
42+
43+
{sections.map(section => (
44+
<h1>{section.title}</h1>
45+
<Fragment>
46+
{section.subTitle && <h2 set:html={section.subTitle} />}
47+
</Fragment>
48+
<div class="grid md-2 lg-3">
49+
<ComponentWrapper title="Default">
50+
<section.component items={breadcrumbs} />
51+
</ComponentWrapper>
52+
53+
<ComponentWrapper title="Breadcrumb with icons">
54+
<section.component items={breadcrumbsWithIcons} />
55+
</ComponentWrapper>
56+
57+
<ComponentWrapper title="Breadcrumb with icons only">
58+
<section.component items={breadcrumbsWithIconsOnly} />
59+
</ComponentWrapper>
60+
61+
<ComponentWrapper title="Breadcrumb with one element">
62+
<section.component items={[breadcrumbs[0]]} />
63+
</ComponentWrapper>
64+
65+
<ComponentWrapper title="Breadcrumb with separator">
66+
<section.component
67+
items={breadcrumbsWithIcons}
68+
separator="/"
69+
/>
70+
</ComponentWrapper>
71+
</div>
72+
))}
73+
</Layout>

src/pages/index.astro

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Accordion from '@components/Accordion/Accordion.astro'
88
import Alert from '@components/Alert/Alert.astro'
99
import Avatar from '@components/Avatar/Avatar.astro'
1010
import Badge from '@components/Badge/Badge.astro'
11+
import Breadcrumb from '@components/Breadcrumb/Breadcrumb.astro'
1112
import Button from '@components/Button/Button.astro'
1213
import Carousel from '@components/Carousel/Carousel.astro'
1314
import Checkbox from '@components/Checkbox/Checkbox.astro'
@@ -102,6 +103,13 @@ const tabItems = [{
102103
<CardWrapper title="Badge" href="/badge">
103104
<Badge theme="outline">Badge</Badge>
104105
</CardWrapper>
106+
<CardWrapper title="Breadcrumb" href="/breadcrumb">
107+
<Breadcrumb items={[
108+
{ icon: 'home' },
109+
{ label: 'Docs' },
110+
{ label: 'Components' }
111+
]} />
112+
</CardWrapper>
105113
<CardWrapper title="Button" href="/button">
106114
<Button>Primary</Button>
107115
<Button theme="secondary">Secondary</Button>

0 commit comments

Comments
 (0)