Skip to content

Commit

Permalink
Merge branch 'main' into feat/editor-ui
Browse files Browse the repository at this point in the history
  • Loading branch information
Collection50 authored Aug 8, 2024
2 parents 8fa0220 + d7f716b commit 22434ea
Show file tree
Hide file tree
Showing 26 changed files with 892 additions and 151 deletions.
331 changes: 207 additions & 124 deletions .pnp.cjs

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.
Binary file not shown.
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
"node": "20.2.0"
},
"dependencies": {
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-slot": "^1.1.0",
"@tanstack/react-query": "^5.51.1",
"@tanstack/react-query-devtools": "^5.51.1",
"@tippyjs/react": "^4.2.6",
Expand Down Expand Up @@ -67,12 +69,14 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"cookies-next": "^4.2.1",
"date-fns": "^3.6.0",
"framer-motion": "^11.3.8",
"lowlight": "^3.1.0",
"lucide-react": "^0.411.0",
"next": "14.2.4",
"react": "^18",
"react-colorful": "^5.6.1",
"react-day-picker": "8.10.1",
"react-dom": "^18",
"tailwind-merge": "^2.4.0",
"tailwind-variants": "^0.2.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { If } from '@/components/If';
import { ComponentProps, ReactNode } from 'react';

interface Props extends ComponentProps<'input'> {
required?: boolean;
right?: ReactNode;
value: string;
}

export function InputField({ required = false, right, value, ...inputProps }: Props) {
return (
<div className="w-full flex justify-between items-center p-12 bg-neutral-1 border-neutral-20 rounded-[8px] border-[1px]">
<If condition={required}>
<div className="text-mint-40 text-label1">*</div>
</If>
<input value={value} className="flex-1 outline-none bg-transparent" {...inputProps} />
<If condition={right != null}>
<div className="ml-[12px]">{right}</div>
</If>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import { Spacing } from '@/components/Spacing';
import { TouchButton } from '@/components/TouchButton';
import { Dialog } from '@/system/components/Dialog/ShadcnDialog';
import { color } from '@/system/token/color';
import { InputField } from './InputField';
import { useState } from 'react';
import { Icon } from '@/system/components';
import { getCurrentYearAndHalf, getNextYearAndHalf } from './date';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/system/components/DropdownMenu/DropdownMenu';
import clsx from 'clsx';
import { motion } from 'framer-motion';
import { Popover, PopoverContent, PopoverTrigger } from '@/system/components/Popover/Popover';
import { Calendar } from '@/system/components/Calendar/Calendar';
import { format } from 'date-fns/format';
import { If } from '@/components/If';

interface Props {
onSubmit: () => void;
}

const TITLE_MAX_LENGTH = 30;
// FIXME: 서버쪽에서 전달해주는 데이터로 교체
const DEFAULT_DROPDOWN_PERIOD = [getCurrentYearAndHalf(), getNextYearAndHalf()];

export function NewRecruitDialogContent() {
const [title, setTitle] = useState('');
const [selectedPeriod, setSelectedPeriod] = useState(getCurrentYearAndHalf());
const [link, setLink] = useState('');
const [selectedDate, setSelectedDate] = useState<Date>();

const isButtonActivated = title.length !== 0;
const isDateSelected = selectedDate != null;

return (
<div className="p-20">
<Dialog.Title>
<span className="text-neutral-95 text-body1 font-semibold">새 공고 추가하기</span>
</Dialog.Title>
<Spacing size={4} />
<span className="text-caption1 text-neutral-35 font-regular">공고를 등록하고 정보를 모아보세요!</span>
<Spacing size={24} />

{/* 공고 제목 입력 */}
<InputField
required
value={title}
placeholder="공고 제목을 입력해주세요"
maxLength={TITLE_MAX_LENGTH}
right={<span className="text-neutral-60 text-caption2">{`${title.length}/${TITLE_MAX_LENGTH}`}</span>}
onChange={(event) => setTitle(event.target.value)}
/>
<Spacing size={8} />

{/* 지원 시기 입력 */}
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button className="w-full flex justify-between items-center p-12 bg-neutral-1 border-neutral-20 rounded-[8px] border-[1px]">
<span>{selectedPeriod}</span>
<Icon name="down" size={24} color="#878A93" />
</button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-360 py-8">
{/* TODO: 이전 공고들의 연도들도 추가 */}
{[...DEFAULT_DROPDOWN_PERIOD].reverse().map((period) => (
<DropdownMenuItem
key={period}
className="w-full flex justify-between px-16 py-8"
onClick={() => setSelectedPeriod(period)}>
<span className={clsx('text-label1', period === selectedPeriod ? 'text-neutral-30' : 'text-neutral-80')}>
{period}
</span>
<If condition={period === selectedPeriod}>
<Icon size={16} name="check" color="#AEB0B6" />
</If>
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
<Spacing size={8} />

{/* 마감일 입력 */}
<div className="w-full flex justify-between items-center p-12 bg-neutral-1 border-neutral-20 rounded-[8px] border-[1px]">
<span className="text-label1 text-neutral-95">서류마감</span>
<Popover>
<PopoverTrigger>
<motion.div
initial="initial"
variants={{
initial: { backgroundColor: 'rgb(241, 242, 243, 0)' },
touch: { scale: 0.96, transition: { duration: 0.1 } },
hover: { backgroundColor: 'rgb(241, 242, 243, 1)' },
}}
whileTap="touch"
whileHover="hover"
className="px-8 py-4 flex items-center gap-[4px] rounded-[4px]">
<Icon name={isDateSelected ? 'calendarFill' : 'calendar'} size={20} color="#AEB0B6" />
<span className={clsx('text-label2', isDateSelected ? 'text-neutral-95' : 'text-neutral-40')}>
{isDateSelected ? format(selectedDate, 'yyyy.mm.dd') : '마감일을 선택해주세요'}
</span>
</motion.div>
</PopoverTrigger>
<PopoverContent className="w-200">
<Calendar mode="single" selected={selectedDate} onSelect={setSelectedDate} />
</PopoverContent>
</Popover>
</div>
<Spacing size={8} />

{/* 공고 링크 입력 */}
<InputField
value={link}
placeholder="공고 링크를 입력해주세요"
right={<Icon name={link.length === 0 ? 'unlink' : 'link'} size={16} color="#70737C" />}
onChange={(event) => setLink(event.target.value)}
/>
<Spacing size={20} />

{/* 제출 버튼 */}
<TouchButton
variants={{
inactive: {
backgroundColor: color.neutral5,
color: color.neutral30,
},
active: {
backgroundColor: color.neutral95,
color: color.white,
},
}}
animate={isButtonActivated ? 'active' : 'inactive'}
disabled={isButtonActivated === false}
className="w-full flex justify-center items-center h-48 rounded-[6px]">
공고 추가하기
</TouchButton>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// NOTE: 서버에서 넘어오는 값에 따라 변경될 예정입니다.
export function getCurrentYearAndHalf() {
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth() + 1;

const half = month <= 6 ? '상반기' : '하반기';

return `${year}${half}`;
}

export function getNextYearAndHalf() {
const now = new Date();
let year = now.getFullYear();
const month = now.getMonth() + 1;

let half: string;
if (month <= 6) {
half = '하반기';
} else {
half = '상반기';
year += 1;
}

return `${year}${half}`;
}
15 changes: 12 additions & 3 deletions src/app/(sidebar)/my-recruit/containers/AllRecruitment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/system/components/DropdownMenu/DropdownMenu';
import { motion } from 'framer-motion';
import { color } from '@/system/token/color';
import { Dialog } from '@/system/components/Dialog/ShadcnDialog';

export function AllRecruitment() {
return (
Expand All @@ -31,9 +34,15 @@ export function AllRecruitment() {
</DropdownMenuContent>
</DropdownMenu>
<Spacing size={24} />
<div className="w-full h-70 flex justify-center items-center rounded-[12px] border-neutral-30 border-dashed border-[1px]">
<span className="text-neutral-30 text-label1">등록된 공고가 없어요</span>
</div>
<Dialog.Trigger asChild>
<motion.button
initial="initial"
whileHover="hover"
variants={{ initial: { backgroundColor: 'transparent' }, hover: { backgroundColor: color.neutral5 } }}
className="w-full h-70 flex justify-center items-center rounded-[12px] border-neutral-30 border-dashed border-[1px]">
<span className="text-neutral-30 text-label1">등록된 공고가 없어요</span>
</motion.button>
</Dialog.Trigger>
</>
);
}
15 changes: 12 additions & 3 deletions src/app/(sidebar)/my-recruit/containers/ProgressingRecruitment.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Spacing } from '@/components/Spacing';
import { ShoeIcon } from './components/ShoeIcon';
import { Dialog } from '@/system/components/Dialog/ShadcnDialog';
import { motion } from 'framer-motion';
import { color } from '@/system/token/color';

export function ProgressingRecruitment() {
return (
Expand All @@ -9,9 +12,15 @@ export function ProgressingRecruitment() {
<span className="text-heading2 font-semibold">현재 진행중인 공고 모아보기</span>
</div>
<Spacing size={24} />
<div className="w-250 h-150 flex justify-center items-center rounded-[12px] border-neutral-30 border-dashed border-[1px]">
<span className="text-neutral-30 text-label1">진행중인 공고가 없어요</span>
</div>
<Dialog.Trigger asChild>
<motion.button
initial="initial"
whileHover="hover"
variants={{ initial: { backgroundColor: 'transparent' }, hover: { backgroundColor: color.neutral5 } }}
className="w-250 h-150 flex justify-center items-center rounded-[12px] border-neutral-30 border-dashed border-[1px]">
<span className="text-neutral-30 text-label1">진행중인 공고가 없어요</span>
</motion.button>
</Dialog.Trigger>
</>
);
}
48 changes: 31 additions & 17 deletions src/app/(sidebar)/my-recruit/page.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,43 @@
'use client';

import { Icon } from '@/system/components';
import { TouchButton } from '@/components/TouchButton';
import { Spacing } from '@/components/Spacing';
import { ProgressingRecruitment } from './containers/ProgressingRecruitment';
import { AllRecruitment } from './containers/AllRecruitment';
import { useState } from 'react';
import { Dialog } from '@/system/components/Dialog/ShadcnDialog';
import { NewRecruitDialogContent } from './components/NewRecruitDialogContent/NewRecruitDialogContent';

export default function MyRecruit() {
return (
<div className="max-w-[1700px] py-[64px] px-[80px] mx-auto">
<div className="flex justify-between">
<h1 className="text-title2 font-bold">내 공고 뽀각</h1>
<div className="flex gap-[16px]">
<TouchButton className="bg-white flex gap-[4px] py-[8px] px-[12px] rounded-[6px]">
<Icon name="copy" size={16} color="#CCCDD1" />
<span className="text-label1 font-semibold text-neutral-20">내 정보 가져오기</span>
</TouchButton>
<TouchButton className="bg-neutral-95 flex items-center gap-[4px] py-[8px] px-[16px] rounded-[6px]">
<Icon name="add" size={24} color="#20E79D" />
<span className="text-label1 text-white font-semibold">새 공고</span>
</TouchButton>
<Dialog>
<div className="max-w-[1700px] py-[64px] px-[80px] mx-auto">
<div className="flex justify-between">
<h1 className="text-title2 font-bold">내 공고 뽀각</h1>
<div className="flex gap-[16px]">
<TouchButton className="bg-white flex gap-[4px] py-[8px] px-[12px] rounded-[6px]">
<Icon name="copy" size={16} color="#CCCDD1" />
<span className="text-label1 font-semibold text-neutral-20">내 정보 가져오기</span>
</TouchButton>
<Dialog.Trigger asChild>
<div>
<TouchButton className="bg-neutral-95 flex items-center gap-[4px] py-[8px] px-[16px] rounded-[6px]">
<Icon name="add" size={24} color="#20E79D" />
<span className="text-label1 text-white font-semibold">새 공고</span>
</TouchButton>
</div>
</Dialog.Trigger>
</div>
</div>
<Spacing size={54} />
<ProgressingRecruitment />
<Spacing size={88} />
<AllRecruitment />
</div>
<Spacing size={54} />
<ProgressingRecruitment />
<Spacing size={88} />
<AllRecruitment />
</div>
<Dialog.Content className="w-400">
<NewRecruitDialogContent />
</Dialog.Content>
</Dialog>
);
}
7 changes: 4 additions & 3 deletions src/components/TouchButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import { ComponentProps } from 'react';

type Props = ComponentProps<typeof motion.button>;

export function TouchButton({ children, ...restProps }: Props) {
export function TouchButton({ children, variants, disabled, ...restProps }: Props) {
return (
<motion.button
initial="idle"
whileTap="touch"
variants={{ idle: { scale: 1 }, touch: { scale: 0.96 } }}
whileTap={disabled ? 'idle' : 'touch'}
variants={{ idle: { scale: 1 }, touch: { scale: 0.96 }, ...variants }}
transition={{ duration: 0.1 }}
disabled={disabled}
{...restProps}>
{children}
</motion.button>
Expand Down
Loading

0 comments on commit 22434ea

Please sign in to comment.