격조하였습니다.
저는 22년 9월을 마지막으로 포스팅을 하지 않고 있었는데요,
입사 이후 일에 치여 글을 쓸 수 있는 시간과 정신이 없었습니다.
직장인일 때의 나
그리고 지난 24년 11월을 기점으로 퇴사를 하게 되어, 햇살이란게 원래 이렇게 따스했는지..
세상이 이렇게 평화로웠는지를 되새기는 시간을 가졌습니다.
그러나 행복한 시간도 잠시, 금전적으로 불안해지기 시작했습니다.
퇴사 후의 나
재취업을 하려면 어떡해야 할까요?
이력서를 써야겠죠.
그래서 이력서 겸 자기소개 사이트를 만들었습니다.
이 글은 기록용이긴 하지만 평소 자기소개 사이트를 어떻게 만들까 고민하시던 분들이 보시면 될 것 같습니다.
완성본부터 보고 싶으신 분은, 이곳으로 방문하시면 되겠습니다.
Q. 원x드 같은 취업 사이트에서 이력서를 기본으로 제공하는데 왜 또 만드는지?
A. 그냥 제 취향대로 만들고 싶어서요.
일단 목표는 빠르게 사이트를 만드는 것이므로 곧장 밑작업부터 들어갑니다.
이것만 해도 벌써 진이 빠진다.
Figma를 이용하여 화면의 기본적인 레이아웃과 요소를 잡아둡니다.
이력서 사이트에 어떤 내용을 넣을지는 간략하게 메모장이나 노션을 이용해 목차, 핵심 내용들을 적어두었습니다.
나중에 컴포넌트를 만들 때 유용하게 쓰일 메인 컬러 코드나 타이포그라피 같은 것들은 미리 수치를 정해두는 게 좋습니다.
저의 경우 아래와 같은 것들을 컴포넌트화 시켰어요.
- 헤드라인(주황색은 마진값입니다.)
- 텍스트 타이포 스타일!(PC,모바일별로 크기가 달라집니다.)
3.태그나 버튼 같은 디자인적 요소들
요소들이 완성되면 PC 화면 레이아웃부터 디자인합니다. 모바일 화면은 PC 화면이 완료된 후 간단하게 레이아웃을 조정합니다. 저의 경우는 PC 너비 기준을 1000px, 모바일은 320px을 최소 기준으로 맞춰두었어요.
이정도만 간략하게 잡아둬도 작업할때 굉장히 편합니다.
이제 어떤 식으로 만들지를 고민해야 합니다.
평소에도 vue.js를 눈여겨보고 있던 터라 프레임워크 공부 겸 vue를 이용해볼까? 했지만
대차게 망했습니다.
튜토리얼에서 보여준 vue의 문법을 곧바로 작업에 써먹어보자니 안되는 것 투성이였습니다.
저는 prettier/eslint 설정이라던가, typescript 설치, sass 설치, styled-component 라이브러리를 설치하는 과정 등에서 vue와 온갖 충돌이 났지요.
이 속도면 한달 내로 만들 수 없다는 판단이 섰고, 일단은 익숙한 React를 이용해 제작하기로 했습니다.
아토믹 디자인을 활용한 디자인 시스템에 익숙해지기 위해 templates, organisms, molcules,atoms
폴더 별로 나누어 보았습니다.
atoms > molcules > organisms > templates
순으로 컴포넌트의 규모가 확대됩니다.
상단의 common 컴포넌트는 제가 디자인 단계에서 정해둔 타이포 스타일 같은 것들이 등록되어 있습니다.
data 폴더에는 객체 형식으로 지정해 둔 정적 텍스트 파일이나 링크 등이 한꺼번에 모여 있습니다.
import { ThemeProvider } from "styled-components";
import { theme } from "@/styles/theme";
import { ResetCss } from "@/styles/reset";
import { GlobalStyle } from "@/styles/global";
import { useMediaQuery } from "react-responsive";
import MainLayout from "./components/system/templates/MainLayout";
function App() {
//mediaQuery
const isMobile = useMediaQuery({ query: "(max-width:1023px)" });
return (
<ThemeProvider theme={theme}>
<ResetCss />
<GlobalStyle />
<MainLayout isMobile={isMobile} />
</ThemeProvider>
);
}
export default App;
index.tsx
에 들어가는 최상단 컴포넌트입니다.
반응형 감지를 빠르게 하기 위해 react-responsive 라이브러리와 제게 익숙한 styled-componenet를 사용했습니다.
useMediaQuery 훅으로 <MainLaout>
컴포넌트에 isMobile이라는 값을 전달해줍니다. 윈도우 창이 1024px밑으로 떨어지면 모바일 레이아웃으로 전환될거에요.
import Header from "../organisms/Header";
import Footer from "../organisms/Footer";
import { useRef, useState, useEffect } from "react";
import CareerSection from "./CareerSection";
import DirectionSection from "./DirectionSection";
export interface IMainLayout {
isMobile: boolean;
}
/**
* 메인 페이지
* @param isMobile
* @returns
*/
const MainLayout = ({ isMobile }: IMainLayout) => {
const pointRef = useRef<HTMLDivElement>(null);
const START_POINT = 150;
const [isPoint, setIsPoint] = useState<boolean>(false);
const setPoint = () => {
const isReachPoint = window.scrollY >= START_POINT;
if (isReachPoint !== isPoint) setIsPoint(isReachPoint);
};
useEffect(() => {
window.addEventListener("scroll", setPoint);
return () => {
window.removeEventListener("scroll", setPoint);
};
}, [isPoint, pointRef]);
return (
<>
<Header isScroll={isPoint} isMobile={isMobile} />
<CareerSection isMobile={isMobile} isPoint={isPoint} />
<DirectionSection isMobile={isMobile} />
<Footer isMobile={isMobile} />
</>
);
};
export default MainLayout;
<MainLayout/>
컴포넌트의 코드 전문입니다.
보시는 것처럼 헤더 / 섹션 2개 / 푸터의 구조로 이루어졌습니다.
이 녀석들도 모바일 레이아웃 여부에 따라 디자인이 바뀌기 때문에 props로 isMobile
을 받아옵니다.
상단에 있는 pointRef
라던가 setPoint
, state 상태 관리, useEffect로 이벤트리스너를 추가한 코드는 모두 스크롤 액션을 넣기 위한 것입니다. 사이트를 직접 보신다면 알겠지만 순전히 헤더에 애니메이팅을 주기 위해 저만큼 들어간 거죠. 정말 귀찮습니다.
<CareerSection/>
과 <DirectionSection/>
컴포넌트는 상당히 많은 콘텐츠를 가지고 있고, 여러 개의 organism으로 이루어져 있기 때문에 templates 폴더에 들어가 있습니다. 그 중 하나를 보여드립니다.
import { Container } from "@/components/common/component";
import { ListWrap } from "./styles";
import TitleWithDot from "../atoms/TitieWithDot";
import { careerData } from "@/data/static";
import CareerList from "../organisms/CareerList";
import { IMainLayout } from "./MainLayout";
import MobileCareerList from "../organisms/CareerList/MobileCareerList";
/**
* 경력기술 섹션
* @param isMobile
* @param isPoint
* @returns
*/
interface ICareerSection extends IMainLayout {
isPoint: boolean;
}
const CareerSection = ({ isMobile, isPoint }: ICareerSection) => {
const title = "어떤 경험을 했나요?";
return isMobile ? (
<Container padding="30px 20px 70px" width="100%">
<TitleWithDot title={title} isMobile />
<ListWrap>
{careerData.map((career, index) => (
<MobileCareerList
careerData={career}
showDivider={index < careerData.length - 1}
key={`career-${index}`}
/>
))}
</ListWrap>
</Container>
) : (
<Container
padding={"50px 0 150px"}
margin={isPoint ? "200px auto 0" : undefined}
>
<TitleWithDot title={title} />
<ListWrap>
{careerData.map((career, index) => (
<CareerList
careerData={career}
showDivider={index < careerData.length - 1}
key={`career-${index}`}
/>
))}
</ListWrap>
</Container>
);
};
export default CareerSection;
title 부분을 변수로 따로 관리하는군요!
이러한 텍스트들은 보통 정적 데이터(static data)를 관리하는 폴더에 집어넣어 분리하는게 좋다고 생각합니다. 하지만 이건 제 사이트니까 제 마음대로 할겁니다.
isMobile
값을 내려받은 이 섹션들은 true일 시 모바일 레이아웃으로 변경됩니다. 보시는 것과 같이 컴포넌트의 css 값이 각자 다른 것을 확인할 수 있습니다.
그냥 하나의 구조로 만들어두고
isMobile
에 따라서 css값만 변경하는 식으로 할 수 있지 않는가?
저도 신입 때는 그렇게 생각했으나 조건에 따라서 레이아웃(HTML 구조) 자체가 변경되는 일을 종종 겪어보니, 차라리 pc화면과 모바일 화면을 따로 관리하여 디자인 이슈를 최소화하는게 효율적이라는 걸 깨달았습니다.
화면을 그려본 사람이라면 정렬과 간격에 굉장히 민감한 디자이너들의 무서움을 잘 아시겠죠..
어쨌든 모든 컴포넌트들은 저렇게 만들어졌습니다.
다른 컴포넌트와 전체적인 파일 구조는, github에서 확인하실 수 있습니다.
사실 로컬 프로젝트를 만드는 것까진 크게 어렵지 않다는걸 다들 아실겁니다.
제게 아직 배포 경험은 옛날에 호스팅 서비스로 도메인을 사고, FTP를 이용하여 파일을 통째로 집어넣은 게 전부라서 어떤 식으로 배포를 해야 할지 조금 두려웠습니다.
그리고 깃허브를 이용하신 분이라면 한번쯤 사용하셨을 법한 github page를 사용하기로 합니다.(전 돈이 없어요.)금전적인 여유가 된다면 언젠가 도메인을 사서 쓰고 싶네요.
깃허브 리포지토리 > settings 에서 사용이 가능합니다. 자세한 이용 방법은 https://docs.github.com/ko/pages/quickstart 에서 확인이 가능합니다.
사실상 page를 만들면 한마디로 '집터'를 마련해주는 것이기 때문에, 이것으로 끝은 아닙니다.
내가 만약에 코드를 바꿔 origin 레포지토리에 커밋한다 해도, 웹페이지에서 보여지는 화면이 바뀌진 않기 때문에 gh-pages
라는 npm 패키지를 추가로 설치해줘야 합니다.
내가 작업하던 vs코드 터미널에서 npm install gh-pages --save-dev
로 설치해줍니다.
설치가 완료되면 package.json
파일에 들어가 몇 가지 스크립트를 추가합니다.
- homepage
package.json 객체 중 맨 마지막 줄에 'homepage'라는 key를 하나 추가해줍니다. 값은 github page로 생성된 도메인을 그대로 적어주면 됩니다."homepage": "https://seraleedev.github.io/resume/"
- scripts
"scripts"
key 값에 추가 스크립트를 적어줍니다.
"predeploy": "npm run build" "deploy": "gh-pages -d build"
package.json의 설정이 완료되면 터미널에서 npm run deploy
를 실행합니다. 이 한 줄로 npm run build
까지 자동으로 실행되며 gh-pages가 origin 레포지토리에 배포될 파일을 보냅니다.
한마디로 코드를 고칠 경우, 변경된 코드를 원격 레포에 커밋 후
npm run deploy
를 해주면 그때 변경사항이 적용되는거죠.
depoly 스크립트를 추가한 뒤 github page 세팅에서 브랜치 루트를 gh-pages로 변경해주어야 합니다.
저 설정을 바꿔주는 것은 단순히 배포를 위한 것이므로, 이후에는 master 브랜치에서 코드를 커밋하면 됩니다. 굳이 gh-pages로 브랜치를 바꿀 필요가 없습니다. npm run deploy
를 하면, 내 레포지토리의 'Actions' 탭에서 배포중인 프로젝트를 확인할 수 있습니다.
이렇게 자기소개 사이트 배포까지 완료된 상태입니다.
처음에는 이 내용을 바로 인쇄할 수 있도록 따로 인쇄용 레이아웃을 만들어 pdf로 다운받는 기능을 만들었으나, 시간이 지나고 내용이 추가되거나 변경됨에 따라 인쇄용 레이아웃도 따로 만져 주어야 하는 불편함이 생겨 인쇄 버튼은 주석으로 처리해두었습니다. 더군다나 공개적으로 보여지는 자기소개 사이트에서는 개인정보같은 민감한 정보를 담기에도 어렵고요. 아직 고쳐 나가야 할 것이 많다는 생각이 듭니다.
질문이 있다면, 언제든지 댓글 남겨주세요!