Skip to content

Commit 5b526cc

Browse files
wahyufebWahyu Febriantogioboa
authored
feat(component): add new Breadcrumb component (#212)
* feat(component): add new Breadcrumb component Add Breadcrumb component (headless and daisy) and Breadcrumb component website docs * style: change style on headless breadcrumb component --------- Co-authored-by: Wahyu Febrianto <[email protected]> Co-authored-by: Giorgio Boa <[email protected]>
1 parent dfd89e0 commit 5b526cc

File tree

19 files changed

+410
-0
lines changed

19 files changed

+410
-0
lines changed

apps/website/src/components/menu/menu.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ export const Menu = component$<Props>(({ onClose$ }) => {
1919
label: 'Alert',
2020
path: `/docs/${appState.theme.toLowerCase()}/alert`,
2121
},
22+
{
23+
label: 'Breadcrumb',
24+
path: `/docs/${appState.theme.toLowerCase()}/breadcrumb`,
25+
},
2226
{ label: 'Button', path: `/docs/${appState.theme.toLowerCase()}/button` },
2327
{
2428
label: 'ButtonGroup',
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { component$, Slot } from '@builder.io/qwik';
2+
3+
export default component$((props: { title?: string; class?: string }) => {
4+
return (
5+
<div class={props.class || ''}>
6+
{props.title && <h1 class="mt-8 mb-4">{props.title}</h1>}
7+
<div class="dark:bg-slate-900 bg-slate-200 rounded p-3">
8+
<Slot />
9+
</div>
10+
</div>
11+
);
12+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { component$ } from '@builder.io/qwik';
2+
3+
export default component$(() => {
4+
return (
5+
<svg
6+
xmlns="http://www.w3.org/2000/svg"
7+
fill="none"
8+
viewBox="0 0 24 24"
9+
class="w-4 h-4 mr-2 stroke-current"
10+
>
11+
<path
12+
strokeLinecap="round"
13+
strokeLinejoin="round"
14+
strokeWidth="2"
15+
d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"
16+
></path>
17+
</svg>
18+
);
19+
});
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { component$ } from '@builder.io/qwik';
2+
import { useLocation } from '@builder.io/qwik-city';
3+
import { Breadcrumb, BreadcrumbItem } from '@qwik-ui/theme-daisy';
4+
import BreadcrumbWrapper from './BreadcrumbWrapper';
5+
import PathIcon from './PathIcon';
6+
7+
interface BreadcrumbPath {
8+
name: string;
9+
path: string;
10+
}
11+
12+
export default component$(() => {
13+
const { url } = useLocation();
14+
15+
const breadcrumbPath: BreadcrumbPath[] = url.pathname
16+
.split('/')
17+
.filter((path) => path)
18+
.map((path, indexPath, arrPath) => {
19+
return {
20+
name: path,
21+
path:
22+
indexPath > 0
23+
? `/${arrPath
24+
.filter((_, indexPath2) => indexPath2 < indexPath)
25+
.join('/')}/${arrPath[indexPath]}/`
26+
: `/${path}/`,
27+
};
28+
});
29+
30+
return (
31+
<div>
32+
<h2>This is the documentation for the Breadcrumb</h2>
33+
34+
<BreadcrumbWrapper title="Breadcrumb Example">
35+
<Breadcrumb>
36+
{breadcrumbPath.map((itemBreadcrumb, index) => (
37+
<BreadcrumbItem key={index}>{itemBreadcrumb.name}</BreadcrumbItem>
38+
))}
39+
</Breadcrumb>
40+
</BreadcrumbWrapper>
41+
42+
<BreadcrumbWrapper title="Breadcrumb with Icon Example">
43+
<Breadcrumb>
44+
{breadcrumbPath.map((itemBreadcrumb, index) => (
45+
<BreadcrumbItem key={index}>
46+
<a
47+
href={`${itemBreadcrumb.path}`}
48+
class="inline-flex items-center hover:underline"
49+
>
50+
<PathIcon />
51+
<span>{itemBreadcrumb.name}</span>
52+
</a>
53+
</BreadcrumbItem>
54+
))}
55+
</Breadcrumb>
56+
</BreadcrumbWrapper>
57+
58+
<BreadcrumbWrapper title="Breadcrumb with Active Example">
59+
<Breadcrumb>
60+
{breadcrumbPath.map((itemBreadcrumb, index) => (
61+
<BreadcrumbItem
62+
key={index}
63+
class={itemBreadcrumb.path === url.pathname ? 'text-primary' : ''}
64+
>
65+
{itemBreadcrumb.name}
66+
</BreadcrumbItem>
67+
))}
68+
</Breadcrumb>
69+
</BreadcrumbWrapper>
70+
71+
<BreadcrumbWrapper class="mt-4">
72+
<Breadcrumb>
73+
{breadcrumbPath.map((itemBreadcrumb, index) => (
74+
<BreadcrumbItem key={index}>
75+
<a
76+
href={`${itemBreadcrumb.path}`}
77+
class={`inline-flex items-center hover:underline ${
78+
itemBreadcrumb.path === url.pathname ? 'text-primary' : ''
79+
}`}
80+
>
81+
<PathIcon />
82+
<span>{itemBreadcrumb.name}</span>
83+
</a>
84+
</BreadcrumbItem>
85+
))}
86+
</Breadcrumb>
87+
</BreadcrumbWrapper>
88+
</div>
89+
);
90+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[data-theme='light'] {
2+
--wrapper-color-bg: rgb(226 232 240);
3+
}
4+
5+
[data-theme='dark'] {
6+
--wrapper-color-bg: rgb(15 23 42);
7+
}
8+
9+
.wrapper__title {
10+
margin-top: 2rem;
11+
margin-bottom: 1rem;
12+
}
13+
14+
.wrapper__content {
15+
background-color: var(--wrapper-color-bg) !important;
16+
border-radius: 0.25rem;
17+
padding: 0.75rem;
18+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { component$, HTMLAttributes, Slot, useStyles$ } from '@builder.io/qwik';
2+
import style from './BreadcrumbWrapper.css?inline';
3+
4+
interface BreadcrumbWrapperProps extends HTMLAttributes<HTMLElement> {
5+
title?: string;
6+
}
7+
8+
export default component$(({ title, ...rest }: BreadcrumbWrapperProps) => {
9+
useStyles$(style);
10+
11+
return (
12+
<div {...rest}>
13+
{title && <h1 class="wrapper__title">{title}</h1>}
14+
<div class="wrapper__content">
15+
<Slot />
16+
</div>
17+
</div>
18+
);
19+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { component$, useStylesScoped$ } from '@builder.io/qwik';
2+
3+
export default component$(() => {
4+
useStylesScoped$(`
5+
svg { width: 1rem;height:1rem;stroke:currentColor;margin-right:0.5rem; }
6+
`);
7+
8+
return (
9+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
10+
<path
11+
strokeLinecap="round"
12+
strokeLinejoin="round"
13+
strokeWidth="2"
14+
d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"
15+
></path>
16+
</svg>
17+
);
18+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
.breadcrumb-item {
2+
display: inline-flex;
3+
align-items: center;
4+
}
5+
6+
.breadcrumb-item:hover {
7+
text-decoration: underline;
8+
}
9+
10+
.breadcrumb-item--hovered:hover {
11+
text-decoration: underline;
12+
color: hsl(258.89 94.378% 51.176%);
13+
}
14+
15+
.breadcrumb-item--active {
16+
color: hsl(258.89 94.378% 51.176%);
17+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { component$, useStylesScoped$ } from '@builder.io/qwik';
2+
import { useLocation } from '@builder.io/qwik-city';
3+
import { Breadcrumb, BreadcrumbItem } from '@qwik-ui/headless';
4+
import BreadcrumbWrapper from './BreadcrumbWrapper';
5+
import PathIcon from './PathIcon';
6+
import style from './index.css?inline';
7+
8+
interface BreadcrumbPath {
9+
name: string;
10+
path: string;
11+
}
12+
13+
export default component$(() => {
14+
const { url } = useLocation();
15+
16+
const breadcrumbPath: BreadcrumbPath[] = url.pathname
17+
.split('/')
18+
.filter((path) => path)
19+
.map((path, indexPath, arrPath) => {
20+
return {
21+
name: path,
22+
path:
23+
indexPath > 0
24+
? `/${arrPath
25+
.filter((_, indexPath2) => indexPath2 < indexPath)
26+
.join('/')}/${arrPath[indexPath]}/`
27+
: `/${path}/`,
28+
};
29+
});
30+
31+
useStylesScoped$(style);
32+
33+
return (
34+
<div>
35+
<h2>This is the documentation for the Breadcrumb</h2>
36+
37+
<BreadcrumbWrapper title="Breadcrumb Example">
38+
<Breadcrumb>
39+
{breadcrumbPath.map((itemBreadcrumb, index) => (
40+
<BreadcrumbItem key={index}>{itemBreadcrumb.name}</BreadcrumbItem>
41+
))}
42+
</Breadcrumb>
43+
</BreadcrumbWrapper>
44+
45+
<BreadcrumbWrapper title="Breadcrumb with Icon Example">
46+
<Breadcrumb>
47+
{breadcrumbPath.map((itemBreadcrumb, index) => (
48+
<BreadcrumbItem key={index}>
49+
<a href={`${itemBreadcrumb.path}`} class="breadcrumb-item">
50+
<PathIcon />
51+
<span>{itemBreadcrumb.name}</span>
52+
</a>
53+
</BreadcrumbItem>
54+
))}
55+
</Breadcrumb>
56+
</BreadcrumbWrapper>
57+
58+
<BreadcrumbWrapper title="Breadcrumb with Active Example">
59+
<Breadcrumb>
60+
{breadcrumbPath.map((itemBreadcrumb, index) => (
61+
<BreadcrumbItem
62+
key={index}
63+
class={
64+
itemBreadcrumb.path === url.pathname
65+
? 'breadcrumb-item--active'
66+
: ''
67+
}
68+
>
69+
{itemBreadcrumb.name}
70+
</BreadcrumbItem>
71+
))}
72+
</Breadcrumb>
73+
</BreadcrumbWrapper>
74+
75+
<BreadcrumbWrapper style={{ marginTop: '1rem' }}>
76+
<Breadcrumb>
77+
{breadcrumbPath.map((itemBreadcrumb, index) => (
78+
<BreadcrumbItem key={index}>
79+
<a
80+
href={`${itemBreadcrumb.path}`}
81+
class={`breadcrumb-item ${
82+
itemBreadcrumb.path === url.pathname
83+
? 'breadcrumb-item--active'
84+
: ''
85+
}`}
86+
>
87+
<PathIcon />
88+
<span>{itemBreadcrumb.name}</span>
89+
</a>
90+
</BreadcrumbItem>
91+
))}
92+
</Breadcrumb>
93+
</BreadcrumbWrapper>
94+
95+
<BreadcrumbWrapper title="Breadcrumb with Custom Divider Example">
96+
<Breadcrumb>
97+
{breadcrumbPath.map((itemBreadcrumb, index) => (
98+
<BreadcrumbItem key={index} divider="→">
99+
<a
100+
href={`${itemBreadcrumb.path}`}
101+
class="breadcrumb-item--hovered"
102+
>
103+
<span>{itemBreadcrumb.name}</span>
104+
</a>
105+
</BreadcrumbItem>
106+
))}
107+
</Breadcrumb>
108+
</BreadcrumbWrapper>
109+
</div>
110+
);
111+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { component$, HTMLAttributes, Slot } from '@builder.io/qwik';
2+
import { BreadcrumbItem as HeadlessBreadcrumbItem } from '@qwik-ui/headless';
3+
4+
type BreadcrumbProps = HTMLAttributes<HTMLElement>;
5+
6+
export const BreadcrumbItem = component$((props: BreadcrumbProps) => {
7+
return (
8+
<li>
9+
<HeadlessBreadcrumbItem {...props}>
10+
<Slot />
11+
</HeadlessBreadcrumbItem>
12+
</li>
13+
);
14+
});

0 commit comments

Comments
 (0)