Skip to content

Commit 58cbd4f

Browse files
committed
✨ Add Skeleton component
1 parent b2d8aca commit 58cbd4f

File tree

9 files changed

+257
-0
lines changed

9 files changed

+257
-0
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ html body {
142142
--w-scrollbar-bg: var(--w-color-primary-60);
143143
--w-scrollbar-fg: var(--w-color-primary-50);
144144

145+
// Skeleton component
146+
--w-skeleton-color: var(--w-color-primary-60);
147+
--w-skeleton-wave-color: var(--w-color-primary-50);
148+
145149
// Slider component
146150
--w-slider-background: var(--w-color-primary-50);
147151
--w-slider-color: var(--w-color-primary);
@@ -239,6 +243,7 @@ import { Accordion } from 'webcoreui/react'
239243
- [Select](https://github.com/Frontendland/webcoreui/tree/main/src/components/Select)
240244
- [Sheet](https://github.com/Frontendland/webcoreui/tree/main/src/components/Sheet)
241245
- [Sidebar](https://github.com/Frontendland/webcoreui/tree/main/src/components/Sidebar)
246+
- [Skeleton](https://github.com/Frontendland/webcoreui/tree/main/src/components/Skeleton)
242247
- [Slider](https://github.com/Frontendland/webcoreui/tree/main/src/components/Slider)
243248
- [Spinner](https://github.com/Frontendland/webcoreui/tree/main/src/components/Spinner)
244249
- [Spoiler](https://github.com/Frontendland/webcoreui/tree/main/src/components/Spoiler)

scripts/buildTypes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ const buildTypes = type => {
7575
'Breadcrumb',
7676
'Icon',
7777
'Rating',
78+
'Skeleton',
7879
'Spinner',
7980
'Stepper',
8081
'Table',
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
import type { SkeletonProps } from './skeleton'
3+
4+
import { classNames } from '../../utils/classNames'
5+
6+
import styles from './skeleton.module.scss'
7+
8+
interface Props extends SkeletonProps {}
9+
10+
const {
11+
animate = 'wave',
12+
type = 'rounded',
13+
width,
14+
height,
15+
color,
16+
waveColor,
17+
className
18+
} = Astro.props
19+
20+
const classes = [
21+
animate && styles[animate],
22+
styles[type],
23+
styles.skeleton,
24+
className
25+
]
26+
27+
const styleVariables = classNames([
28+
width && `width: ${width}px;`,
29+
height && `height: ${height}px;`,
30+
color && `--w-skeleton-color: ${color};`,
31+
waveColor && `--w-skeleton-wave-color: ${waveColor};`
32+
])
33+
---
34+
35+
<div class:list={classes} style={styleVariables}>&nbsp;</div>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<script lang="ts">
2+
import type { SkeletonProps } from './skeleton'
3+
4+
import { classNames } from '../../utils/classNames'
5+
6+
import styles from './skeleton.module.scss'
7+
8+
export let animate: SkeletonProps['animate'] = 'wave'
9+
export let type: SkeletonProps['type'] = 'rounded'
10+
export let width: SkeletonProps['width'] = 0
11+
export let height: SkeletonProps['height'] = 0
12+
export let color: SkeletonProps['color'] = ''
13+
export let waveColor: SkeletonProps['waveColor'] = ''
14+
export let className: SkeletonProps['className'] = ''
15+
16+
const classes = classNames([
17+
animate && styles[animate],
18+
styles[type!],
19+
styles.skeleton,
20+
className
21+
])
22+
23+
const styleVariables = classNames([
24+
width && `width: ${width}px;`,
25+
height && `height: ${height}px;`,
26+
color && `--w-skeleton-color: ${color};`,
27+
waveColor && `--w-skeleton-wave-color: ${waveColor};`
28+
])
29+
</script>
30+
31+
<div class={classes} style={styleVariables}>&nbsp;</div>

src/components/Skeleton/Skeleton.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React from 'react'
2+
import type { SkeletonProps } from './skeleton'
3+
4+
import { classNames } from '../../utils/classNames'
5+
6+
import styles from './skeleton.module.scss'
7+
8+
const Skeleton = ({
9+
animate = 'wave',
10+
type = 'rounded',
11+
width,
12+
height,
13+
color,
14+
waveColor,
15+
className
16+
}: SkeletonProps) => {
17+
const classes = classNames([
18+
animate && styles[animate],
19+
styles[type],
20+
styles.skeleton,
21+
className
22+
])
23+
24+
const styleVariables = {
25+
...(width && { width: `${width}px` }),
26+
...(height && { height: `${height}px` }),
27+
...(color && { '--w-skeleton-color': color }),
28+
...(waveColor && { '--w-skeleton-wave-color': waveColor })
29+
} as React.CSSProperties
30+
31+
return <div className={classes} style={styleVariables}>&nbsp;</div>
32+
}
33+
34+
export default Skeleton
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
@use '../../scss/config.scss' as *;
2+
3+
body {
4+
--w-skeleton-color: var(--w-color-primary-60);
5+
--w-skeleton-wave-color: var(--w-color-primary-50);
6+
}
7+
8+
.skeleton {
9+
@include background(var(--w-skeleton-color));
10+
@include size(100%);
11+
12+
text-indent: -9999px;
13+
14+
&.wave {
15+
@include position(relative);
16+
@include visibility(hidden);
17+
18+
&::after {
19+
@include position(absolute, t0);
20+
@include visibility(block);
21+
@include size('w200px', 'h100%');
22+
23+
content: '';
24+
left: -200px;
25+
animation: wave 1s cubic-bezier(0.4, 0.0, 0.2, 1) infinite;
26+
background: linear-gradient(
27+
to right,
28+
transparent 0%,
29+
var(--w-skeleton-wave-color) 50%,
30+
transparent 100%
31+
);
32+
}
33+
}
34+
35+
&.pulse {
36+
animation: pulse 1.3s cubic-bezier(0.4, 0.0, 0.2, 1) infinite;
37+
}
38+
39+
&.rounded {
40+
@include border-radius();
41+
}
42+
43+
&.circle {
44+
@include border-radius(max);
45+
}
46+
}
47+
48+
@keyframes wave {
49+
from {
50+
left: -200px;
51+
}
52+
to {
53+
left: 100%;
54+
}
55+
}
56+
57+
58+
@keyframes pulse {
59+
0% {
60+
@include visibility(1);
61+
}
62+
50% {
63+
@include visibility(.7);
64+
}
65+
100% {
66+
@include visibility(1);
67+
}
68+
}

src/components/Skeleton/skeleton.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export type SkeletonProps = {
2+
animate?: 'wave' | 'pulse' | false
3+
type?: 'rounded' | 'rectangular' | 'circle'
4+
width?: number
5+
height?: number
6+
color?: string
7+
waveColor?: string
8+
className?: string
9+
}

src/pages/components/skeleton.astro

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
---
2+
import ComponentWrapper from '@static/ComponentWrapper.astro'
3+
import Layout from '@static/Layout.astro'
4+
5+
import AstroSkeleton from '@components/Skeleton/Skeleton.astro'
6+
import SvelteSkeleton from '@components/Skeleton/Skeleton.svelte'
7+
import ReactSkeleton from '@components/Skeleton/Skeleton.tsx'
8+
9+
import { getSections } from '@helpers'
10+
11+
const sections = getSections({
12+
title: 'skeletons',
13+
components: [AstroSkeleton, SvelteSkeleton, ReactSkeleton]
14+
})
15+
---
16+
17+
<Layout>
18+
<h1>Skeleton</h1>
19+
<div class="grid md-2 lg-3">
20+
<ComponentWrapper type="Astro">
21+
<AstroSkeleton />
22+
</ComponentWrapper>
23+
24+
<ComponentWrapper type="Svelte">
25+
<SvelteSkeleton
26+
color="var(--w-color-warning)"
27+
waveColor="var(--w-color-alert-accent)"
28+
/>
29+
</ComponentWrapper>
30+
31+
<ComponentWrapper type="React">
32+
<ReactSkeleton
33+
color="var(--w-color-info)"
34+
waveColor="var(--w-color-info-accent)"
35+
/>
36+
</ComponentWrapper>
37+
</div>
38+
39+
{sections.map(section => (
40+
<h1>{section.title}</h1>
41+
<Fragment>
42+
{section.subTitle && <h2 set:html={section.subTitle} />}
43+
</Fragment>
44+
<div class="grid md-2 lg-3">
45+
<ComponentWrapper title="Default">
46+
<section.component />
47+
</ComponentWrapper>
48+
49+
<ComponentWrapper title="Pulse animation">
50+
<section.component animate="pulse" />
51+
</ComponentWrapper>
52+
53+
<ComponentWrapper title="No animation">
54+
<section.component animate={false} />
55+
</ComponentWrapper>
56+
57+
<ComponentWrapper title="Rectangular">
58+
<section.component type="rectangular" />
59+
</ComponentWrapper>
60+
61+
<ComponentWrapper title="Circle">
62+
<section.component type="circle" width={20} height={20} />
63+
</ComponentWrapper>
64+
65+
<ComponentWrapper title="Custom size">
66+
<section.component width={100} />
67+
</ComponentWrapper>
68+
</div>
69+
))}
70+
</Layout>

src/pages/index.astro

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import Progress from '@components/Progress/Progress.astro'
2929
import Radio from '@components/Radio/Radio.astro'
3030
import Rating from '@components/Rating/Rating.astro'
3131
import Select from '@components/Select/Select.astro'
32+
import Skeleton from '@components/Skeleton/Skeleton.astro'
3233
import Slider from '@components/Slider/Slider.astro'
3334
import Spinner from '@components/Spinner/Spinner.astro'
3435
import Spoiler from '@components/Spoiler/Spoiler.astro'
@@ -263,6 +264,9 @@ const tabItems = [{
263264
<Badge theme="success" small={true}>new components</Badge>
264265
</div>
265266
</CardWrapper>
267+
<CardWrapper title="Skeleton" href="/components/skeleton">
268+
<Skeleton height={15} />
269+
</CardWrapper>
266270
<CardWrapper title="Slider" href="/components/slider">
267271
<Slider min={0} max={100} value={50} />
268272
</CardWrapper>

0 commit comments

Comments
 (0)