디자인 시안과 똑같은 캘린더를 만들고 싶었는데, 라이브러리를 사용하면 스타일 적용이 불가능할 것 같아서 아예 자바스크립트로 새로이 만들었다. 참고 블로그 의 코드를 거의 똑같이 따라 작성한 것에 불과하지만 그 과정에서 나도 바닐라 자바스크립트를 많이 배웠다. 더 나아가 이 글이 또 다른 누군가에게 도움이 되길 바라며 쓰는 글!
(그림이...😅)
달과 연도가 있는 RenderHeader, 요일이 있는 RenderDays, 날짜가 있는 RenderCells로 컴포넌트를 나눌 것이다.
export const RenderHeader = ({ currentMonth, prevMonth, nextMonth }: headerProps) => {
return (
<CalHeader className="header row">
<div className="col col-1">
<Expand onClick={prevMonth} />
</div>
<MonthYear className="col col-2">
<span>
<span>{format(currentMonth, "M")} </span>
{format(currentMonth, "yyyy")}
</span>
</MonthYear>
<div className="col col-3">
<Expand onClick={nextMonth} />
</div>
</CalHeader>
);
};
export const RenderDays = () => {
const days = [];
const date = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
for (let i = 0; i < 7; i++) {
days.push(
<Days className="col" key={i}>
{date[i]}
</Days>
);
}
return <div className="days row">{days}</div>;
};
const Cells = styled.div`
font-size: 1rem;
`;
const DayBox = styled.div`
padding: 0;
width: fit-content;
`
type dayprops = {
display: string;
};
const Day = styled.span<dayprops>`
display: ${(props) => (props.display === 'true' ? "block" : "none")};
`;
export const RenderCells = ({
currentMonth,
onDateClick,
}: headerProps) => {
const monthStart = startOfMonth(currentMonth);
const monthEnd = endOfMonth(monthStart);
const startDate = startOfWeek(monthStart);
const endDate = endOfWeek(monthEnd);
const rows = [];
let days = [];
let day = startDate;
let formattedDate = "";
while (day <= endDate) {
for (let i = 0; i < 7; i++) {
formattedDate = format(day, "d");
const cloneDay = day;
days.push(
<DayBox className="col cell">
<Day display={isSameMonth(day, monthStart) ? 'true' : 'false'}>
{formattedDate}
</Day>
</DayBox>
);
day = addDays(day, 1);
}
rows.push(<div className="row">{days}</div>);
days = [];
}
return <Cells className="cells">{rows}</Cells>;
};
monthStart : 현재 날짜가 속한 달의 첫 날
monthEnd : 현재 날짜가 속한 달의 마지막 날
startDate : monthStart가 속한 주의 첫 날
endDate : monthEnd가 속한 주의 마지막 날
먼저 for문을 이용해 days 배열에 startDate부터 시작해서 7개씩 날짜를 넣는다. 변수 day의 최초값은 startDate이며, 배열에 push된 후 1씩 증가한다.
days가 7개로 가득 차면 for문이 종료되며 rows 배열에 days가 통째로 들어간다. 그리고 days는 비워진다.
day가 endDate와 같아지면 while문이 종료되며, 전체 rows 배열이 리턴된다.
이전/다음 달의 날짜는 표시하고 싶지 않아서 isSameMonth 메소드를 이용해서 조건부 스타일링을 했다. (display none을 쓰면 웹 접근성을 무시하게 된다는데 일단 넘어가고 다음에 다시 알아볼래...)
👀 scss 파일이 연결이 안되어있는데 grid가 어떻게 적용되는지 모르겠어서 참고 블로그에 문의해놓았음