Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
30b368a
feat: 기본 구조 자성
dioo1461 Feb 4, 2025
4623a7d
feat: DateCell 구현, 외부에서 dynamic으로 cell style 주입할 수 있도록 구현
dioo1461 Feb 4, 2025
c22f406
feat: 캘린더 헤더 구현
dioo1461 Feb 4, 2025
9e29326
feat: 캘린더 렌더링 가능하도록 구현
dioo1461 Feb 5, 2025
596c17b
feat: 날짜 선택 구현, 회색 날짜 선택 시 이전 혹은 다음 달로 넘어가도록 구현
dioo1461 Feb 5, 2025
176867a
feat: Date Cell 스타일 변경
dioo1461 Feb 5, 2025
474fdb3
refactor: calendar 관련 유틸함수의 인자를 {year, month} -> Date 객체 로 변경
dioo1461 Feb 5, 2025
f94014e
refactor: intersperseElement 메서드를 util에 정의
dioo1461 Feb 5, 2025
73e5180
feat: 하이라이트 기능 구현
dioo1461 Feb 5, 2025
fc6d388
feat: calendarType이 'range' 일 시 하이라이트 시작점과 끝점이 selected style을 가지도록 구현
dioo1461 Feb 5, 2025
d7b7caf
refactor: useMonthCalendar -> useDatePicker 로 명칭 변경
dioo1461 Feb 5, 2025
d74ac12
refactor: MonthCalendarContext -> DatePickerContext 로 명칭 변경
dioo1461 Feb 5, 2025
e164314
feat: 주입받은 DatePicker type에 따라 cell style이 달라지도록 구현
dioo1461 Feb 5, 2025
e46fd5a
feat: 하이라이트 끝 날짜가 시작 날짜보다 작을 경우에 대한 예외를 처리
dioo1461 Feb 5, 2025
a326e91
chore: storybook 디렉토리(사이드바)를 Calendar로 변경
dioo1461 Feb 5, 2025
0a21728
feat: storybook에서 calendarType 선택할 수 있도록 구현
dioo1461 Feb 5, 2025
f108e50
feat: highlightGap에도 highlightRange 스타일이 적용되도록 구현
dioo1461 Feb 5, 2025
4c97ae3
feat: dateCell의 타입에 따라 cursorStyle 바뀌도록 구현
dioo1461 Feb 6, 2025
dd3eae7
feat: calendarType이 'range'일 때, 다른 달의 날짜(회색 날짜)의 클릭 이벤트를 무시하도록 구현
dioo1461 Feb 6, 2025
ca1b852
fix: highlight start, end를 같은 날짜로 지정하지 못하도록 수정
dioo1461 Feb 6, 2025
aa95f5b
refactor: Date 객체로부터 year, month, day를 가져오는 getDateParts 유틸 작성 및 적용
dioo1461 Feb 6, 2025
0a3bfd7
refactor: 문자열로 작성된 클래스명에 clsx 유틸을 적용
dioo1461 Feb 6, 2025
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
48 changes: 48 additions & 0 deletions frontend/src/components/Avatar/index.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { style } from '@vanilla-extract/css';
import { recipe } from '@vanilla-extract/recipes';

import { vars } from '@/theme/index.css';

export const avatarContainerStyle = style({
display: 'flex',
alignItems: 'center',
});

