-
Notifications
You must be signed in to change notification settings - Fork 0
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: 스터디 생성 페이지 재작성, 구조 재정의 #154
Merged
Merged
Changes from 109 commits
Commits
Show all changes
115 commits
Select commit
Hold shift + click to select a range
95c39e3
feat: 스터디 생성 페이지 재작성, 구조 재정의
abiriadev 1926dfd
feat: 스터디 생성 폼을 위한 범용 SelectBox 컴포넌트 추가
abiriadev 5af9ab4
fix: SelectBox가 `label`, `values` prop을 가지지 않더라도 에러가 나지 않도록 허용
abiriadev 92e8db3
fix: 스터디 생성 타입 정의 및 RHF 바인딩
abiriadev b17110b
fix: select 필드 빠진 스타일 적용
abiriadev 11a17d7
feat: <form> 요소 스타일 추가, 하위 섹션 요소 컴포넌트로 분리
abiriadev d59fb3d
fix: SelectBox의 label 방향을 세로로 교정
abiriadev cce8acb
feat: SelectBox의 기본값 추가
abiriadev 28e2fc0
feat: 기본값 추가
abiriadev d9cddbc
feat: 구분선 추가 및 스타일 반영
abiriadev 384255e
Merge branch 'dev' into feat/create-study
abiriadev 581a205
feat: 스터디 생성을 위한 API 정의
abiriadev a0493dd
feat: 카테고리 생성시 사용할 타입 정의 추가
abiriadev 7207c68
feat: 새로 정의한 스터디 생성용 타입을 인자로 허용
abiriadev 65d6789
fix: 스터디 생성 페이지로의 라우터 다시 복구
abiriadev 9c3bbf5
fix: 수정된 Pretendard600 폰트 사용 및 스타일 수정
abiriadev 0b451ef
fix: 오타 수정
abiriadev 5de8921
feat: 수정 가능한 드롭다운 아이콘 허용
abiriadev 081d495
style: 셀렉트 박스 기본 화살표 스타일 제거
hyosin-Jang 6872bd3
feat: Heading 컴포넌트 추가 (WIP)
hyosin-Jang 6e5586b
feat: Stack 컴포넌트 정의
abiriadev c592cb1
refactor: 사전 등록된 버튼 컴포넌트 사용
abiriadev bb873b9
refactor: 패딩을 `<PageWrapper />` 컴포넌트로 대체
abiriadev 860ec46
feat: 디자인 시스템에서 미구현된 `<BoldDivider />` 구현
abiriadev e189cd6
feat: shared에서 정의된 선택지 적용
abiriadev f52d3b7
fix: 중복된 '카테고리'를 온/오프라인으로 정정
abiriadev 5604948
fix: placeholder 색 수정
abiriadev b33dee5
feat: <Stack> 컴포넌트가 구분자를 받을 수 있도록 정의
abiriadev 61d1117
refactor: <Stack> 컴포넌트가 자식을 받지 않아도 되도록 허용
abiriadev a0440ce
refactor: <Stack> 컴포넌트로 반복 제거
abiriadev 8bc1f59
feat: gap 속성 허용
abiriadev 3839e56
fix: gap 단위를 px로 지정, flex 방향을 세로로 변경
abiriadev 75c1754
fix: 숫자를 자동으로 px로 변환하도록 수정
abiriadev 994650a
fix: 입력 양식 내부 gap과 버튼과의 gap을 분리
abiriadev bbc3ccc
refactor: <Heading> 컴포넌트 재사용
abiriadev e6b8388
refactor: <SelectBox />에서 label 분리
abiriadev 936f3e4
feat: `<Labeled>` 컴포넌트 정의
abiriadev 6b519ff
refactor: <Labeled> 적용
abiriadev 86dc326
fix: 빠진 에러 메세지 색상 추가
abiriadev ad6ed4a
chore: 스터디 최대 인원 최대 10명 제한 (WIP)
abiriadev 901b277
fix: 선택을 해도 색상이 placeholder와 달라지지 않는 이슈 해결
abiriadev 891ab04
feat: error prop으로 에러 메세지 삽입 허용
abiriadev 6b8cef3
fix: RHF에서 검증을 진행하기 위해 required 삭제
abiriadev aafd878
feat: `<Labeled />`별 검증 로직 추가 및 에러 메세지 삽입
abiriadev 92d4341
chore: 에러 문구 수정
abiriadev f35892e
fix: 에러 메세지 원인을 필드별로 분리
abiriadev 1d8bf82
chpre: 제목 필드에 대한 에러 메세지와 placeholder 메세지 추가
abiriadev ed522d3
refactor: `forwardRef` 타입 재정의
abiriadev 7068388
fix: 카테고리 필드에 바인딩된 `title` 속성을 제목 필드로 이동
abiriadev 47d7d39
refactor: `currentLength` prop을 외부 상태에서 수집
abiriadev fe1bd82
feat: `currentLength` 렌더링 로직 추가
abiriadev 73fe2bd
refactor: `maxLength`를 prop으로 받을 수 있도록 개선
abiriadev 13a56cd
feat: 생성 페이지에서 maxLength 넘겨주도록 수정
abiriadev 0f4cb83
chore:
abiriadev c5c30f0
Merge branch 'dev' into feat/create-study
abiriadev 505f156
Merge branch 'setup-storybook' into feat/create-study
abiriadev 5a661aa
feat: Atomic한 타입만 따로 정의하기 위한 파일 생성
abiriadev c284dc2
feat: <DateRange /> 구현 완료
abiriadev 43d2d3b
refactor: 콜백 함수 등을 `Partial<T>` 로 옵셔널화
abiriadev 69cab71
docs: `<ProgressPeriod />` 컴포넌트를 위한 스토리 문서 추가
abiriadev 14be7ba
perf: 팀원 배열을 매 렌더링시마다 반복하지 않도록 분리
abiriadev 20eb437
fix: `iindex.ts` 파일 수정 반영
abiriadev d3a0778
feat: 요구사항에 맞게 타입 추가
abiriadev 80085db
style: <CalendarButton> 스타일 수정
hyosin-Jang 76b31dc
fix: 필드명 변경
abiriadev 4f80308
feat: 스터디 진행 기간을 <ProgressPeriod /> 컴포넌트로 수정
abiriadev 437cc4f
refactor: validation 메세지를 `register`함수 호출시 입력하도록 리팩토링
abiriadev 146bae2
fix: `?.` 로 에러 메시지를 옵셔널로 전달
abiriadev 2743ae6
feat: <CustomSelect> 멀티셀렉트 기능 추가
hyosin-Jang b8972ea
feat: react-select를 위한 카테고리 목록 정의
abiriadev f3c42a5
chore: RecruitFormSelect 타입 수정 반영
hyosin-Jang 37216d5
feat: 라벨이 부착된 폼 UI <LabelForm> 컴포넌트로 분리
hyosin-Jang 10387be
chore: RecruitFormSelect 타입 수정 반영
hyosin-Jang 86560c1
style: theme color > input negative 색상 추가
hyosin-Jang a68f480
docs: nagative 색상 문서화
abiriadev 8b3fe6f
refactor: LabelForm을 제네릭화
abiriadev ecae190
refactor: 카테고리 입력을 `LabelForm`, `CustomSelect`를 사용하도록 업데이트
abiriadev ef4d6ae
refactor: 스터디 최대 인원 수정
abiriadev 2a0fbe9
feat: 프로젝트 진행 방식을 React-select에서 사용할 수 있도록 재정의
abiriadev b83ec1b
refactor: 스터디 진행 방식 폼 업데이트
abiriadev 2dc60df
feat: react-select용 플랫폼 옵션 재정의
abiriadev f240d19
refactor: 플랫폼 선택 폼 업데이트
abiriadev 315078c
chore: 문구 수정
abiriadev 2d21a85
refactor: 진행기간 선택 폼에 `LabelFrom` 사용
abiriadev e50d1ed
fix: 모든 폼에 validation 추가 확인
abiriadev 920090f
chore: <InputText> label props 추가
hyosin-Jang 8331d60
style: <Heading>, <EndDate> 스타일 수정
hyosin-Jang 3e6d635
feat: InputText 수정 반영
abiriadev 544c12e
feat: 진행 플랫폼 필드 추가
abiriadev 6968e8b
chore: 80% 오류 수정
abiriadev fd5e5d5
feat: Grid 컴포넌트 재사용 가능하게 분리
abiriadev c846cdc
feat: `<Grid />`로 길어진 폼 항목들을 wrapping
abiriadev db1be97
feat: react-select를 위한 포지션 데이터 재정의
abiriadev f0cf70b
feat: 포지션 입력 필드 추가
abiriadev 2d70c38
chore: 등록 버튼 텍스트 수정
abiriadev 0523265
refactor: `saveTemporary` 함수를 컴포넌트에서 분리
abiriadev 08e0407
chore: RecruitFormSelect 타입 수정 반영
hyosin-Jang c507132
feat: 임시저장 목록에서 클릭된 카드 key 스토어에 저장
hyosin-Jang 28b6cde
feat: 임시저장시 페이지 전환 기능 구현
abiriadev b6737a5
feat: react-select를 `yarn.lock`에 업데이트
abiriadev c75e71e
feat: 스터디 생성 `mutation` 정의
abiriadev 7b89775
feat: `useMutation`으로 새 스터디 생성하기
abiriadev 414060b
feat: 생성시 에러가 발생할 경우, `<ErrorBoundary />` 를 표시하기
abiriadev d44b15f
fix: 로케일 설정 경고 해결
abiriadev 41cc043
test: 스터디 생성에 대한 Mock 추가
abiriadev 46baa52
feat: 스터디 수정 API 정의
abiriadev 3acd2e2
feat: 스터디 수정을 위한 mutation 훅 정의
abiriadev 9591c14
feat: 스터디 수정 페이지 추가
abiriadev f3009a6
fix: 라우터 수정, 생성 및 수정 페이지의 export 수정
abiriadev 5f5f1c1
refactor: 쿼리를 받을 수 있게 prop을 리팩토링
abiriadev 2eaa479
feat: 스터디 수정 페이지에서 `defaultValue` 를 가져오게 구현
abiriadev e0a03cb
refactor: 중복된 기능을 하는 `<Labeled />`컴포넌트 제거
abiriadev fd295a8
Merge branch 'dev' into feat/create-study
abiriadev 19b5d49
fix: `<Stack />` 컴포넌트 머지
abiriadev 1a2da7f
tempfix: 스터디 아이디를 고정함으로써 `saveTemporary`호환 문제 해결
abiriadev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
import { ProgressPeriod } from './ProgressPeriod'; | ||
|
||
const meta = { | ||
component: ProgressPeriod, | ||
parameters: { | ||
docs: { | ||
story: { | ||
height: '300px', | ||
}, | ||
}, | ||
}, | ||
} satisfies Meta<typeof ProgressPeriod>; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof meta>; | ||
|
||
export const Primary: Story = {}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,78 +1,74 @@ | ||
// react-datepicker를 사용해서 진행기간 구현 328px, 24px, ex) 24.01.23 - 24.03.23 | ||
import DatePicker from 'react-datepicker'; | ||
import { useState } from 'react'; | ||
import 'react-datepicker/dist/react-datepicker.css'; | ||
import { forwardRef, useState } from 'react'; | ||
import styled from 'styled-components'; | ||
import { OptionalCreates } from '@/Pages/Studies/CreateStudy'; | ||
import { Creates } from '@/Types/studies'; | ||
import { DateRange } from '@/Types/atoms'; | ||
import { ControllerRenderProps } from 'react-hook-form'; | ||
import 'react-datepicker/dist/react-datepicker.css'; | ||
|
||
export type Props = { | ||
onClick?: () => void; | ||
children?: React.ReactNode; | ||
// onChange?: (event: string) => void; | ||
setForm: (any: OptionalCreates) => void; | ||
useForm: Creates; | ||
value?: string; | ||
type?: string; | ||
export interface ProgressPeriodProps { | ||
/** input 요소가 가질 폼 필드 이름 속성 */ | ||
name?: string; | ||
maxlength?: number; | ||
id?: string; | ||
formData?: number | string; | ||
ref?: string; | ||
}; | ||
} | ||
|
||
interface IProgressPeriodForm { | ||
progressPeriod: DateRange; | ||
} | ||
|
||
export const ProgressPeriod = ({ useForm }: Props) => { | ||
const [startDateTime, setForms] = useState(new Date()); | ||
const [endDateTime, setFormss] = useState(new Date()); | ||
// const StartHandler = (event: ChangeEvent<HTMLSelectElement>) => { | ||
// setForm({ startDateTime: event.target.value }); | ||
// }; | ||
/** | ||
* 특정한 범위의 기간을 입력받는 데 사용되는 컴포넌트입니다. | ||
* | ||
* 사용처는 다음과 같습니다: | ||
* - 스터디 기간 설정 | ||
* - 기간으로 스터디 조회 등 | ||
*/ | ||
export const ProgressPeriod = forwardRef< | ||
DatePicker, | ||
ProgressPeriodProps & Partial<ControllerRenderProps<IProgressPeriodForm, 'progressPeriod'>> | ||
>(({ name, onChange, onBlur }, ref) => { | ||
const now = new Date(); | ||
|
||
const [startDate, setStartDate] = useState(now); | ||
const [endDate, setEndDate] = useState(null); | ||
|
||
return ( | ||
<> | ||
<DateContainer | ||
selected={startDateTime} | ||
value={(useForm.startDateTime = startDateTime.toISOString().slice(0, -5))} | ||
name="startDateTime" | ||
onChange={(date: Date) => setForms(date)} | ||
// onChange={StartHandler} | ||
selectsStart | ||
startDate={startDateTime} | ||
// endDate={endDateTime} | ||
dateFormat="yyyy-MM-dd'T'HH:mm:ss" | ||
/> | ||
<Slash>-</Slash> | ||
<DateContainer | ||
selected={endDateTime} | ||
value={(useForm.endDateTime = endDateTime.toISOString().slice(0, -5))} | ||
name="endDateTime" | ||
onChange={(date: any) => setFormss(date)} | ||
selectsEnd | ||
endDate={endDateTime} | ||
minDate={startDateTime} | ||
dateFormat="yyyy-MM-dd'T'HH:mm:ss" | ||
/> | ||
</> | ||
<DateContainer | ||
ref={ref} | ||
name={name} | ||
locale="ko" | ||
// 기본값은 오늘부터 시작하는 것으로 가정 | ||
selected={startDate} | ||
onBlur={onBlur} | ||
onChange={([start, end]: [Date, Date]) => { | ||
setStartDate(start); | ||
setEndDate(end); | ||
onChange([start, end]); | ||
}} | ||
// 시작일은 오늘 이후로 선택할 수 없다 | ||
minDate={now} | ||
startDate={startDate} | ||
endDate={endDate} | ||
placeholderText="ex) 24.01.23 - 24.03.23" | ||
// 범위 선택 | ||
selectsRange | ||
shouldCloseOnSelect | ||
showDisabledMonthNavigation | ||
// 한국인에게 익숙한 날짜 순서 | ||
dateFormat="yy.MM.dd" | ||
/> | ||
); | ||
}; | ||
}); | ||
|
||
// TODO: ./EndDate.tsx 랑 똑같은 Styled Component인데 한쪽으로 빼서 공용 컴포넌트로 사용하기 | ||
const DateContainer = styled(DatePicker)` | ||
width: 145px; | ||
width: 328px; | ||
height: 24px; | ||
background-color: ${(props) => props.theme.color.gray3}; | ||
align-items: center; | ||
align-self: stretch; | ||
border: 1px solid #cbcdd1; | ||
border-width: 0; | ||
background: ${(props) => props.theme.color.gray1}; | ||
resize: none; | ||
flex: 1 0 0; | ||
margin-top: 10px; | ||
padding-bottom: 10px; | ||
padding-right: 16px; | ||
padding-left: 16px; | ||
`; | ||
|
||
const Slash = styled.p` | ||
padding-right: 20px; | ||
&::placeholder { | ||
color: ${(props) => props.theme.color.black2}; | ||
} | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import styled from 'styled-components'; | ||
|
||
export const BoldDivider = styled.div<{ rowHeight: number }>` | ||
width: 100%; | ||
height: ${(props) => `${props.rowHeight}px`}; | ||
background-color: ${(props) => props.theme.color.gray1}; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import styled from 'styled-components'; | ||
|
||
export const Grid = styled.div` | ||
display: grid; | ||
grid-template-columns: repeat(3, minmax(392px, 1fr)); | ||
gap: 24px; | ||
margin-top: 24px; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,88 @@ | ||
import React, { ForwardedRef } from 'react'; | ||
import { ComponentProps, ForwardedRef, forwardRef, useState } from 'react'; | ||
import styled from 'styled-components'; | ||
|
||
interface InputTextProps extends React.InputHTMLAttributes<HTMLInputElement> { | ||
placeholder?: string; | ||
inputType?: 'text' | 'email' | 'password' | 'member'; | ||
defaultValue?: string; | ||
currentLength?: number; | ||
maxLength?: number; | ||
label?: string; | ||
} | ||
|
||
const InputText = React.forwardRef( | ||
({ placeholder, inputType, onChange, ...props }: InputTextProps, ref: ForwardedRef<HTMLInputElement>) => { | ||
return <InputWrapper placeholder={placeholder} ref={ref} type={inputType} onChange={onChange} {...props} />; | ||
const InputText = forwardRef<HTMLInputElement, ComponentProps<'input'> & InputTextProps>( | ||
( | ||
{ name, placeholder, defaultValue, inputType, onChange, maxLength, currentLength, label, ...props }: InputTextProps, | ||
ref: ForwardedRef<HTMLInputElement>, | ||
) => { | ||
return ( | ||
<Box> | ||
{label && <Label>{label}</Label>} | ||
<InputWrapper | ||
placeholder={placeholder} | ||
defaultValue={defaultValue} | ||
name={name} | ||
ref={ref} | ||
type={inputType ?? 'text'} | ||
onChange={onChange} | ||
autoComplete="off" | ||
{...props} | ||
/> | ||
{maxLength && ( | ||
<LengthIndicator> | ||
{currentLength} / {maxLength} | ||
</LengthIndicator> | ||
)} | ||
</Box> | ||
); | ||
}, | ||
); | ||
|
||
export const Label = styled.div` | ||
font-size: 18px; | ||
line-height: 24px; | ||
color: #000000f2; | ||
margin-bottom: 12px; | ||
`; | ||
|
||
const InputWrapper = styled.input` | ||
width: 100%; | ||
padding: 10px 16px; | ||
border: 1px solid ${({ theme }) => theme.color.black1}; | ||
border-radius: ${({ theme }) => theme.borderRadius.small}; | ||
font-size: ${({ theme }) => theme.font.medium}; | ||
font-size: ${({ theme }) => theme.font.small}; | ||
line-height: 1.5; | ||
color: ${({ theme }) => theme.color.black}; | ||
text-overflow: ellipsis; | ||
display: block; | ||
white-space: nowrap; | ||
overflow: hidden; | ||
|
||
::placeholder { | ||
&::placeholder { | ||
color: ${({ theme }) => theme.color.black2}; | ||
font-family: 'Pretendard400'; | ||
font-size: ${({ theme }) => theme.font.medium}; | ||
font-size: ${({ theme }) => theme.font.small}; | ||
font-style: normal; | ||
font-weight: 400; | ||
line-height: 28px; | ||
} | ||
`; | ||
|
||
const Box = styled.div` | ||
position: relative; | ||
display: flex; | ||
flex-direction: column; | ||
`; | ||
|
||
const LengthIndicator = styled.div` | ||
position: absolute; | ||
bottom: 13px; | ||
right: 16px; | ||
color: #00000073; | ||
font-family: Pretendard400; | ||
font-weight: 400; | ||
font-size: 14px; | ||
line-height: 20px; | ||
`; | ||
|
||
export default InputText; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
import React from 'react'; | ||
import { LabelForm } from '.'; | ||
|
||
const meta = { | ||
component: LabelForm, | ||
args: { | ||
label: '포지션', | ||
children: React.createElement('input', { placeholder: 'input' }, null), | ||
}, | ||
} satisfies Meta<typeof LabelForm>; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof meta>; | ||
|
||
/** 유효하지 않을 경우, 에러메시지를 표시합니다. */ | ||
export const Errors: Story = { | ||
args: { | ||
errors: { | ||
positionIds: { | ||
message: '포지션을 선택해주세요.', | ||
}, | ||
}, | ||
name: 'positionIds', | ||
}, | ||
}; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Grid까지 Common 컴포넌트화 하셨네요!! 세심함에 감탄하고 갑니다👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
원본은 클레어님이 제작하신 코드입니다...
잘 보시면
Co-Authored-By: hyosin Jang <[email protected]>
가 있습니다.