Skip to content

Commit 4d663b1

Browse files
committed
✨Add Empty block
1 parent 9f7c44c commit 4d663b1

File tree

9 files changed

+265
-1
lines changed

9 files changed

+265
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ import { Accordion } from 'webcoreui/react'
336336
- [BlogCard](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/BlogCard)
337337
- [ComponentMap](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/ComponentMap)
338338
- [DeviceMockup](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/DeviceMockup)
339+
- [Empty](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/Empty)
339340
- [ErrorPage](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/ErrorPage)
340341
- [ExpandableTable](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/ExpandableTable)
341342
- [FAQ](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/FAQ)

src/blocks/Empty/Empty.astro

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
import { Icon } from 'webcoreui/astro'
3+
4+
import Button from '@blocks/Button/Button.astro'
5+
6+
import type { EmptyProps } from './empty'
7+
import styles from './empty.module.scss'
8+
9+
interface Props extends EmptyProps {}
10+
11+
const {
12+
icon,
13+
iconWithBackground,
14+
title,
15+
text,
16+
buttons,
17+
className
18+
} = Astro.props
19+
20+
const classes = [
21+
'flex column center xs',
22+
iconWithBackground && styles['icon-bg'],
23+
styles.empty,
24+
className
25+
]
26+
---
27+
28+
<section class:list={classes}>
29+
{icon && (
30+
<Fragment>
31+
{icon.startsWith('<svg')
32+
? <Fragment set:html={icon} />
33+
: <Icon type={icon} size={28} />
34+
}
35+
</Fragment>
36+
)}
37+
38+
<b class={styles.title}>{title}</b>
39+
40+
<div class:list={[styles.text, 'muted']} set:html={text} />
41+
42+
{!!buttons?.length && (
43+
<div class="flex xs wrap justify-center">
44+
{buttons?.map(button => (
45+
<Button {...button} />
46+
))}
47+
</div>
48+
)}
49+
</section>