export const avatarItemStyle = recipe({
base: {
backgroundColor: vars.color.Ref.Netural['White'],
borderRadius: vars.radius['Max'],
border: `2px solid ${vars.color.Ref.Netural[500]}`,
Comment on lines +13 to +15
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix typo in color variable name.

There's a typo in the color variable name: "Netural" should be "Neutral".

Apply this diff to fix the typo:

-    backgroundColor: vars.color.Ref.Netural['White'],
-    borderRadius: vars.radius['Max'],
-    border: `2px solid ${vars.color.Ref.Netural[500]}`,
+    backgroundColor: vars.color.Ref.Neutral['White'],
+    borderRadius: vars.radius['Max'],
+    border: `2px solid ${vars.color.Ref.Neutral[500]}`,

-    backgroundColor: vars.color.Ref.Netural['White'],
-    color: vars.color.Ref.Netural[500],
-    border: `2px solid ${vars.color.Ref.Netural[100]}`,
+    backgroundColor: vars.color.Ref.Neutral['White'],
+    color: vars.color.Ref.Neutral[500],
+    border: `2px solid ${vars.color.Ref.Neutral[100]}`,

Also applies to: 44-46

},
variants: {
size: {
sm: {
width: '28px',
height: '28px',
selectors: {
'&:not(:first-child)': {
marginLeft: '-12px',
},
},
},
lg: {
width: '42px',
height: '42px',
selectors: {
'&:not(:first-child)': {
marginLeft: '-14px',
},
},
},
},
},
});

export const avatarCountStyle = recipe({
base: {
borderRadius: vars.radius['Max'],
backgroundColor: vars.color.Ref.Netural['White'],
color: vars.color.Ref.Netural[500],
border: `2px solid ${vars.color.Ref.Netural[100]}`,
},
});
2 changes: 1 addition & 1 deletion frontend/src/components/Calendar/Calendar.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ export default meta;

type Story = StoryObj<typeof meta>;

export const Primary: Story = {};
export const Primary: Story = {};
24 changes: 24 additions & 0 deletions frontend/src/components/DatePicker/DatePicker.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Meta, StoryObj } from '@storybook/react';

import DatePicker from '.';

const meta: Meta = {
title: 'Calendar/DatePicker',
component: DatePicker,
argTypes: {
calendarType: {
control: { type: 'radio' },
options: ['select', 'range'],
},
},
} satisfies Meta<typeof DatePicker>;

export default meta;

type Story = StoryObj<typeof DatePicker>;

export const Default: Story = {
args: {
calendarType: 'select',
},
};
Comment on lines +20 to +24
Copy link
Contributor

Choose a reason for hiding this comment

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

p3;
기능적으로 큰 차이라서, range 타입 스토리도 추가해주시면 좋을 것 같습니다.

12 changes: 12 additions & 0 deletions frontend/src/components/DatePicker/DatePickerContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createContext } from 'react';

import type { UseMonthCalendarReturn } from '@/hooks/useDatePicker';

import type { CellStyleProps, DatePickerProps } from '.';

interface DatePickerContextProps extends UseMonthCalendarReturn, DatePickerProps {
todayCellStyle: CellStyleProps;
selectedCellStyle: CellStyleProps;
}

export const DatePickerContext = createContext<DatePickerContextProps | null>(null);
17 changes: 17 additions & 0 deletions frontend/src/components/DatePicker/Header/index.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { style } from '@vanilla-extract/css';

export const headerStyle = style({
display: 'flex',
paddingLeft: '8px',
justifyContent: 'space-between',
alignItems: 'center',
alignSelf: 'stretch',
});

export const chevronWrapper = style({
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: 32,
height: 32,
});
49 changes: 49 additions & 0 deletions frontend/src/components/DatePicker/Header/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Flex } from '@/components/Flex';
import { ChevronLeft, ChevronRight } from '@/components/Icon';
import { Text } from '@/components/Text';
import { useSafeContext } from '@/hooks/useSafeContext';
import { vars } from '@/theme/index.css';
import { getDateParts } from '@/utils/date/calendar';

import { DatePickerContext } from '../DatePickerContext';
import { chevronWrapper, headerStyle } from './index.css';

