Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] 캘린더 v2 변경 #328

Open
wants to merge 19 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/components/common/Icon.tsx
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제 pc 상에서만 깨지는 거일 가능성이 높은데요..(pr에는 잘 보여서)
요거 정렬 혹시 왜 이럴까유,, 👀
스크린샷 2025-01-06 오후 10 01 44

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

스크린샷 2025-01-08 22 30 12

오잉 이 부분은 SubDate 컴포넌트 사용한건데, 혹시 이전 pr 확인하실때에도 이런 문제 있으셨을까요????
스토리북 확인해도 중앙에 맞게 떠서.. 글씨체 먹었는 지 확인 부탁드립니다

Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ type IconProps = {
size?: 'tiny' | 'small' | 'medium' | 'large' | 'xlarge';
color?: 'nomal' | 'strong' | 'heavy' | 'primary' | 'inverse';
onClick?: () => void;
isCusor?: boolean;
isCursor?: boolean;
};

function Icon({ name, size = 'medium', color, onClick, isCusor }: IconProps) {
function Icon({ name, size = 'medium', color, onClick, isCursor }: IconProps) {
const SelectedIcon = Icn[name];
return (
<StyledIconWrapper size={size} color={color} onClick={onClick} isCusor={isCusor}>
<StyledIconWrapper size={size} color={color} onClick={onClick} isCursor={isCursor}>
<SelectedIcon />
</StyledIconWrapper>
);
Expand All @@ -41,15 +41,15 @@ const getColorMap = (theme: Theme) => ({
const StyledIconWrapper = styled.div<{
size: 'tiny' | 'small' | 'medium' | 'large' | 'xlarge';
color?: 'nomal' | 'strong' | 'heavy' | 'primary' | 'inverse';
isCusor?: boolean;
isCursor?: boolean;
}>`
display: flex;
align-items: center;
justify-content: center;
width: ${({ size }) => sizeMap[size]};
height: ${({ size }) => sizeMap[size]};

${({ isCusor }) => isCusor && `cursor: pointer;`}
${({ isCursor }) => isCursor && `cursor: pointer;`}

svg {
width: 100%;
Expand Down
43 changes: 43 additions & 0 deletions src/components/common/fullCalendar/CalendarHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import styled from '@emotion/styled';

import IconButton from '../v2/IconButton';
import MainDate from '../v2/TextBox/MainDate';

type Props = {
size: 'small' | 'big';
date: { year: number; month: number };
};

function CalendarHeader({ size, date }: Props) {
return (
<CalendarHeaderContainer size={size}>
<MainDate year={date.year} month={date.month} />
<CalendarHeaderWrapper>
<IconButton type="normal" size="small" iconName="IcnCalendar" />
<IconButton type="normal" size="small" iconName="IcnFilter" />
</CalendarHeaderWrapper>
</CalendarHeaderContainer>
);
}

export default CalendarHeader;

const CalendarHeaderContainer = styled.div<{ size: string }>`
position: absolute;
top: 56px;
display: flex;
align-items: flex-start;
justify-content: space-between;
box-sizing: border-box;
width: 100%;
height: auto;
padding: ${({ size }) => (size === 'big' ? '0 2.4rem;' : '0 1.6rem 0 2.4rem;')};
`;

const CalendarHeaderWrapper = styled.div`
display: flex;
gap: 194px;
margin-top: 0.2rem;

color: ${({ theme }) => theme.colorToken.Icon.normal};
`;
127 changes: 127 additions & 0 deletions src/components/common/fullCalendar/CustomDayCellContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/* eslint-disable no-nested-ternary */
import { css } from '@emotion/react';
import styled from '@emotion/styled';
import { DayCellContentArg } from '@fullcalendar/core';
import { useState } from 'react';

import { theme } from '@/styles/theme';

const TYPE = {
TERITARY: 'Teritary',
SECONDARY: 'Secondary',
PRIMARY: 'Primary',
} as const;

const STATE = {
DEFAULT: 'Default',
HOVER: 'Hover',
PRESSED: 'Pressed',
} as const;

type StateType = (typeof STATE)[keyof typeof STATE];

interface CustomDayCellContentProps {
arg: DayCellContentArg;
today: string;
selectDate?: string;
}

// 월간 달력에서 날짜 '일' 제거 및 스타일링 적용
function CustomDayCellContent({ arg, today, selectDate }: CustomDayCellContentProps) {
const date = new Date(arg.date);
const day = arg.dayNumberText.replace('일', '');
const isSelectedDate = date.toDateString() === selectDate;
const isToday = date.toDateString() === today;
const [state, setState] = useState<StateType>(STATE.DEFAULT);

const type = isToday ? TYPE.PRIMARY : isSelectedDate ? TYPE.SECONDARY : TYPE.TERITARY;

const handleStateChange = (newState: StateType) => () => {
setState(newState);
};

if (arg.view.type === 'dayGridMonth') {
return (
<MonthViewDate
type={type}
state={state}
onMouseEnter={handleStateChange(STATE.HOVER)}
onMouseLeave={handleStateChange(STATE.DEFAULT)}
onMouseDown={handleStateChange(STATE.PRESSED)}
onMouseUp={handleStateChange(STATE.DEFAULT)}
isSelectedDate={isSelectedDate}
isToday={isToday}
>
{arg.view.type === 'dayGridMonth' ? day : ''}
</MonthViewDate>
);
}
}

export default CustomDayCellContent;

const backgroundStyles = {
Teritary: {
Default: 'transparent',
Hover: theme.colorToken.Primary.strongVariant,
Pressed: theme.colorToken.Primary.heavyVariant,
},
Secondary: {
Default: 'transparent',
Hover: theme.colorToken.Primary.strongVariant,
Pressed: theme.colorToken.Component.heavy,
},
Primary: {
Default: theme.colorToken.Primary.normal,
Hover: theme.colorToken.Primary.strong,
Pressed: theme.colorToken.Primary.heavy,
},
};

const textStyles = {
Teritary: theme.colorToken.Text.neutralLight,
Secondary: theme.colorToken.Text.primary,
Primary: theme.colorToken.Text.neutralDark,
};

const MonthViewDate = styled.div<{
type: keyof typeof backgroundStyles;
state: keyof (typeof backgroundStyles)['Teritary'];
isSelectedDate: boolean;
isToday: boolean;
}>`
display: flex;
align-items: center;
justify-content: center;
width: 2.4rem;
height: 2.4rem;

border-radius: 6px;

${({ theme }) => theme.font.label03};

${({ type, state }) => css`
color: ${textStyles[type]};

background-color: ${backgroundStyles[type][state]};

${type === TYPE.SECONDARY && underlineStyle}
`}
`;

const underlineStyle = css`
position: relative;

&::after {
position: absolute;
bottom: 2px;
left: 50%;
width: 3.2rem;
height: 0.1rem;

background-color: ${theme.colorToken.Text.primary};
transform: translateX(-50%);

content: '';
}
`;
59 changes: 32 additions & 27 deletions src/components/common/fullCalendar/DayHeaderContent.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,55 @@
/* eslint-disable no-nested-ternary */
import styled from '@emotion/styled';
import { DayHeaderContentArg } from '@fullcalendar/core';

import SubDate from '../v2/TextBox/SubDate';

interface DayHeaderContentProps {
arg: DayHeaderContentArg;
currentView: string;
today: string;
selectDate?: string;
size: string;
}

function DayHeaderContent({ arg, currentView, today }: DayHeaderContentProps) {
function DayHeaderContent({ arg, currentView, today, selectDate, size }: DayHeaderContentProps) {
let adjustDay = size === 'big' ? 3 : 2;
if (currentView === 'dayGridMonth') {
adjustDay = 0;
}
const adjustedDate = new Date(arg.date);
adjustedDate.setDate(adjustedDate.getDate() - adjustDay);

const isTimeGridDay = currentView === 'timeGridDay';
const day = new Intl.DateTimeFormat('en-US', { weekday: isTimeGridDay ? 'long' : 'short' }).format(arg.date);
const date = arg.date.getDate();
const isToday = arg.date.toDateString() === today;
const day = new Intl.DateTimeFormat('ko', { weekday: isTimeGridDay ? 'long' : 'short' }).format(adjustedDate);
const date = adjustedDate.getDate();
const isSelectedDate = adjustedDate.toDateString() === selectDate;
const isToday = adjustedDate.toDateString() === today;
const isSatday = day === '토';
const isSunday = day === '일';

return (
<div>
{!isTimeGridDay ? (
<>
<WeekDay isToday={isToday}>{day}</WeekDay>
{currentView !== 'dayGridMonth' && <WeekDate isToday={isToday}>{date}</WeekDate>}
</>
{currentView === 'dayGridMonth' ? (
<WeekDay isSatday={isSatday} isSunday={isSunday}>
{day}
</WeekDay>
) : (
<DayLayout>
<WeekDate isToday={false}>{date}일</WeekDate> <WeekDay isToday={false}>{day}</WeekDay>
</DayLayout>
<SubDate
day={date.toString()}
weekDay={day.toString()}
type={isToday ? 'Primary' : isSelectedDate ? 'Secondary' : 'Teritary'}
/>
)}
</div>
);
}

const DayLayout = styled.div`
display: flex;
gap: 1.2rem;
align-items: flex-end;
margin-left: 0.8rem;
`;

const WeekDay = styled.div<{ isToday: boolean }>`
${({ theme }) => theme.fontTheme.CAPTION_02};
color: ${({ isToday, theme }) => (isToday ? theme.palette.Blue.Blue11 : theme.palette.Grey.Grey6)};
const WeekDay = styled.div<{ isSatday: boolean; isSunday: boolean }>`
${({ theme }) => theme.font.label04};
color: ${({ isSatday, isSunday, theme }) =>
isSatday ? theme.color.Blue.Blue7 : isSunday ? theme.color.Orange.Orange5 : theme.color.Grey.Grey5};
text-transform: uppercase;
`;

const WeekDate = styled.div<{ isToday: boolean }>`
${({ theme }) => theme.fontTheme.HEADLINE_01};
color: ${({ isToday, theme }) => (isToday ? theme.palette.Primary : theme.palette.Grey.Black)};
`;

export default DayHeaderContent;
Loading
Loading