728x90
페이지별 공통으로 사용하는 스크립트나 scss는 import를 시키면 코드를 효율적으로 줄일 수 있다.
이처럼 style-comonponent와 framer-motion 또한 공통 파일로 꾸려서 import 하면 효과적으로 코드를 작성할 수 있다.
예를 들어 270줄이였던 한 페이지를 94줄로 줄였었다.
방법은 간단하다.
1. src 폴더 안에 js/styled.js 라는 임의의 js 파일을 생성
2. 공통으로 사용하는 스타일 컴포넌트와 프레이머 모션을 다 가져와서 styled.js에 저장한다.
그후 사용하려는 페이지에 import 시킨다.
주의할 점은 styled.js 파일 안에 const 변수를 꼭 export 시켜야 외부에서도 사용이 가능하다.
[src/js/styled.js]
import styled from 'styled-components';
import { media } from 'style/media_query';
import { motion } from 'framer-motion';
export const Spacing = styled.div`
position: relative;
z-index: 1;
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 2%;
padding: 110px 32px 0;
${media.large`
padding-top: 70px;
`};
${media.medium`
padding: 70px 24px 0;
`};
${media.small`
flex-direction: column;
padding: 40px 20px 0;
gap: 15px 0;
`};
`;
export const CaptureMove = styled.div`
overflow: hidden;
border: 2px solid #000;
background-color: #000;
border-radius: 7px;
> video {
width: 100%;
}
`;
export const Device = styled.div`
overflow: hidden;
flex-basis: calc(40% - 10px / 3 * 2);
&.mo {
flex-basis: calc(20% - 10px / 3 * 2);
/* ${media.small`
width: 35%;
`}; */
}
`;
export const DeviceName = styled.p`
color: ${(props) => props.theme.textColor.gray.first};
font-size: 16px;
font-weight: 700;
text-align: right;
width: 100%;
padding: 0 12px 8px 0;
opacity: 0.7;
`;
export const GridFrame = styled.div`
flex: 0 0 auto;
`;
export const Grid = styled(motion.div)`
overflow-x: hidden;
overflow-y: auto;
background-color: rgba(251, 234, 173, 0.7);
border-radius: 7px;
box-shadow: ${(props) => props.theme.shadow.box};
cursor: pointer;
max-height: 600px;
&::-webkit-scrollbar {
width: 8px;
}
&::-webkit-scrollbar-thumb {
background-color: #807d7d;
border-radius: 6px;
border: 6px solid #fbeaad;
}
&::-webkit-scrollbar-track {
background-color: rgb(128, 125, 125, 0.9);
border-radius: 6px;
}
> img {
display: block;
width: 100%;
}
`;
export const Modal = styled.div`
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
position: fixed;
left: 0;
top: 0;
z-index: 9;
height: calc(var(--vh, 1vh) * 100);
`;
export const Overlay = styled(motion.div)`
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-color: #000;
opacity: 0.4;
z-index: -1;
`;
export const GridWhole = styled(motion.div)`
width: 95%;
border-radius: 7px;
position: relative;
overflow: hidden;
/* ${media.medium`
border-bottom-left-radius: 16px;
border-bottom-right-radius: 16px;
`};
${media.small`
border-bottom-left-radius: 14px;
border-bottom-right-radius: 14px;
`}; */
> svg {
position: absolute;
right: 20px;
top: 16px;
width: 22px;
height: 22px;
padding: 10px;
border-radius: 50%;
background-color: rgba(66, 66, 66, 0.6);
color: #fff;
cursor: pointer;
}
`;
export const GridBody = styled.div`
height: calc(var(--vh, 1vh) * 82);
overflow-x: hidden;
overflow-y: auto;
&::-webkit-scrollbar {
width: 10px;
}
&::-webkit-scrollbar-thumb {
background-color: #807d7d;
border-radius: 6px;
border: 6px solid #fbeaad;
}
&::-webkit-scrollbar-track {
background-color: rgb(128, 125, 125, 0.9);
border-radius: 6px;
}
> img {
display: block;
width: 100%;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
${media.medium`
border-bottom-left-radius: 16px;
border-bottom-right-radius: 16px;
`};
${media.small`
border-bottom-left-radius: 14px;
border-bottom-right-radius: 14px;
`};
}
`;
// motion
export const overlay = {
hidden: { backgroundColor: 'rgba(0, 0, 0, 0)' },
visible: { backgroundColor: 'rgba(0, 0, 0, 1)' },
exit: { backgroundColor: 'rgba(0, 0, 0, 0)' },
};
export const girdVariants = {
start: {
border: '3px solid transparent',
},
hover: {
borderColor: '#ffcc42',
y: -20,
scale: 1.05,
},
};
[sub_pages/Example.tsx]
import { AnimatePresence } from 'framer-motion';
import { Spacing, CaptureMove, DeviceName, GridFrame, Grid, Modal, Overlay, GridWhole, GridBody, overlay, girdVariants } from 'js/styled.js';
import '../style/sub.scss';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faXmark } from '@fortawesome/free-solid-svg-icons';
import fullMp4 from 'img/sub_pages/event/full.mp4';
import mainKo from 'img/sub_pages/event/page.webp';
import mainMo from 'img/sub_pages/event/page_mo.webp';
import { useEffect, useState } from 'react';
import { focusHandler, resetHandler } from 'function/ModalScroll';
function Roball() {
const [data, setData] = useState<any[]>();
const [id, setId] = useState<null | string>(null);
const [device, setDevice] = useState<null | number>(null);
const [func, setFunc] = useState<any>({ on: null, off: null });
useEffect(() => {
// data
const imgArr = [mainKo, mainMo];
let isMount = true;
if (isMount) {
setData(imgArr);
setFunc({ on: focusHandler, off: resetHandler });
}
return () => {
isMount = false;
setData([]);
setFunc({});
};
}, []);
return (
<div className="sub">
<div>
<DeviceName>인터렉션 영상</DeviceName>
<CaptureMove>
<video muted autoPlay loop>
<source type="video/mp4" src={fullMp4} />
</video>
</CaptureMove>
</div>
<Spacing>
{data?.map((val: any, i: any) => (
<GridFrame key={i} className={i === 0 ? 'first' : 'second'}>
<DeviceName>{i === 0 ? 'PC' : 'Mobile'}</DeviceName>
<Grid
layoutId={i}
onClick={() => {
setId(val);
setDevice(i);
func.on();
}}
variants={girdVariants}
initial="start"
whileHover="hover"
>
<img src={val} alt="작업물 이미지" />
</Grid>
</GridFrame>
))}
</Spacing>
<AnimatePresence>
{id ? (
<Modal>
<Overlay
variants={overlay}
onClick={() => {
setId(null);
func.off();
}}
initial="hidden"
animate="visible"
exit="exit"
/>
<GridWhole layoutId={id} style={{ width: device == 1 ? '35%' : '' }}>
<FontAwesomeIcon
icon={faXmark}
onClick={() => {
setId(null);
func.off();
}}
/>
<GridBody>
<img src={id} alt="작업물 이미지" />
</GridBody>
</GridWhole>
</Modal>
) : null}
</AnimatePresence>
</div>
);
}
export default Roball;
import { Spacing, CaptureMove, DeviceName, GridFrame, Grid, Modal, Overlay, GridWhole, GridBody, overlay, girdVariants } from 'js/styled.js';
위와 같이 import 시키면 페이지 어디에서나 사용이 가능하다.
중괄호 {} 안에는 js/styled.js 파일안에서 외부로 사용하려는 변수 명들을 언급해야 한다.
'DEVELOP' 카테고리의 다른 글
[React.js] Cannot find module 'sass' node-sass 버전과 node 버전 맞추기 (1) | 2024.09.10 |
---|---|
[React.js] Cannot find module 'img/full.mp4' or its corresponding type declarations. : React.js video 사용하기 (1) | 2024.09.04 |
[Javascript] IOS 대응을 위한 webm <-> mp4 변환 스크립트 (0) | 2024.07.08 |
React.js) react already included file name (0) | 2024.06.03 |
React.js 기존 프로젝트 다른 로컬 설치 및 실행 (0) | 2024.06.03 |