diff --git a/public/assets/android-chrome-192x192.png b/public/assets/android-chrome-192x192.png index 36cc6ad..62ea683 100644 Binary files a/public/assets/android-chrome-192x192.png and b/public/assets/android-chrome-192x192.png differ diff --git a/public/assets/android-chrome-512x512.png b/public/assets/android-chrome-512x512.png index 4142dc5..dca6905 100644 Binary files a/public/assets/android-chrome-512x512.png and b/public/assets/android-chrome-512x512.png differ diff --git a/public/assets/favicon-16x16.png b/public/assets/favicon-16x16.png index 4af35e9..8a95413 100644 Binary files a/public/assets/favicon-16x16.png and b/public/assets/favicon-16x16.png differ diff --git a/public/assets/favicon-32x32.png b/public/assets/favicon-32x32.png index a774516..57ec732 100644 Binary files a/public/assets/favicon-32x32.png and b/public/assets/favicon-32x32.png differ diff --git a/public/assets/intro-1.png b/public/assets/intro-1.png index a42bf2c..0f62bce 100644 Binary files a/public/assets/intro-1.png and b/public/assets/intro-1.png differ diff --git a/public/assets/intro-2.png b/public/assets/intro-2.png index 19b9346..cbf49a3 100644 Binary files a/public/assets/intro-2.png and b/public/assets/intro-2.png differ diff --git a/public/assets/intro-3.png b/public/assets/intro-3.png index 3c8682f..4274b68 100644 Binary files a/public/assets/intro-3.png and b/public/assets/intro-3.png differ diff --git a/public/assets/logos/og-image.png b/public/assets/logos/og-image.png index 07dc3db..37e4dc0 100644 Binary files a/public/assets/logos/og-image.png and b/public/assets/logos/og-image.png differ diff --git a/src/components/atoms/DraggableContainer/index.module.scss b/src/components/atoms/DraggableContainer/index.module.scss new file mode 100644 index 0000000..abf6ea8 --- /dev/null +++ b/src/components/atoms/DraggableContainer/index.module.scss @@ -0,0 +1,9 @@ +.container { + overflow-x: scroll; + cursor: grab; + user-select: none; + + &:active { + cursor: grabbing; + } +} diff --git a/src/components/atoms/DraggableContainer/index.tsx b/src/components/atoms/DraggableContainer/index.tsx new file mode 100644 index 0000000..408659d --- /dev/null +++ b/src/components/atoms/DraggableContainer/index.tsx @@ -0,0 +1,54 @@ +'use client'; + +import { ComponentProps } from 'react'; + +import clsx from 'clsx'; + +import useDraggableScroll from '@/hook/useDraggableScroll'; + +import styles from './index.module.scss'; + +type DraggableContainerProps = ComponentProps<'div'> & { + className?: string; + ariaLabel?: string; +}; + +function DraggableContainer({ + children, + className, + ariaLabel, + ...props +}: DraggableContainerProps) { + const { + ref, + onMouseDown, + onMouseLeave, + onMouseUp, + onMouseMove, + onTouchStart, + onTouchMove, + onTouchEnd, + } = useDraggableScroll(); + + return ( +
+ {children} +
+ ); +} + +export default DraggableContainer; diff --git a/src/components/organisms/home/RecruitmentStatusSection/index.module.scss b/src/components/organisms/home/RecruitmentStatusSection/index.module.scss index 8fe23ae..8f6e077 100644 --- a/src/components/organisms/home/RecruitmentStatusSection/index.module.scss +++ b/src/components/organisms/home/RecruitmentStatusSection/index.module.scss @@ -25,6 +25,10 @@ &.primary { background-color: var(--primary); + + &:hover { + background-color: var(--primary-hover); + } } @include mobile { diff --git a/src/components/pages/Recruit/index.module.scss b/src/components/pages/Recruit/index.module.scss index c874f5d..cab479c 100644 --- a/src/components/pages/Recruit/index.module.scss +++ b/src/components/pages/Recruit/index.module.scss @@ -1,5 +1,4 @@ .cardListWrapper { - overflow-x: scroll; width: 100%; .cardList { diff --git a/src/components/pages/Recruit/index.tsx b/src/components/pages/Recruit/index.tsx index 125f943..f7b2c40 100644 --- a/src/components/pages/Recruit/index.tsx +++ b/src/components/pages/Recruit/index.tsx @@ -1,6 +1,7 @@ import { Flex } from '@sipe-team/side'; import ContentWithTitle from '@/components/atoms/ContentWithTitle'; +import DraggableContainer from '@/components/atoms/DraggableContainer'; import Layout from '@/components/atoms/Layout'; import Table from '@/components/molecules/Table'; import Faq from '@/components/organisms/Faq'; @@ -19,11 +20,9 @@ function Recruit() { - ))} - +
diff --git a/src/hook/useDraggableScroll.ts b/src/hook/useDraggableScroll.ts new file mode 100644 index 0000000..4864f70 --- /dev/null +++ b/src/hook/useDraggableScroll.ts @@ -0,0 +1,79 @@ +import { useCallback, useRef } from 'react'; + +interface UseDraggableScrollReturn { + ref: React.RefObject; + onMouseDown: (e: React.MouseEvent) => void; + onMouseLeave: () => void; + onMouseUp: () => void; + onMouseMove: (e: React.MouseEvent) => void; + onTouchStart: (e: React.TouchEvent) => void; + onTouchMove: (e: React.TouchEvent) => void; + onTouchEnd: () => void; +} + +export default function useDraggableScroll(): UseDraggableScrollReturn { + const ref = useRef(null); + const isDragging = useRef(false); + const startX = useRef(0); + const scrollLeft = useRef(0); + + const onMouseDown = useCallback((e: React.MouseEvent) => { + if (!ref.current) return; + isDragging.current = true; + startX.current = e.pageX - ref.current.offsetLeft; + scrollLeft.current = ref.current.scrollLeft; + ref.current.style.cursor = 'grabbing'; + }, []); + + const onMouseLeave = useCallback(() => { + isDragging.current = false; + if (ref.current) { + ref.current.style.cursor = 'grab'; + } + }, []); + + const onMouseUp = useCallback(() => { + isDragging.current = false; + if (ref.current) { + ref.current.style.cursor = 'grab'; + } + }, []); + + const onMouseMove = useCallback((e: React.MouseEvent) => { + if (!isDragging.current || !ref.current) return; + e.preventDefault(); + const x = e.pageX - ref.current.offsetLeft; + const walk = (x - startX.current) * 2; + ref.current.scrollLeft = scrollLeft.current - walk; + }, []); + + const onTouchStart = useCallback((e: React.TouchEvent) => { + if (!ref.current) return; + isDragging.current = true; + startX.current = e.touches[0].pageX - ref.current.offsetLeft; + scrollLeft.current = ref.current.scrollLeft; + }, []); + + const onTouchMove = useCallback((e: React.TouchEvent) => { + if (!isDragging.current || !ref.current) return; + e.preventDefault(); + const x = e.touches[0].pageX - ref.current.offsetLeft; + const walk = (x - startX.current) * 2; + ref.current.scrollLeft = scrollLeft.current - walk; + }, []); + + const onTouchEnd = useCallback(() => { + isDragging.current = false; + }, []); + + return { + ref, + onMouseDown, + onMouseLeave, + onMouseUp, + onMouseMove, + onTouchStart, + onTouchMove, + onTouchEnd, + }; +} diff --git a/src/libs/constants/recruit.ts b/src/libs/constants/recruit.ts index b649cc2..9b6b237 100644 --- a/src/libs/constants/recruit.ts +++ b/src/libs/constants/recruit.ts @@ -6,6 +6,12 @@ export const JOIN_FORM_URL = 'https://forms.gle/SPM3xXTVrnvupcLDA'; export const JOIN_ALARM_FORM_URL = 'https://forms.gle/VS7Ap4xfSyf2qYqQ6'; export const JOIN_NEXT_ALARM_FORM_URL = 'https://forms.gle/VS7Ap4xfSyf2qYqQ6'; +export type CardListType = { + title: string; + processDate: string; + subTitle: string; +}; + export const Applicants = [ { text: '격주 토요일 오후 2시 ~ 6시에 진행되는 정규 활동에 성실하게 참여할 수 있는', @@ -22,53 +28,58 @@ export const Applicants = [ export const InActivity = [ { - recurring_date: '1회차 (04.26)', + recurring_date: '1회차 (03.07)', text: 'OT', badge: '', }, { - recurring_date: '2회차 (05.10)', + recurring_date: '2회차 (03.21)', text: 'MT', - badge: '1차 미션 시작', + badge: '1차 미션 팀 빌딩', }, { - recurring_date: '3회차 (05.24)', - text: '사이프챗', + recurring_date: '3회차 (04.04)', + text: '라이트닝 토크 1', badge: '', }, { - recurring_date: '4회차 (06.07)', - text: '홈커밍데이', + recurring_date: '4회차 (04.18)', + text: '개발자 힐링 캠프', badge: '', }, { - recurring_date: '5회차 (06.21)', + recurring_date: '5회차 (05.02)', text: '1차 미션 발표', badge: '', }, { - recurring_date: '6회차 (07.05)', + recurring_date: '6회차 (05.16)', text: '스파크 세션', - badge: '2차 미션 시작', + badge: '해커톤 팀 빌딩', }, { - recurring_date: '7회차 (07.19)', - text: '사이데이션', + recurring_date: '7회차 (05.30)', + text: '내친소', badge: '', }, { - recurring_date: '8회차 (08.02)', - text: '사담콘', + recurring_date: '8회차 (06.13)', + text: '라이트닝 토크 2', + badge: '', + }, + { + recurring_date: '9회차 (06.27)', + text: '사이프톤', badge: '', }, { - recurring_date: '9회차 (08.16)', - text: '2차 미션 발표', + recurring_date: '10회차 (07.11)', + text: '사담콘', badge: '', }, { - recurring_date: '10회차 (08.30)', - text: '사이프-로그', + recurring_date: '10회차 (07.25)', + text: '사이프 로그', badge: '정규 활동 종료', }, ]; @@ -82,7 +93,7 @@ export const CardList = [ { title: '서류 합격자 발표', processDate: '01.13(화)', - subTitle: '오후 1시 예정', + subTitle: '힙격자 개별 연락', }, { title: '오프라인 인터뷰', @@ -93,7 +104,7 @@ export const CardList = [ { title: '최종 합격자 발표', processDate: '02.14(토)', - subTitle: '오후 1시 예정', + subTitle: '힙격자 개별 연락', }, { title: '정규 활동 시작', diff --git a/src/styles/variables.scss b/src/styles/variables.scss index aa82731..df1267e 100644 --- a/src/styles/variables.scss +++ b/src/styles/variables.scss @@ -1,6 +1,7 @@ :root { /* colors */ --primary: #ffb24d; + --primary-hover: #d9963f; // --primary: #00ffff; --black: #131518; --gray000: #1a202c;