Skip to content

Commit 4c98734

Browse files
committed
✨ Add Stepper component for Astro
1 parent 2e75831 commit 4c98734

File tree

9 files changed

+335
-0
lines changed

9 files changed

+335
-0
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ html body {
157157
// Spoiler component
158158
--w-spoiler-color: var(--w-color-primary);
159159

160+
// Stepper component
161+
--w-stepper-color-border: var(--w-color-primary-50);
162+
--w-stepper-color-active: var(--w-color-info);
163+
--w-stepper-color-complete: var(--w-color-success);
164+
160165
// Switch component
161166
--w-switch-off-color: var(--w-color-primary-50);
162167
--w-switch-on-color: var(--w-color-primary);
@@ -237,6 +242,7 @@ import { Accordion } from 'webcoreui/react'
237242
- [Slider](https://github.com/Frontendland/webcoreui/tree/main/src/components/Slider)
238243
- [Spinner](https://github.com/Frontendland/webcoreui/tree/main/src/components/Spinner)
239244
- [Spoiler](https://github.com/Frontendland/webcoreui/tree/main/src/components/Spoiler)
245+
- [Stepper](https://github.com/Frontendland/webcoreui/tree/main/src/components/Stepper)
240246
- [Switch](https://github.com/Frontendland/webcoreui/tree/main/src/components/Switch)
241247
- [Table](https://github.com/Frontendland/webcoreui/tree/main/src/components/Table)
242248
- [Tabs](https://github.com/Frontendland/webcoreui/tree/main/src/components/Tabs)

src/components/Stepper/Stepper.astro

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
import type { StepperProps } from './stepper'
3+
4+
import ConditionalWrapper from '../ConditionalWrapper/ConditionalWrapper.astro'
5+
import Icon from '../Icon/Icon.astro'
6+
7+
import styles from './stepper.module.scss'
8+
9+
import type { IconProps } from '../Icon/icon'
10+
11+
interface Props extends StepperProps {}
12+
13+
const {
14+
items,
15+
color,
16+
completedColor,
17+
activeColor,
18+
vertical,
19+
className
20+
} = Astro.props
21+
22+
const classes = [
23+
styles.stepper,
24+
vertical && styles.vertical,
25+
className
26+
]
27+
28+
const styleVariables = [
29+
color && `--w-stepper-color-border: ${color}`,
30+
completedColor && `--w-stepper-color-complete: ${completedColor}`,
31+
activeColor && `--w-stepper-color-active: ${activeColor}`
32+
].filter(Boolean).join('')
33+
---
34+
35+
<ol class:list={classes} style={styleVariables}>
36+
{items?.map((item, index) => (
37+
<li class:list={[
38+
index !== 0 && styles.connect,
39+
item.active && styles.active,
40+
item.completed && styles.completed
41+
]}>
42+
<span class={styles.number}>
43+
{item.icon ? (
44+
<Fragment>
45+
{item.icon.startsWith('<svg')
46+
? <Fragment set:html={item.icon} />
47+
: <Icon type={item.icon as IconProps['type']} />
48+
}
49+
</Fragment>
50+
) : index + 1}
51+
</span>
52+
<ConditionalWrapper condition={!!(item.title && item.subTitle)}>
53+
<div slot="wrapper" class={styles.container}>children</div>
54+
{item.title && <span>{item.title}</span>}
55+
{item.subTitle && <span class={styles.muted}>{item.subTitle}</span>}
56+
</ConditionalWrapper>
57+
</li>
58+
))}
59+
</ol>

src/components/Stepper/Stepper.svelte

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<script lang="ts">
2+
import type { StepperProps } from './stepper'
3+
4+
import { classNames } from '../../utils/classNames'
5+
6+
import styles from './stepper.module.scss'
7+
8+
export let className: StepperProps['className'] = ''
9+
10+
const classes = classNames([
11+
styles.stepper,
12+
className
13+
])
14+
</script>

src/components/Stepper/Stepper.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from 'react'
2+
import type { StepperProps } from './stepper'
3+
4+
import { classNames } from '../../utils/classNames'
5+
6+
import styles from './stepper.module.scss'
7+
8+
const Stepper = ({
9+
className
10+
}: StepperProps) => {
11+
const classes = classNames([
12+
styles.stepper,
13+
className
14+
])
15+
16+
return <div>Stepper</div>
17+
}
18+
19+
export default Stepper
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
@import '../../scss/config.scss';
2+
3+
body {
4+
--w-stepper-color-border: var(--w-color-primary-50);
5+
--w-stepper-color-active: var(--w-color-info);
6+
--w-stepper-color-complete: var(--w-color-success);
7+
}
8+
9+
$size: 20px;
10+
11+
.stepper {
12+
@include layout(flex, default, column);
13+
@include spacing(0);
14+
@include size('w100%');
15+
16+
list-style-type: none;
17+
18+
li {
19+
@include layout(flex, sm, v-center);
20+
@include typography(normal);
21+
@include spacing(m0);
22+
23+
flex: 1;
24+
25+
&.connect {
26+
@include position(relative);
27+
28+
&::before {
29+
@include position(absolute, l16px);
30+
@include background(primary-50);
31+
@include size(w2px);
32+
33+
top: -50%;
34+
bottom: calc(50% + $size);
35+
36+
content: '';
37+
}
38+
39+
&.completed::before,
40+
&.active::before {
41+
@include background(var(--w-stepper-color-complete));
42+
}
43+
}
44+
45+
&.active .number {
46+
border-color: var(--w-stepper-color-active);
47+
color: var(--w-stepper-color-active);
48+
}
49+
50+
&.completed .number {
51+
border-color: var(--w-stepper-color-complete);
52+
color: var(--w-stepper-color-complete);
53+
}
54+
55+
.number {
56+
@include size($size);
57+
@include border-radius(max);
58+
@include layout(flex, center);
59+
@include spacing(p-md);
60+
@include typography(bold, md);
61+
62+
border: 2px solid var(--w-stepper-color-border);
63+
64+
svg {
65+
@include position(absolute);
66+
}
67+
}
68+
69+
.container {
70+
@include layout(flex, column);
71+
}
72+
73+
.muted {
74+
@include typography(primary-20, md);
75+
}
76+
}
77+
}
78+
79+
@include media(xs) {
80+
.stepper:not(.vertical) {
81+
@include layout(row);
82+
83+
li {
84+
@include layout(column, xs, v-center);
85+
86+
&.connect::before {
87+
@include size(h2px);
88+
89+
width: auto;
90+
top: 16px;
91+
left: calc(-50%);
92+
right: calc(50% + $size);
93+
}
94+
95+
.container {
96+
@include layout(v-center);
97+
}
98+
}
99+
}
100+
}

src/components/Stepper/stepper.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type { IconProps } from '../Icon/icon'
2+
3+
export type StepperProps = {
4+
items: {
5+
icon?: IconProps['type'] | string
6+
title?: string
7+
subTitle?: string
8+
completed?: boolean
9+
active?: boolean
10+
}[]
11+
color?: string
12+
completedColor?: string
13+
activeColor?: string
14+
vertical?: boolean
15+
className?: string
16+
}

src/data.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,3 +372,33 @@ export const reactMasonryComponentItems = masonryComponentItems.map(item => ({
372372
...item,
373373
component: ReactAlert
374374
}))
375+
376+
export const stepper = [
377+
{ title: 'Setup' },
378+
{ title: 'Configure' },
379+
{ title: 'Finish' }
380+
]
381+
382+
export const stepperWithSubTitle = [
383+
{ title: 'Setup', subTitle: 'Get ready' },
384+
{ title: 'Configure', subTitle: 'Preferences' },
385+
{ title: 'Finish', subTitle: 'Final steps' }
386+
]
387+
388+
export const completedStepper = [
389+
{ title: 'Setup', subTitle: 'Get ready', completed: true },
390+
{ title: 'Configure', subTitle: 'Preferences' },
391+
{ title: 'Finish', subTitle: 'Final steps' }
392+
]
393+
394+
export const activeStepper = [
395+
{ title: 'Setup', subTitle: 'Get ready', completed: true },
396+
{ title: 'Configure', subTitle: 'Preferences', active: true },
397+
{ title: 'Finish', subTitle: 'Final steps' }
398+
]
399+
400+
export const stepperWithIcons = [
401+
{ title: 'Setup', subTitle: 'Get ready', completed: true, icon: successIcon },
402+
{ title: 'Configure', subTitle: 'Preferences', active: true, icon: gitHubIcon },
403+
{ title: 'Finish', subTitle: 'Final steps' }
404+
]

src/pages/components/stepper.astro

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
---
2+
import ComponentWrapper from '@static/ComponentWrapper.astro'
3+
import Layout from '@static/Layout.astro'
4+
5+
import AstroStepper from '@components/Stepper/Stepper.astro'
6+
import SvelteStepper from '@components/Stepper/Stepper.svelte'
7+
import ReactStepper from '@components/Stepper/Stepper.tsx'
8+
9+
import { getSections } from '@helpers'
10+
import {
11+
activeStepper,
12+
completedStepper,
13+
stepper,
14+
stepperWithIcons,
15+
stepperWithSubTitle
16+
} from '@data'
17+
18+
const sections = getSections({
19+
title: 'steppers',
20+
components: [AstroStepper, SvelteStepper, ReactStepper]
21+
})
22+
23+
const items = [
24+
{ title: 'Setup', subTitle: 'Get ready', completed: true, icon: 'circle-check' },
25+
{ title: 'Configure', subTitle: 'Preferences', active: true, icon: 'github' },
26+
{ title: 'Finish', subTitle: 'Final steps' }
27+
]
28+
---
29+
30+
<Layout>
31+
<h1>Stepper</h1>
32+
<div class="grid md-2 lg-3">
33+
<ComponentWrapper type="Astro">
34+
<AstroStepper items={items} />
35+
</ComponentWrapper>
36+
37+
<ComponentWrapper type="Svelte">
38+
<SvelteStepper items={items} />
39+
</ComponentWrapper>
40+
41+
<ComponentWrapper type="React">
42+
<ReactStepper items={items} />
43+
</ComponentWrapper>
44+
</div>
45+
46+
{sections.map(section => (
47+
<h1>{section.title}</h1>
48+
<Fragment>
49+
{section.subTitle && <h2 set:html={section.subTitle} />}
50+
</Fragment>
51+
<div class="grid md-2 lg-3">
52+
<ComponentWrapper title="Default">
53+
<section.component items={stepper} />
54+
</ComponentWrapper>
55+
56+
<ComponentWrapper title="Stepper with subtitles">
57+
<section.component items={stepperWithSubTitle} />
58+
</ComponentWrapper>
59+
60+
<ComponentWrapper title="Completed state">
61+
<section.component items={completedStepper} />
62+
</ComponentWrapper>
63+
64+
<ComponentWrapper title="Active state">
65+
<section.component items={activeStepper} />
66+
</ComponentWrapper>
67+
68+
<ComponentWrapper title="Stepper with icons">
69+
<section.component items={stepperWithIcons} />
70+
</ComponentWrapper>
71+
72+
<ComponentWrapper title="Borderless stepper">
73+
<section.component
74+
items={stepperWithIcons}
75+
color="transparent"
76+
completedColor="transparent"
77+
activeColor="transparent"
78+
/>
79+
</ComponentWrapper>
80+
81+
<ComponentWrapper title="Vertical stepper">
82+
<section.component items={stepperWithIcons} vertical={true} />
83+
</ComponentWrapper>
84+
</div>
85+
))}
86+
</Layout>

src/pages/index.astro

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import Select from '@components/Select/Select.astro'
3232
import Slider from '@components/Slider/Slider.astro'
3333
import Spinner from '@components/Spinner/Spinner.astro'
3434
import Spoiler from '@components/Spoiler/Spoiler.astro'
35+
import Stepper from '@components/Stepper/Stepper.astro'
3536
import Switch from '@components/Switch/Switch.astro'
3637
import Table from '@components/Table/Table.astro'
3738
import Tabs from '@components/Tabs/Tabs.astro'
@@ -50,6 +51,7 @@ import {
5051
avatarGroupAlt2,
5152
listPreview,
5253
masonryItems,
54+
stepperWithIcons,
5355
themes
5456
} from '@data'
5557
@@ -270,6 +272,9 @@ const tabItems = [{
270272
<CardWrapper title="Spoiler" href="/components/spoiler">
271273
<Spoiler>This text is hidden.</Spoiler>
272274
</CardWrapper>
275+
<CardWrapper title="Stepper" href="/components/stepper">
276+
<Stepper items={[stepperWithIcons[0], stepperWithIcons[1]]} />
277+
</CardWrapper>
273278
<CardWrapper title="Switch" href="/components/switch">
274279
<Switch toggled={true} />
275280
</CardWrapper>

0 commit comments

Comments
 (0)