const Header = () => {
const {
baseDate,
goToPrevMonth,
goToNextMonth,
} = useSafeContext(DatePickerContext);
const { year: currentYear, month: currentMonth } = getDateParts(baseDate);
return (
<div className={headerStyle}>
<Text typo='b1M'>{`${currentYear}년 ${currentMonth + 1}월`}</Text>
<Flex direction='row'>
<span className={chevronWrapper}>
<ChevronLeft
aria-label='이전 달로 이동'
clickable={true}
fill={vars.color.Ref.Netural[500]}
onClick={goToPrevMonth}
onKeyDown={(e) => e.key === 'Enter' && goToPrevMonth()}
role='button'
tabIndex={0}
/>
</span>
<span className={chevronWrapper}>
<ChevronRight
aria-label='다음 달로 이동'
clickable={true}
fill={vars.color.Ref.Netural[500]}
onClick={goToNextMonth}
onKeyDown={(e) => e.key === 'Enter' && goToNextMonth()}
role='button'
tabIndex={0}
/>
</span>
</Flex>
</div>
);
};

export default Header;
31 changes: 31 additions & 0 deletions frontend/src/components/DatePicker/Table/Cell/CellWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

import type { PropsWithChildren } from 'react';

import clsx from '@/utils/clsx';

import { Text } from '../../../Text';
import { cellWrapperStyle } from './index.css';

interface CellWrapperProps extends PropsWithChildren {
cursorType: 'default' | 'pointer' | 'not-allowed';
className?: string;
style?: object;
onClick?: () => void;
}
export const CellWrapper = ({
className,
cursorType,
style,
onClick,
children,
}: CellWrapperProps) => (
<div
className={clsx(cellWrapperStyle({ cursorType }), className )}
onClick={onClick}
style={style}
>
<Text typo='caption'>{children}</Text>
</div>
);

export default CellWrapper;
104 changes: 104 additions & 0 deletions frontend/src/components/DatePicker/Table/Cell/DateCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { assignInlineVars } from '@vanilla-extract/dynamic';

import { useDateSelect } from '@/hooks/useDatePicker/useDateSelect';
import { useSafeContext } from '@/hooks/useSafeContext';
import { isSameDate, isSaturday, isSunday } from '@/utils/date';

import type { CalendarType } from '../..';
import { DatePickerContext } from '../../DatePickerContext';
import type { HighlightState } from '../Highlight';
import { cellThemeVars } from '../index.css';
import CellWrapper from './CellWrapper';
import {
holidayCellStyle,
otherMonthCellStyle,
saturdayCellStyle,
selectedCellStyle,
todayCellStyle,
weekdayCellStyle,
} from './index.css';

export interface DateCellProps {
date: Date;
baseDate: Date;
selected: boolean;
highlightState: HighlightState;
}

export const DateCell = ({ date, selected, baseDate, highlightState }: DateCellProps) => {
const {
calendarType,
todayCellStyle,
selectedCellStyle,
} = useSafeContext(DatePickerContext);
const inlineCellStyles = assignInlineVars(cellThemeVars, {
todayCellBackgroundColor: todayCellStyle.backgroundColor ?? 'transparent',
todayCellColor: todayCellStyle.color ?? 'transparent',
selectedCellBackgroundColor: selectedCellStyle.backgroundColor ?? 'transparent',
selectedCellColor: selectedCellStyle.color ?? 'transparent',
});

Comment on lines +34 to +40
Copy link
Contributor

Choose a reason for hiding this comment

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

just ask;
assignInlineVars로 넣어주신 이유가 있나요??!

Copy link
Contributor Author

@dioo1461 dioo1461 Feb 6, 2025

Choose a reason for hiding this comment

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

원래 스타일을 외부에서 주입하게 설계했다가 도중에 튼 거라, 나중에 css 내부에서 정의하도록 리팩터링해보겠습니다!

+ 스타일이 런타임에 변할 일이 없으니 inline을 쓸 필요가 없었군요,, 아무튼 추후 리팩터링해보겠습니다!

const dateCellType = getDateCellType(date, calendarType, selected, baseDate, highlightState);
const selectDate = useDateSelect(date);
const handleDateCellClick = () => {
if (calendarType === 'range' && dateCellType === 'otherMonth') return;
selectDate();
};
// TODO: cell에 대한 cursor style과 컨트롤을 묶어서 처리할 방법 모색
return (
<CellWrapper
className={getDateCellStyle(dateCellType)}
cursorType={calendarType === 'range' && dateCellType === 'otherMonth'
? 'not-allowed'
: 'pointer'}
onClick={handleDateCellClick}
style={inlineCellStyles}
>
{date.getDate()}
</CellWrapper>
);
};

