Skip to content

Commit 495ce1e

Browse files
committed
✨ Add Sidebar component
1 parent f9e98e7 commit 495ce1e

File tree

12 files changed

+390
-42
lines changed

12 files changed

+390
-42
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ import { Accordion } from 'webcoreui/react'
220220
- [Rating](https://github.com/Frontendland/webcoreui/tree/main/src/components/Rating)
221221
- [Select](https://github.com/Frontendland/webcoreui/tree/main/src/components/Select)
222222
- [Sheet](https://github.com/Frontendland/webcoreui/tree/main/src/components/Sheet)
223+
- [Sidebar](https://github.com/Frontendland/webcoreui/tree/main/src/components/Sidebar)
223224
- [Slider](https://github.com/Frontendland/webcoreui/tree/main/src/components/Slider)
224225
- [Spinner](https://github.com/Frontendland/webcoreui/tree/main/src/components/Spinner)
225226
- [Switch](https://github.com/Frontendland/webcoreui/tree/main/src/components/Switch)
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
import type { SidebarProps } from './sidebar'
3+
4+
import Badge from '../Badge/Badge.astro'
5+
import Icon from '../Icon/Icon.astro'
6+
7+
import styles from './sidebar.module.scss'
8+
9+
import type { IconProps } from '../Icon/icon'
10+
11+
interface Props extends SidebarProps {}
12+
13+
const {
14+
groups,
15+
className
16+
} = Astro.props
17+
18+
const classes = [
19+
styles.sidebar,
20+
className
21+
]
22+
---
23+
24+
<aside class:list={classes}>
25+
{groups.map(group => (
26+
<Fragment>
27+
{group.title && (
28+
<strong>{group.title}</strong>
29+
)}
30+
31+
<ul>
32+
{group.items.map(item => (
33+
<li>
34+
<a
35+
href={item.href}
36+
target={item.target}
37+
class:list={[item.active && styles.active]}
38+
>
39+
{item.icon && (
40+
<Fragment>
41+
{item.icon.startsWith('<svg')
42+
? <Fragment set:html={item.icon} />
43+
: <Icon type={item.icon as IconProps['type']} />
44+
}
45+
</Fragment>
46+
)}
47+
{item.name}
48+
{item.badge && (
49+
<Badge theme={item.badgeTheme || 'success'} small={true}>
50+
{item.badge}
51+
</Badge>
52+
)}
53+
</a>
54+
</li>
55+
))}
56+
</ul>
57+
</Fragment>
58+
))}
59+
60+
<slot />
61+
</aside>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<script lang="ts">
2+
import type { SidebarProps } from './sidebar'
3+
4+
import Badge from '../Badge/Badge.svelte'
5+
6+
import { classNames } from '../../utils/classNames'
7+
8+
import styles from './sidebar.module.scss'
9+
10+
export let groups: SidebarProps['groups'] = []
11+
export let className: SidebarProps['className'] = ''
12+
13+
const classes = classNames([
14+
styles.sidebar,
15+
className
16+
])
17+
</script>
18+
19+
<aside class={classes}>
20+
{#each groups as group}
21+
22+
{#if group.title}
23+
<strong>{group.title}</strong>
24+
{/if}
25+
26+
<ul>
27+
{#each group.items as item}
28+
<li>
29+
<a
30+
href={item.href}
31+
target={item.target}
32+
class={item.active ? styles.active : undefined}
33+
>
34+
{#if item.icon}
35+
{@html item.icon}
36+
{/if}
37+
{item.name}
38+
{#if item.badge}
39+
<Badge theme={item.badgeTheme || 'success'} small={true}>
40+
{item.badge}
41+
</Badge>
42+
{/if}
43+
</a>
44+
</li>
45+
{/each}
46+
</ul>
47+
{/each}
48+
49+
<slot />
50+
</aside>

src/components/Sidebar/Sidebar.tsx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import React from 'react'
2+
import type { ReactSidebarProps } from './sidebar'
3+
4+
import Badge from '../Badge/Badge.tsx'
5+
6+
import { classNames } from '../../utils/classNames'
7+
8+
import styles from './sidebar.module.scss'
9+
10+
const Sidebar = ({
11+
groups,
12+
children,
13+
className
14+
}: ReactSidebarProps) => {
15+
const classes = classNames([
16+
styles.sidebar,
17+
className
18+
])
19+
20+
return (
21+
<aside className={classes}>
22+
{groups.map((group, groupIndex) => (
23+
<React.Fragment key={groupIndex}>
24+
{group.title && (
25+
<strong>{group.title}</strong>
26+
)}
27+
28+
<ul>
29+
{group.items.map((item, itemIndex) => (
30+
<li key={itemIndex}>
31+
<a
32+
href={item.href}
33+
target={item.target}
34+
className={item.active ? styles.active : undefined}
35+
>
36+
{item.icon && (
37+
<span dangerouslySetInnerHTML={{ __html: item.icon }} />
38+
)}
39+
{item.name}
40+
{item.badge && (
41+
<Badge theme={item.badgeTheme || 'success'} small={true}>
42+
{item.badge}
43+
</Badge>
44+
)}
45+
</a>
46+
</li>
47+
))}
48+
</ul>
49+
</React.Fragment>
50+
))}
51+
52+
{children}
53+
</aside>
54+
)
55+
}
56+
57+
export default Sidebar
58+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
@import '../../scss/config.scss';
2+
3+
.sidebar {
4+
5+
strong {
6+
@include spacing(mb-sm);
7+
8+
display: block;
9+
}
10+
11+
ul {
12+
@include layout(flex, column, sm);
13+
@include typography(normal);
14+
@include spacing(0);
15+
16+
list-style-type: none;
17+
18+
&:not(:last-child) {
19+
@include spacing('mb-3xl');
20+
}
21+
22+
li {
23+
@include spacing(m0);
24+
}
25+
26+
a {
27+
@include typography(primary-20, none);
28+
@include layout(flex, v-center, sm);
29+
30+
&:hover {
31+
@include typography(primary);
32+
}
33+
34+
&.active {
35+
@include typography(primary);
36+
}
37+
38+
svg {
39+
@include size(18px);
40+
}
41+
}
42+
}
43+
}

src/components/Sidebar/sidebar.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { ButtonProps } from '../Button/button'
2+
3+
export type SidebarProps = {
4+
groups: {
5+
title?: string
6+
items: {
7+
name: string
8+
href: string
9+
target?: ButtonProps['target']
10+
active?: boolean
11+
icon?: string
12+
badge?: string
13+
badgeTheme?: ButtonProps['theme']
14+
}[]
15+
}[]
16+
className?: string
17+
}
18+
19+
export type ReactSidebarProps = {
20+
children?: React.ReactNode
21+
} & SidebarProps

src/data.js renamed to src/data.ts

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/* eslint-disable max-lines */
2+
import type { ButtonProps } from '@components/Button/button'
3+
14
import successIcon from './icons/circle-check.svg?raw'
25
import componentsIcon from './icons/components.svg?raw'
36
import fileIcon from './icons/file.svg?raw'
@@ -263,34 +266,64 @@ export const breadcrumbsWithIconsOnly = [
263266
{ icon: componentsIcon, href: '/docs/components' }
264267
]
265268

266-
export const footerColumn1 = [{
269+
export const itemGroup1 = [{
267270
items: [
268271
{ name: 'Home', href: '#' },
269272
{ name: 'Docs', href: '#' },
270273
{ name: 'Component', href: '#' }
271274
]
272275
}]
273276

274-
export const footerColumn2 = [{
277+
export const itemGroup2 = [{
275278
items: [
276279
{ name: 'CSS Config', href: '#' },
277280
{ name: 'Styles', href: '#' },
278281
{ name: 'Utilities', href: '#' }
279282
]
280283
}]
281284

282-
export const footerColumns = [
283-
{ items: footerColumn1[0].items },
284-
{ items: footerColumn2[0].items }
285+
export const itemGroups = [
286+
{ items: itemGroup1[0].items },
287+
{ items: itemGroup2[0].items }
285288
]
286289

287-
export const footerColumnsWithTitle = [
290+
export const itemGroupsWithTitle = [
288291
{
289292
title: 'SITEMAP',
290-
items: footerColumn1[0].items
293+
items: itemGroup1[0].items
294+
},
295+
{
296+
title: 'THEMES',
297+
items: itemGroup2[0].items
298+
}
299+
]
300+
301+
export const itemGroupsWithBadges = [
302+
{
303+
title: 'SITEMAP',
304+
items: [
305+
{ name: 'Home', href: '#' },
306+
{ name: 'Docs', href: '#', badge: 'updated', badgeTheme: 'info' as ButtonProps['theme'] },
307+
{ name: 'Component', href: '#', badge: 'new components' }
308+
]
309+
},
310+
{
311+
title: 'THEMES',
312+
items: itemGroup2[0].items
313+
}
314+
]
315+
316+
export const itemGroupsWithIcons = [
317+
{
318+
title: 'SITEMAP',
319+
items: [
320+
{ name: 'Home', href: '#', icon: gitHubIcon, target: '_blank' as any },
321+
{ name: 'Docs', href: '#', badge: 'updated', badgeTheme: 'info' as ButtonProps['theme'], icon: fileIcon },
322+
{ name: 'Component', href: '#', badge: 'new components', icon: componentsIcon, active: true }
323+
]
291324
},
292325
{
293326
title: 'THEMES',
294-
items: footerColumn2[0].items
327+
items: itemGroup2[0].items
295328
}
296329
]

0 commit comments

Comments
 (0)