mirror of
https://github.com/vercel/commerce.git
synced 2025-07-24 02:31:24 +00:00
✨ feat: Skeleton Common
This commit is contained in:
@@ -1,32 +0,0 @@
|
|||||||
@import '../../../styles/utilities';
|
|
||||||
|
|
||||||
$base-color: #ddd;
|
|
||||||
$shine-color: #e8e8e8;
|
|
||||||
$animation-duration: 1.6s;
|
|
||||||
|
|
||||||
@mixin background-gradient {
|
|
||||||
background-image: linear-gradient(90deg, $base-color 0px, $shine-color 40px, $base-color 80px) ;
|
|
||||||
background-size: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.skeletonCommon:empty {
|
|
||||||
margin: auto;
|
|
||||||
height: 14rem;
|
|
||||||
width: 14rem;
|
|
||||||
animation: name duration timing-function delay iteration-count direction fill-mode;
|
|
||||||
|
|
||||||
@include background-gradient;
|
|
||||||
animation: shine-lines $animation-duration infinite linear;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes shine-lines {
|
|
||||||
0% {
|
|
||||||
background-position: -100px;
|
|
||||||
}
|
|
||||||
40% {
|
|
||||||
background-position: 140px;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
background-position: 140px;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import s from './SkeletonCommon.module.scss'
|
|
||||||
|
|
||||||
interface SkeletonCommonProps {
|
|
||||||
children? : React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SkeletonCommon = ({ children }: SkeletonCommonProps) => {
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={s.skeletonCommon}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SkeletonCommon
|
|
@@ -0,0 +1,53 @@
|
|||||||
|
@import '../../../../styles/utilities';
|
||||||
|
|
||||||
|
.skeletonImage:empty {
|
||||||
|
@apply relative;
|
||||||
|
background: #DDDBDD;
|
||||||
|
|
||||||
|
&.small {
|
||||||
|
width: 10rem;
|
||||||
|
height: 10rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.default {
|
||||||
|
width: 15rem;
|
||||||
|
height: 15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.large {
|
||||||
|
width: 20rem;
|
||||||
|
height: 20rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.left {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.center {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
transform: translateX(-100%);
|
||||||
|
background-image: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
rgba(#fff, 0) 0,
|
||||||
|
rgba(#fff, 0.2) 20%,
|
||||||
|
rgba(#fff, 0.5) 60%,
|
||||||
|
rgba(#fff, 0)
|
||||||
|
);
|
||||||
|
animation: shimmer 2s infinite;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shimmer {
|
||||||
|
100% {
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
import classNames from "classnames";
|
||||||
|
import React from "react";
|
||||||
|
import s from './SkeletonImage.module.scss'
|
||||||
|
|
||||||
|
interface SkeletonImageProps {
|
||||||
|
align?: "left" | "center"
|
||||||
|
size?: "small" | "default" | "large"
|
||||||
|
children?: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const SkeletonImage = ({ align="center", size="default", children }: SkeletonImageProps) => {
|
||||||
|
return (
|
||||||
|
<div className={classNames(s.skeletonImage, {
|
||||||
|
[s[size]] : size,
|
||||||
|
[s[align]] : align
|
||||||
|
})}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SkeletonImage
|
@@ -0,0 +1,63 @@
|
|||||||
|
@import '../../../../styles/utilities';
|
||||||
|
|
||||||
|
.skeletonParagraph {
|
||||||
|
.row {
|
||||||
|
display: inline-block;
|
||||||
|
height: 2rem;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #DDDBDD;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
transform: translateX(-100%);
|
||||||
|
background-image: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
rgba(#fff, 0) 0,
|
||||||
|
rgba(#fff, 0.2) 20%,
|
||||||
|
rgba(#fff, 0.5) 60%,
|
||||||
|
rgba(#fff, 0)
|
||||||
|
);
|
||||||
|
animation: shimmer 2s infinite;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lastRow {
|
||||||
|
display: inline-block;
|
||||||
|
height: 2rem;
|
||||||
|
width: 80%;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #DDDBDD;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
transform: translateX(-100%);
|
||||||
|
background-image: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
rgba(#fff, 0) 0,
|
||||||
|
rgba(#fff, 0.2) 20%,
|
||||||
|
rgba(#fff, 0.5) 60%,
|
||||||
|
rgba(#fff, 0)
|
||||||
|
);
|
||||||
|
animation: shimmer 2s infinite;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shimmer {
|
||||||
|
100% {
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,31 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import s from './SkeletonParagraph.module.scss'
|
||||||
|
|
||||||
|
interface SkeletonParagraphProps {
|
||||||
|
rows?: number // number of rows in paragraph
|
||||||
|
children?: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const SkeletonParagraph = ({ rows=2, children }: SkeletonParagraphProps) => {
|
||||||
|
|
||||||
|
const [isChildLoaded, setIsChildLoaded] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsChildLoaded(true);
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={s.skeletonParagraph}>
|
||||||
|
{
|
||||||
|
isChildLoaded ? children : [...Array(rows)].map((e, i) => {
|
||||||
|
if (i === rows-1) {
|
||||||
|
return <div key={i} className={s.lastRow}></div>
|
||||||
|
}
|
||||||
|
return <div key={i} className={s.row}></div>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SkeletonParagraph
|
@@ -1,51 +0,0 @@
|
|||||||
@import '../../../../../styles/utilities';
|
|
||||||
|
|
||||||
$base-color: #8F8F8F;
|
|
||||||
$shine-color: #ebebeb;
|
|
||||||
$animation-duration: 1.6s;
|
|
||||||
$avatar-offset: 52 + 16;
|
|
||||||
|
|
||||||
@mixin background-gradient {
|
|
||||||
background-image: linear-gradient(90deg, $base-color 0px, $shine-color 40px, $base-color 80px) ;
|
|
||||||
background-size: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.skeletonAvatar {
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
@include background-gradient;
|
|
||||||
animation: shine-avatar $animation-duration infinite linear;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.circle {
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.square {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.small {
|
|
||||||
width: 3.2rem;
|
|
||||||
height: 3.2rem;
|
|
||||||
}
|
|
||||||
&.default {
|
|
||||||
width: 4.8rem;
|
|
||||||
height: 4.8rem;
|
|
||||||
}
|
|
||||||
&.large {
|
|
||||||
width: 6.4rem;
|
|
||||||
height: 6.4rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes shine-avatar {
|
|
||||||
0% {
|
|
||||||
background-position: -100px + $avatar-offset
|
|
||||||
}
|
|
||||||
|
|
||||||
40%, 100% {
|
|
||||||
background-position: 140px + $avatar-offset
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,25 +0,0 @@
|
|||||||
import classNames from "classnames";
|
|
||||||
import React from "react";
|
|
||||||
import s from './SkeletonAvatar.module.scss'
|
|
||||||
|
|
||||||
interface SkeletonAvatarProps {
|
|
||||||
active?: boolean,
|
|
||||||
shape?: "circle" | "square",
|
|
||||||
size?: "small" | "default" | "large",
|
|
||||||
children: React.ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
const SkeletonAvatar = ({ active=true, shape="circle", size="default", children }: SkeletonAvatarProps) => {
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classNames(s.skeletonAvatar, {
|
|
||||||
[s.active] : active,
|
|
||||||
[s[shape]] : shape,
|
|
||||||
[s[size]] : size,
|
|
||||||
})}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SkeletonAvatar
|
|
@@ -1,41 +0,0 @@
|
|||||||
@import '../../../../../styles/utilities';
|
|
||||||
|
|
||||||
$base-color: #DDD;
|
|
||||||
$shine-color: #ebebeb;
|
|
||||||
$animation-duration: 2s;
|
|
||||||
|
|
||||||
@mixin background-gradient {
|
|
||||||
background-image: linear-gradient(90deg, $base-color 0px, $shine-color 40px, $base-color 80px) ;
|
|
||||||
background-size: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.skeletonParagraph {
|
|
||||||
@apply bg-white;
|
|
||||||
height: fit-content;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.row {
|
|
||||||
height: 2rem;
|
|
||||||
margin: 1rem;
|
|
||||||
animation: shine-lines $animation-duration infinite linear;
|
|
||||||
@include background-gradient;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lastRow {
|
|
||||||
height: 2rem;
|
|
||||||
margin: 1rem;
|
|
||||||
width: 85%;
|
|
||||||
animation: shine-lines $animation-duration infinite linear;
|
|
||||||
@include background-gradient;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes shine-lines {
|
|
||||||
0% {
|
|
||||||
background-position: -100px;
|
|
||||||
}
|
|
||||||
40%, 100% {
|
|
||||||
background-position: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@@ -1,30 +0,0 @@
|
|||||||
import classNames from "classnames";
|
|
||||||
import React from "react";
|
|
||||||
import s from './SkeletonParagraph.module.scss'
|
|
||||||
|
|
||||||
interface SkeletonParagraphProps {
|
|
||||||
active?: boolean,
|
|
||||||
rows?: number // number of rows in paragraph
|
|
||||||
children: React.ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
const SkeletonParagraph = ({ active=true, rows=2, children }: SkeletonParagraphProps) => {
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classNames(s.skeletonParagraph, {
|
|
||||||
[s.active] : active
|
|
||||||
})}>
|
|
||||||
{
|
|
||||||
[...Array(rows)].map((e, i) => {
|
|
||||||
if (i === rows-1) {
|
|
||||||
return <p key={i} className={s.lastRow}></p>
|
|
||||||
}
|
|
||||||
return <p key={i} className={s.row}></p>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SkeletonParagraph
|
|
@@ -1,27 +0,0 @@
|
|||||||
@import '../../../../../styles/utilities';
|
|
||||||
|
|
||||||
$base-color: #8F8F8F;
|
|
||||||
$shine-color: #ebebeb;
|
|
||||||
$animation-duration: 1.6s;
|
|
||||||
|
|
||||||
@mixin background-gradient {
|
|
||||||
background-image: linear-gradient(90deg, $base-color 0px, $shine-color 40px, $base-color 80px) ;
|
|
||||||
background-size: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.skeletonTitle {
|
|
||||||
&.active {
|
|
||||||
@include background-gradient;
|
|
||||||
animation: shine-lines $animation-duration infinite linear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes shine-lines {
|
|
||||||
0% {
|
|
||||||
background-position: -100px;
|
|
||||||
}
|
|
||||||
40%, 100% {
|
|
||||||
background-position: 50rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@@ -1,28 +0,0 @@
|
|||||||
import classNames from "classnames";
|
|
||||||
import React from "react";
|
|
||||||
import s from './SkeletonTitle.module.scss'
|
|
||||||
|
|
||||||
interface SkeletonTitleProps {
|
|
||||||
active?: boolean,
|
|
||||||
width: string | number, // number px
|
|
||||||
height: string | number,
|
|
||||||
children: React.ReactNode
|
|
||||||
}
|
|
||||||
|
|
||||||
const SkeletonTitle = ({ active=true, width, height, children }: SkeletonTitleProps) => {
|
|
||||||
|
|
||||||
const styles = {
|
|
||||||
width: width,
|
|
||||||
height: height
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={styles} className={classNames(s.skeletonTitle, {
|
|
||||||
[s.active] : active
|
|
||||||
})}>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SkeletonTitle
|
|
Reference in New Issue
Block a user