src/blocks/Empty/Empty.svelte

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<script lang="ts">
2+
import Button from '@blocks/Button/Button.svelte'
3+
4+
import type { EmptyProps } from './empty'
5+
import styles from './empty.module.scss'
6+
7+
import { classNames } from '../../utils/classNames'
8+
9+
const {
10+
icon,
11+
iconWithBackground,
12+
title,
13+
text,
14+
buttons,
15+
className
16+
}: EmptyProps = $props()
17+
18+
const classes = classNames([
19+
'flex column center xs',
20+
iconWithBackground && styles['icon-bg'],
21+
styles.empty,
22+
className
23+
])
24+
</script>
25+
26+
<section class={classes}>
27+
{#if icon}
28+
{@html icon}
29+
{/if}
30+
31+
<b class={styles.title}>{title}</b>
32+
33+
<div class={classNames([styles.text, 'muted'])}>
34+
{@html text}
35+
</div>
36+
37+
{#if buttons?.length}
38+
<div class="flex xs wrap justify-center">
39+
{#each buttons as button}
40+
<Button {...button} />
41+
{/each}
42+
</div>
43+
{/if}
44+
</section>

src/blocks/Empty/Empty.tsx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React from 'react'
2+
3+
import Button from '@blocks/Button/Button.tsx'
4+
5+
import type { EmptyProps } from './empty'
6+
import styles from './empty.module.scss'
7+
8+
import { classNames } from '../../utils/classNames'
9+
10+
const Empty = ({
11+
icon,
12+
iconWithBackground,
13+
title,
14+
text,
15+
buttons,
16+
className
17+
}: EmptyProps) => {
18+
const classes = classNames([
19+
'flex column center xs',
20+
iconWithBackground && styles['icon-bg'],
21+
styles.empty,
22+
className
23+
])
24+
25+
return (
26+
<section className={classes}>
27+
{icon && (
28+
<span dangerouslySetInnerHTML={{ __html: icon }} />
29+
)}
30+
31+
<b className={styles.title}>{title}</b>
32+
33+
<div
34+
className={classNames([styles.text, 'muted'])}
35+
dangerouslySetInnerHTML={{ __html: text }}
36+
/>
37+
38+
{!!buttons?.length && (
39+
<div className="flex xs wrap justify-center">
40+
{buttons?.map((button, index) => (
41+
<Button {...button} key={index} />
42+
))}
43+
</div>
44+
)}
45+
</section>
46+
)
47+
}
48+
49+
export default Empty

src/blocks/Empty/empty.module.scss

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
@use '../../scss/config.scss' as *;
2+
3+
.empty {
4+
&.icon-bg svg {
5+
@include background(primary-50);
6+
@include border-radius(xl);
7+
@include size(56px);
8+
@include spacing(p-md);
9+
}
10+
11+
svg {
12+
@include size(28px);
13+
@include spacing(mb-sm);
14+
}
15+
}
16+
17+
.text {
18+
@include spacing(my-sm);
19+
}

src/blocks/Empty/empty.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type {
2+
ButtonProps,
3+
IconProps
4+
} from 'webcoreui/astro'
5+
6+
export type EmptyProps = {
7+
icon?: IconProps['type'] | string
8+
iconWithBackground?: boolean
9+
title: string
10+
text: string
11+
buttons?: ({
12+
text: string
13+
icon?: IconProps['type'] | string
14+
} & ButtonProps)[]
15+
className?: string
16+
}

src/data.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,3 +911,12 @@ export const members = [
911911
description: 'Fiona manages the deployment pipelines and cloud infrastructure, making sure our applications are scalable, secure, and run smoothly.'
912912
}
913913
]
914+
915+
export const emptyProps = {
916+
icon: fileIcon,
917+
title: 'No documents found',
918+
text: 'You haven\'t created any documents yet. <br /> Get started by creating your first one.',
919+
buttons: [
920+
{ text: 'Create New' }
921+
]
922+
}

src/pages/blocks/empty.astro

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
---
2+
import ComponentWrapper from '@static/ComponentWrapper.astro'
3+
import Layout from '@static/Layout.astro'
4+
5+
import AstroEmpty from '@blocks/Empty/Empty.astro'
6+
import SvelteEmpty from '@blocks/Empty/Empty.svelte'
7+
import ReactEmpty from '@blocks/Empty/Empty.tsx'
8+
9+
import { getSections } from '@helpers'
10+
import { emptyProps } from '@data'
11+
12+
const sections = getSections({
13+
title: 'empty',
14+
components: [AstroEmpty, SvelteEmpty, ReactEmpty]
15+
})
16+
---
17+
18+
<Layout>
19+
<h1>Empty</h1>
20+
<h2>
21+
<a href="/blocks">
22+
{'<-'} Back to all blocks
23+
</a>
24+
</h2>
25+
26+
<div class="grid md-2 lg-3">
27+
<ComponentWrapper type="Astro">
28+
<AstroEmpty {...emptyProps} />
29+
</ComponentWrapper>
30+
31+
<ComponentWrapper type="Svelte">
32+
<SvelteEmpty {...emptyProps} />
33+
</ComponentWrapper>
34+
35+
<ComponentWrapper type="React">
36+
<ReactEmpty {...emptyProps} />
37+
</ComponentWrapper>
38+
</div>
39+
40+
{sections.map(section => (
41+
<h1>{section.title}</h1>
42+
<Fragment>
43+
{section.subTitle && <h2 set:html={section.subTitle} />}
44+
</Fragment>
45+
<div class="grid md-2 lg-3">
46+
<ComponentWrapper title="Required props only">
47+
<section.component
48+
title={emptyProps.title}
49+
text={emptyProps.text}
50+
/>
51+
</ComponentWrapper>
52+
53+
<ComponentWrapper title="With icon">
54+
<section.component
55+
icon={emptyProps.icon}
56+
title={emptyProps.title}
57+
text={emptyProps.text}
58+
/>
59+
</ComponentWrapper>
60+
61+
<ComponentWrapper title="Icon with background">
62+
<section.component
63+
icon={emptyProps.icon}
64+
iconWithBackground={true}
65+
title={emptyProps.title}
66+
text={emptyProps.text}
67+
/>
68+
</ComponentWrapper>
69+
</div>
70+
))}
71+
</Layout>

src/pages/blocks/index.astro

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import AvatarWithRating from '@blocks/AvatarWithRating/AvatarWithRating.astro'
99
import BlogCard from '@blocks/BlogCard/BlogCard.astro'
1010
import ComponentMap from '@blocks/ComponentMap/ComponentMap.astro'
1111
import DeviceMockup from '@blocks/DeviceMockup/DeviceMockup.astro'
12+
import Empty from '@blocks/Empty/Empty.astro'
1213
import ErrorPage from '@blocks/ErrorPage/ErrorPage.astro'
1314
import ExpandableTable from '@blocks/ExpandableTable/ExpandableTable.astro'
1415
import FAQ from '@blocks/FAQ/FAQ.astro'
@@ -26,7 +27,7 @@ import Team from '@blocks/Team/Team.astro'
2627
import Tiles from '@blocks/Tiles/Tiles.astro'
2728
import User from '@blocks/User/User.astro'
2829
29-
import { avatarGroup, gridWithIconsItems, members } from '@data'
30+
import { avatarGroup, emptyProps, gridWithIconsItems, members } from '@data'
3031
---
3132

3233
<Layout docs="/blocks/introduction">
@@ -188,6 +189,11 @@ import { avatarGroup, gridWithIconsItems, members } from '@data'
188189
</div>
189190
</DeviceMockup>
190191

192+
<Card title="Empty">
193+
<Empty {...emptyProps} />
194+
<Link href="/blocks/empty" />
195+
</Card>
196+
191197
<Card title="Expandable table" secondary={true}>
192198
<ExpandableTable
193199
headings={['ID', 'Name']}

0 commit comments

Comments
 (0)