4
0
forked from crowetic/commerce

Skeleton Component

This commit is contained in:
Belen Curcio 2020-10-15 11:10:07 -03:00
parent 3b7b71422c
commit bf1ffcace9
9 changed files with 163 additions and 15 deletions

View File

@ -1,16 +1,4 @@
@keyframes blink {
0% {
opacity: 0.2;
}
20% {
opacity: 1;
}
100% {
opacity: 0.2;
}
}
.loading {
.root {
@apply inline-flex text-center items-center leading-7;
& span {
@ -30,3 +18,15 @@
}
}
}
@keyframes blink {
0% {
opacity: 0.2;
}
20% {
opacity: 1;
}
100% {
opacity: 0.2;
}
}

View File

@ -2,7 +2,7 @@ import s from './LoadingDots.module.css'
const LoadingDots: React.FC = () => {
return (
<span className={s.loading}>
<span className={s.root}>
<span />
<span />
<span />

View File

@ -0,0 +1,59 @@
.skeleton {
@apply block rounded-md;
&.loaded {
width: unset !important;
}
&:not(.wrapper):not(.show) {
display: none;
}
&::not(.wrapper):not(.loaded) {
background-image: linear-gradient(
270deg,
var(--accents-1),
var(--accents-2),
var(--accents-2),
var(--accents-1)
);
background-size: 400% 100%;
animation: loading 8s ease-in-out infinite;
}
}
.wrapper {
@apply block relative;
&:not(.show)::before {
content: none;
}
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 100;
background-image: linear-gradient(
270deg,
var(--accents-1),
var(--accents-2),
var(--accents-2),
var(--accents-1)
);
background-size: 400% 100%;
animation: loading 8s ease-in-out infinite;
}
}
@keyframes loading {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}

View File

@ -0,0 +1,57 @@
import React, { CSSProperties } from 'react'
import cn from 'classnames'
import px from '@lib/to-pixels'
import s from './skeleton.module.css'
interface Props {
width?: string | number
height?: string | number
boxHeight?: string | number
style?: CSSProperties
show?: boolean
block?: boolean
className?: string
}
const Skeleton: React.FC<Props> = ({
style,
width,
height,
children,
className,
show = true,
boxHeight = height,
}) => {
// Automatically calculate the size if there are children
// and no fixed sizes are specified
const shouldAutoSize = !!children && !(width || height)
// Defaults
width = width || 24
height = height || 24
boxHeight = boxHeight || height
return (
<span
className={cn(s.skeleton, className, {
[s.show]: show,
[s.wrapper]: shouldAutoSize,
[s.loaded]: !shouldAutoSize && !!children,
})}
style={
shouldAutoSize
? {}
: {
minWidth: px(width),
minHeight: px(height),
marginBottom: `calc(${px(boxHeight)} - ${px(height)})`,
...style,
}
}
>
{children}
</span>
)
}
export default Skeleton

View File

@ -0,0 +1 @@
export { default } from './Skeleton'

View File

@ -6,3 +6,4 @@ export { default as Sidebar } from './Sidebar'
export { default as Marquee } from './Marquee'
export { default as Container } from './Container'
export { default as LoadingDots } from './LoadingDots'
export { default as Skeleton } from './Skeleton'

13
lib/to-pixels.ts Normal file
View File

@ -0,0 +1,13 @@
// Convert numbers or strings to pixel value
// Helpful for styled-jsx when using a prop
// height: ${toPixels(height)}; (supports height={20} and height="20px")
const toPixels = (value: string | number) => {
if (typeof value === 'number') {
return `${value}px`
}
return value
}
export default toPixels

View File

@ -128,7 +128,10 @@ export default function Search({
</>
) : (
// TODO: add a proper loading state
<div>Searching...</div>
<div>
Searching...
<Skeleton></Skeleton>
</div>
)}
</div>
<div className="col-span-2">

14
pages/ui.tsx Normal file
View File

@ -0,0 +1,14 @@
import { GetStaticPropsContext, InferGetStaticPropsType } from 'next'
import { useRouter } from 'next/router'
import Link from 'next/link'
import { Layout } from '@components/core'
import { Container, Grid, Skeleton } from '@components/ui'
export default function Search() {
return (
<Container>
<Skeleton className="w-64 h-12 rounded-md" />
</Container>
)
}
Search.Layout = Layout