[CHART SKELETON] REACT 차트 스켈레톤

Darcy Daeseok YU ·2023년 9월 4일

I've never expected I should implement a Skeleton component from scratch...
Even though there's a bunch of library for it. :)

Shimmer (번쩍임)

전체 페이지 번쩍임 Shimmering at container
absolute + translate animation

styles.ts (emotion/styled)


const transXFlow = keyframes`
  0% {
    transform: translateX(-300%);
  }
  
  100% {
     transform: translateX(300%);
  }
`;


export const Shimmer = styled.div`
  position: absolute;
  top: 0;
  left: 0;
  width: 50%;
  height: 100%;

  background: linear-gradient(
    100deg,
    rgba(255, 255, 255, 0) 20%,
    rgba(255, 255, 255, 0.5) 50%,
    rgba(255, 255, 255, 0) 80%
  );

  animation: ${transXFlow} 2.2s infinite linear;
`;


번쩍임 각 컨테이너별 Shimmering on each child components
background + background-position animation


const shimmer = keyframes`
    0% {
    background-position: -1200px 0;
  }
  
  100% {
    background-position: 1200px 0; 
  }
`;

export const ShimmerBG = styled.div`
  animation-duration: 2.2s;
  animation-fill-mode: forwards;
  animation-iteration-count: infinite;
  animation-name: ${shimmer};
  animation-timing-function: linear;
  background: #ddd;
  background: linear-gradient(45deg, #f6f6f6 8%, #f0f0f0 18%, #f6f6f6 33%);

  background-size: 1200px 100%;
`;



// export const Container = styled(ShimmerBG)`
  width: 100%;
  height: 100%;
  max-height: 300px;
  position: relative;
  display: flex;
`;


// export const Item = styled(ShimmerBG)`
  position: relative;
  box-shadow: 6px 0px 8px rgba(0, 0, 0, 0.1);
  /* background-color: #fff; */
  width: 100%;

  background-color: #d9d9d9;
`;

Whole css

import { keyframes } from '@emotion/react';
import styled from '@emotion/styled';
import { CSSProperties } from 'react';
import { palette } from '../../styles/palette';

const shimmer = keyframes`
    0% {
    background-position: -1200px 0;
  }
  
  100% {
    background-position: 1200px 0; 
  }
`;

export const ShimmerBG = styled.div`
  animation-duration: 2.2s;
  animation-fill-mode: forwards;
  animation-iteration-count: infinite;
  animation-name: ${shimmer};
  animation-timing-function: linear;
  background: #ddd;
  background: linear-gradient(45deg, #f6f6f6 8%, #f0f0f0 18%, #f6f6f6 33%);

  background-size: 1200px 100%;
`;

// export const Container = styled(ShimmerBG)`
export const Container = styled.div`
  width: 100%;
  height: 100%;
  max-height: 300px;
  position: relative;
  display: flex;
`;

// export const Item = styled(ShimmerBG)`
export const Bar = styled.div`
  position: relative;
  box-shadow: 6px 0px 8px rgba(0, 0, 0, 0.1);
  /* background-color: #fff; */
  width: 100%;

  background-color: #d9d9d9;
`;

const transXFlow = keyframes`
  0% {
    transform: translateX(-300%);
  }
  
  100% {
     transform: translateX(300%);
  }
`;

export const Shimmer = styled.div`
  position: absolute;
  top: 0;
  left: 0;
  width: 50%;
  height: 100%;

  background: linear-gradient(
    100deg,
    rgba(255, 255, 255, 0) 20%,
    rgba(255, 255, 255, 0.5) 50%,
    rgba(255, 255, 255, 0) 80%
  );

  animation: ${transXFlow} 2.2s infinite linear;
`;

export const XAxis = styled.div<{ borderColor?: CSSProperties['color'] }>`
  width: 100%;
  height: 2px;
  position: absolute;
  bottom: -2px;
  background: ${(props) => (props.borderColor ? props.borderColor : palette.gray400)};
`;
export const XAxisGridLine = styled.div<{ borderColor?: CSSProperties['color']; top?: CSSProperties['top'] }>`
  width: 100%;
  height: 2px;
  position: absolute;
  top: ${(props) => (props.top ? props.top : '50%')};
  background: ${(props) => (props.borderColor ? props.borderColor : palette.chartGridLine)};
`;

export const YAxis = styled.div<{ borderColor?: CSSProperties['color'] }>`
  width: 2px;
  height: 100%;
  position: absolute;
  left: 0;
  background: ${(props) => (props.borderColor ? props.borderColor : palette.gray400)};
`;

export const GradientLayer = styled.div`
  position: absolute;
  width: 100%;
  height: 100%;

  background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.7));
`;

whole component Code

function SkeletonDualBarChart({ showDualBar }: IProps) {
  return (
    <Container>
      <XAxisGridLine top={'10%'} />
      <XAxisGridLine top={'45%'} />

      <XAxis />
      <YAxis />
      {[...Array(5)].map((config, idx) => {
        return (
          <CommColFlexContainer justifyContent="end" style={{ padding: `0 50px`, position: 'relative' }}>
            <CommRowFlexContainer alignItems="end" gap={8} style={{ width: '100%', height: '100%' }}>
              <Bar style={{ height: `${25 + idx * 10}%` }} />
              <Bar style={{ height: `${30 + idx * 10}%` }} />
            </CommRowFlexContainer>

            {/* <CommText style={{ position: 'absolute', bottom: -26, left: '50%', transform: 'translate(-50% , 0)' }}>
              {config.label}
            </CommText> */}
          </CommColFlexContainer>
        );
      })}

      <GradientLayer />
      <Shimmer />
    </Container>
  );
}
profile
React, React-Native https://darcyu83.netlify.app/

0개의 댓글