type DateCellType = 'weekday' | 'saturday' | 'holiday' | 'otherMonth' | 'today' | 'selected';

const getDateCellType = (
date: Date,
calendarType: CalendarType,
selected: boolean,
baseDate: Date,
highlightState: HighlightState,
): DateCellType => {
if (selected) return 'selected';
if (calendarType === 'range' && (
highlightState === 'startOfRange' || highlightState === 'endOfRange'
)) {
return 'selected';
}

if (calendarType === 'select' && isSameDate(date, new Date())) return 'today';
if (date.getMonth() !== baseDate.getMonth()) return 'otherMonth';
// TODO: 공휴일도 함께 체크
if (isSunday(date)) return 'holiday';
if (isSaturday(date)) return 'saturday';
return 'weekday';
};

const getDateCellStyle = (
dateCellType: DateCellType,
) => {
switch (dateCellType) {
case 'selected':
return selectedCellStyle;
case 'today':
return todayCellStyle;
case 'otherMonth':
return otherMonthCellStyle;
case 'holiday':
return holidayCellStyle;
case 'saturday':
return saturdayCellStyle;
case 'weekday':
default:
return weekdayCellStyle;
}
};
13 changes: 13 additions & 0 deletions frontend/src/components/DatePicker/Table/Cell/DowCell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { PropsWithChildren } from 'react';

import CellWrapper from './CellWrapper';

interface DowCellProps extends PropsWithChildren {
className: string;
}

export const DowCell = ({ className, children }: DowCellProps) => (
<CellWrapper className={className} cursorType={'default'}>
{children}
</CellWrapper>
);
57 changes: 57 additions & 0 deletions frontend/src/components/DatePicker/Table/Cell/index.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { style } from '@vanilla-extract/css';
import { recipe } from '@vanilla-extract/recipes';

import { vars } from '@/theme/index.css';

import { cellThemeVars } from '../index.css';

export const cellWrapperStyle = recipe({
base: {
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '24px',
height: '24px',
},
variants: {
cursorType: {
pointer: {
cursor: 'pointer',
},
default: {
cursor: 'default',
},
'not-allowed': {
cursor: 'not-allowed',
},
},
},
});

export const weekdayCellStyle = style({
color: vars.color.Ref.Netural[700],
});

export const todayCellStyle = style({
borderRadius: vars.radius[200],
backgroundColor: cellThemeVars.todayCellBackgroundColor,
color: cellThemeVars.todayCellColor,
});

export const selectedCellStyle = style({
borderRadius: vars.radius[200],
backgroundColor: cellThemeVars.selectedCellBackgroundColor,
color: cellThemeVars.selectedCellColor,
});

export const otherMonthCellStyle = style({
color: vars.color.Ref.Netural[400],
});

export const saturdayCellStyle = style({
color: vars.color.Ref.Primary[500],
});

export const holidayCellStyle = style({
color: vars.color.Ref.Red[500],
});
2 changes: 2 additions & 0 deletions frontend/src/components/DatePicker/Table/Cell/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './DateCell.tsx';
export * from './DowCell.tsx';
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

import type { HighlightProps } from '.';
import { highlightBoxStyle } from './index.css';

const HighlightBox = ({ highlightState, children }: HighlightProps) => (
<div className={highlightBoxStyle({ highlightState })}>
{children}
</div>
);

export default HighlightBox;
Loading