Skip to content

Commit 956e8a1

Browse files
committed
✨ Add GridWithIcons block
1 parent 2e18ed7 commit 956e8a1

File tree

9 files changed

+332
-0
lines changed

9 files changed

+332
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ import { Accordion } from 'webcoreui/react'
268268
- [BlogCard](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/BlogCard)
269269
- [ErrorPage](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/ErrorPage)
270270
- [FAQ](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/FAQ)
271+
- [GridWithIcons](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/GridWithIcons)
271272
- [Hero](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/Hero)
272273
- [IconList](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/IconList)
273274
- [SettingCard](https://github.com/Frontendland/webcoreui/tree/main/src/blocks/SettingCard)
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
---
2+
import type { GridWithIconsProps } from './gridWithIcons'
3+
4+
import styles from './grid-with-icons.module.scss'
5+
6+
interface Props extends GridWithIconsProps {}
7+
8+
import {
9+
ConditionalWrapper,
10+
Icon,
11+
type IconProps
12+
} from 'webcoreui/astro'
13+
14+
const {
15+
items,
16+
columns,
17+
alignment,
18+
iconWithBackground,
19+
secondary,
20+
className
21+
} = Astro.props
22+
23+
const classes = [
24+
`grid sm-${columns || 3}`,
25+
styles.list,
26+
alignment && styles[alignment],
27+
iconWithBackground && styles['icon-bg'],
28+
secondary && styles.secondary,
29+
className
30+
]
31+
32+
const wrapperClasses = [
33+
'flex sm items-center',
34+
alignment === 'center' && 'justify-center',
35+
alignment === 'right' && 'justify-end'
36+
]
37+
---
38+
39+
<ul class:list={classes}>
40+
{items?.map(item => (
41+
<li class="grid sm">
42+
<ConditionalWrapper condition={!!secondary}>
43+
<div slot="wrapper" class:list={[wrapperClasses]}>
44+
children
45+
</div>
46+
47+
{item.icon && (
48+
<Fragment>
49+
{item.icon.startsWith('<svg')
50+
? <Fragment set:html={item.icon} />
51+
: <Icon type={item.icon as IconProps['type']} />
52+
}
53+
</Fragment>
54+
)}
55+
56+
{item.title && (
57+
<strong class={styles.title}>{item.title}</strong>
58+
)}
59+
</ConditionalWrapper>
60+
<div set:html={item.text} class="muted" />
61+
</li>
62+
))}
63+
</ul>
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 { GridWithIconsProps } from './gridWithIcons'
3+
4+
import styles from './grid-with-icons.module.scss'
5+
6+
import { classNames } from 'webcoreui'
7+
import { ConditionalWrapper } from 'webcoreui/svelte'
8+
9+
export let items: GridWithIconsProps['items'] = []
10+
export let columns: GridWithIconsProps['columns'] = null
11+
export let alignment: GridWithIconsProps['alignment'] = null
12+
export let iconWithBackground: GridWithIconsProps['iconWithBackground'] = false
13+
export let secondary: GridWithIconsProps['secondary'] = false
14+
export let className: GridWithIconsProps['className'] = ''
15+
16+
const classes = classNames([
17+
`grid sm-${columns || 3}`,
18+
styles.list,
19+
alignment && styles[alignment],
20+
iconWithBackground && styles['icon-bg'],
21+
secondary && styles.secondary,
22+
className
23+
])
24+
25+
const wrapperClasses = classNames([
26+
'flex sm items-center',
27+
alignment === 'center' && 'justify-center',
28+
alignment === 'right' && 'justify-end'
29+
])
30+
</script>
31+
32+
<ul class={classes}>
33+
{#each items as item}
34+
<li class="grid sm">
35+
<ConditionalWrapper
36+
condition={!!secondary}
37+
class={wrapperClasses}
38+
>
39+
{#if item.icon}
40+
{@html item.icon}
41+
{/if}
42+
43+
{#if item.title}
44+
<strong class={styles.title}>{item.title}</strong>
45+
{/if}
46+
</ConditionalWrapper>
47+
<div class="muted">{@html item.text}</div>
48+
</li>
49+
{/each}
50+
</ul>
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import React from 'react'
2+
import type { GridWithIconsProps } from './gridWithIcons'
3+
4+
import styles from './grid-with-icons.module.scss'
5+
6+
import { classNames } from 'webcoreui'
7+
import { ConditionalWrapper } from 'webcoreui/react'
8+
9+
const GridWithIcons = ({
10+
items,
11+
columns,
12+
alignment,
13+
iconWithBackground,
14+
secondary,
15+
className
16+
}: GridWithIconsProps) => {
17+
const classes = classNames([
18+
`grid sm-${columns || 3}`,
19+
styles.list,
20+
alignment && styles[alignment],
21+
iconWithBackground && styles['icon-bg'],
22+
secondary && styles.secondary,
23+
className
24+
])
25+
26+
const wrapperClasses = classNames([
27+
'flex sm items-center',
28+
alignment === 'center' && 'justify-center',
29+
alignment === 'right' && 'justify-end'
30+
])
31+
32+
return (
33+
<ul className={classes}>
34+
{items?.map((item, index) => (
35+
<li className="grid sm" key={index}>
36+
<ConditionalWrapper
37+
condition={!!secondary}
38+
wrapper={children => (
39+
<div slot="wrapper" className={wrapperClasses}>
40+
{children}
41+
</div>
42+
)}
43+
>
44+
45+
{item.icon && (
46+
<span
47+
dangerouslySetInnerHTML={{ __html: item.icon }}
48+
style={{ height: iconWithBackground ? '34px' : '24px' }}
49+
/>
50+
)}
51+
52+
{item.title && (
53+
<strong className={styles.title}>
54+
{item.title}
55+
</strong>
56+
)}
57+
</ConditionalWrapper>
58+
<div
59+
dangerouslySetInnerHTML={{ __html: item.text }}
60+
className="muted"
61+
/>
62+
</li>
63+
))}
64+
</ul>
65+
)
66+
}
67+
68+
export default GridWithIcons
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
@use 'webcoreui/config' as *;
2+
3+
.list {
4+
@include spacing(0);
5+
list-style-type: none;
6+
7+
&.center {
8+
@include typography(center);
9+
10+
&:not(.secondary) svg {
11+
@include spacing(auto-none);
12+
}
13+
}
14+
15+
&.right {
16+
@include typography(right);
17+
18+
svg {
19+
margin-left: auto;
20+
}
21+
}
22+
23+
&.icon-bg svg {
24+
@include background(primary-50);
25+
@include border(6px, primary-50);
26+
@include border-radius(max);
27+
@include size(34px);
28+
}
29+
30+
.title {
31+
@include typography(lg);
32+
}
33+
34+
li {
35+
margin-bottom: auto;
36+
}
37+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import type { IconProps } from 'webcoreui/astro'
2+
3+
export type GridWithIconsProps = {
4+
items: {
5+
icon?: IconProps['type'] | string
6+
title?: string
7+
text: string
8+
}[]
9+
columns?: 1 | 2 | 3 | 4 | null
10+
alignment?: 'center' | 'right' | null
11+
iconWithBackground?: boolean
12+
secondary?: boolean
13+
className?: string
14+
}

src/data.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable max-len */
12
/* eslint-disable max-lines */
23
import type { ButtonProps } from '@components/Button/button'
34

@@ -8,6 +9,7 @@ import SvelteBox from '@static/Box.svelte'
89
import ReactAlert from '@components/Alert/Alert.tsx'
910
import ReactBox from '@static/Box.tsx'
1011

12+
import alertIcon from './icons/alert.svg?raw'
1113
import successIcon from './icons/circle-check.svg?raw'
1214
import componentsIcon from './icons/components.svg?raw'
1315
import fileIcon from './icons/file.svg?raw'
@@ -402,3 +404,22 @@ export const stepperWithIcons = [
402404
{ title: 'Configure', subTitle: 'Preferences', active: true, icon: gitHubIcon },
403405
{ title: 'Finish', subTitle: 'Final steps' }
404406
]
407+
408+
export const gridWithIconsItems = [{
409+
icon: componentsIcon,
410+
title: 'Grid with Icons',
411+
text: 'Use the <code>GridWithIcons</code> block to organize your list into a grid with icons to enhance clarity and visual appeal.'
412+
}, {
413+
icon: alertIcon,
414+
title: 'Configurable',
415+
text: 'You can create as many items as necessary with icons and an optional title. You can also configure the number of columns.'
416+
}, {
417+
icon: successIcon,
418+
title: 'Supports formatting',
419+
text: 'The <code>text</code> prop also supports formatting through <b>HTML</b> tags to help you customize the appearance of the element.'
420+
}, {
421+
title: 'Graceful degradation',
422+
text: 'If the <code>items</code> prop is not defined, nothing will be rendered. Grid items can be rendered without icons or titles too.'
423+
}, {
424+
text: 'This last item is created without an icon or title, meaning you can also use this block to create simple text in a grid layout.'
425+
}]
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
import ComponentWrapper from '@static/ComponentWrapper.astro'
3+
import Layout from '@static/Layout.astro'
4+
5+
import { getSections } from '@helpers'
6+
import { gridWithIconsItems } from '@data'
7+
8+
import AstroGridWithIcons from '@blocks/GridWithIcons/GridWithIcons.astro'
9+
import SvelteGridWithIcons from '@blocks/GridWithIcons/GridWithIcons.svelte'
10+
import ReactGridWithIcons from '@blocks/GridWithIcons/GridWithIcons.tsx'
11+
12+
const sections = getSections({
13+
title: '',
14+
components: [AstroGridWithIcons, SvelteGridWithIcons, ReactGridWithIcons]
15+
})
16+
---
17+
18+
<Layout>
19+
<h1>Grid with Icons</h1>
20+
<h2>
21+
<a href="/blocks">
22+
{'<-'} Back to all blocks
23+
</a>
24+
</h2>
25+
26+
{sections.map(section => (
27+
<h3>{section.title} Blocks</h3>
28+
<div class="grid">
29+
<ComponentWrapper type={section.type} title="Default">
30+
<section.component items={gridWithIconsItems} />
31+
</ComponentWrapper>
32+
33+
<ComponentWrapper type={section.type} title="Custom number of columns (2)">
34+
<section.component
35+
items={gridWithIconsItems.slice(0, 4)}
36+
columns={2}
37+
/>
38+
</ComponentWrapper>
39+
40+
<ComponentWrapper type={section.type} title="Center aligned">
41+
<section.component
42+
items={gridWithIconsItems}
43+
alignment="center"
44+
/>
45+
</ComponentWrapper>
46+
47+
<ComponentWrapper type={section.type} title="Right aligned">
48+
<section.component
49+
items={gridWithIconsItems}
50+
alignment="right"
51+
/>
52+
</ComponentWrapper>
53+
54+
<ComponentWrapper type={section.type} title="With icon background">
55+
<section.component
56+
items={gridWithIconsItems}
57+
iconWithBackground={true}
58+
/>
59+
</ComponentWrapper>
60+
61+
<ComponentWrapper type={section.type} title="Secondary">
62+
<section.component
63+
items={gridWithIconsItems}
64+
secondary={true}
65+
/>
66+
</ComponentWrapper>
67+
</div>
68+
))}
69+
</Layout>

src/pages/blocks/index.astro

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Link from '@static/Link.astro'
55
import BlogCard from '@blocks/BlogCard/BlogCard.astro'
66
import ErrorPage from '@blocks/ErrorPage/ErrorPage.astro'
77
import FAQ from '@blocks/FAQ/FAQ.astro'
8+
import GridWithIcons from '@blocks/GridWithIcons/GridWithIcons.astro'
89
import Hero from '@blocks/Hero/Hero.astro'
910
import IconList from '@blocks/IconList/IconList.astro'
1011
import SettingCard from '@blocks/SettingCard/SettingCard.astro'
@@ -39,6 +40,14 @@ import { Card, Switch } from 'webcoreui/astro'
3940
</SettingCard>
4041
<Link href="/blocks/setting-card" />
4142
</Card>
43+
<Card>
44+
<GridWithIcons items={[{
45+
icon: 'components',
46+
title: 'Grid with Icons',
47+
text: 'Use the <code>GridWithIcons</code> block to organize your list into a grid with icons to enhance clarity and visual appeal.'
48+
}]} columns={1} />
49+
<Link href="/blocks/grid-with-icons" />
50+
</Card>
4251
</div>
4352
<div class="block-column flex column">
4453
<Card title="User with Rating">

0 commit comments

Comments
 (0)