diff --git a/components/common/Banner/index.tsx b/components/common/Banner/index.tsx index 035be43..fbb7378 100644 --- a/components/common/Banner/index.tsx +++ b/components/common/Banner/index.tsx @@ -4,6 +4,8 @@ import media from 'styles/media'; interface BannerProps { backgroundImg?: string; + backgroundImgTablet?: string; + backgroundImgMobile?: string; className?: string; title?: string; description?: string; @@ -11,12 +13,19 @@ interface BannerProps { function Banner({ className, - backgroundImg = '/assets/images/27th/banner_project_story.png', + backgroundImg = '/assets/images/28th/project_page_pc.png', + backgroundImgTablet = '/assets/images/28th/project_page_tablet.png', + backgroundImgMobile = '/assets/images/28th/project_page_mo.png', title, description, }: BannerProps): ReactElement { return ( - + {title} {description} @@ -39,6 +48,14 @@ const StyledBox = styled.div` flex-direction: column; justify-content: center; gap: 8px; + + ${media.tablet} { + background-image: url(${({ backgroundImgTablet }) => backgroundImgTablet}); + } + + ${media.mobile} { + background-image: url(${({ backgroundImgMobile }) => backgroundImgMobile}); + } `; const InnerTextContainer = styled.div` @@ -71,7 +88,7 @@ const slideUp = keyframes` `; const StyledTitle = styled.h1` - color: ${({ theme }) => theme.palette.white_100}; + color: ${({ theme }) => theme.palette.discovery_28th_title}; ${({ theme }) => theme.textStyleV2.resp.title1_md}; white-space: nowrap; margin-top: 0; @@ -88,7 +105,7 @@ const StyledTitle = styled.h1` `; const StyledDescription = styled.p` - color: ${({ theme }) => theme.palette.white_50}; + color: ${({ theme }) => theme.palette.discovery_28th_button}; ${({ theme }) => theme.textStyleV2.resp.subtitle_md}; white-space: nowrap; margin-top: 0; diff --git a/components/common/JoinSection/index.tsx b/components/common/JoinSection/index.tsx index 0799c42..7be021b 100644 --- a/components/common/JoinSection/index.tsx +++ b/components/common/JoinSection/index.tsx @@ -4,17 +4,19 @@ import media from 'styles/media'; import SectionTemplate from '../../home/SectionTemplate'; import SectionTitle from '../SectionTitle'; import Button from '../Button'; -import Yapp from 'constants/yapp'; +import { LINK_BY_STATUS, RecruitStatus } from '../../../constants/status'; interface JoinSectionProps { + status: RecruitStatus; title?: string; subTitle?: string; btnText?: string; - caution?: string; url?: string; + caution?: string; } function JoinSection({ + status, title, subTitle, btnText, @@ -27,26 +29,19 @@ function JoinSection({ @@ -75,7 +70,7 @@ const ImageContainer = styled.div` width: 100%; height: 800px; border-radius: 32px; - background: url('/assets/images/27th/recruit.png') no-repeat center; + background: url('/assets/images/28th/recruit_bg.png') no-repeat center; background-size: cover; ${media.tablet} { diff --git a/components/common/SectionTitle/index.tsx b/components/common/SectionTitle/index.tsx index 90cf85f..7e43934 100644 --- a/components/common/SectionTitle/index.tsx +++ b/components/common/SectionTitle/index.tsx @@ -15,8 +15,8 @@ interface SectionTitleProps { function SectionTitle({ className, - fontColor = 'white', - subFontColor = 'white_50', + fontColor = 'black_100', + subFontColor = 'black_60', title = '', subTitle = '', align = 'flex-start', diff --git a/components/home/AnimatedTextSection/index.tsx b/components/home/AnimatedTextSection/index.tsx index 9262562..9b6ac68 100644 --- a/components/home/AnimatedTextSection/index.tsx +++ b/components/home/AnimatedTextSection/index.tsx @@ -30,7 +30,7 @@ function AnimatedTextSection(): ReactElement { const SectionContainer = styled.section` width: 100%; height: 100vh; - background-color: ${({ theme }) => theme.palette.black}; + background-color: ${({ theme }) => theme.palette.white}; display: flex; justify-content: center; align-items: center; @@ -49,9 +49,9 @@ const HighLightText = styled(motion.div)` background: linear-gradient( 270deg, - rgba(255, 255, 255, 0.3) 0%, - rgba(255, 255, 255, 0.8) 50%, - rgba(255, 255, 255, 0.3) 100% + rgba(0, 0, 0, 0.3) 0%, + rgba(0, 0, 0, 0.8) 50%, + rgba(0, 0, 0, 0.3) 100% ); background-position: center; background-size: cover; @@ -60,7 +60,7 @@ const HighLightText = styled(motion.div)` -webkit-background-clip: text; -webkit-text-fill-color: transparent; - ${media.mobile} { + ${media.small} { ${({ theme }) => theme.textStyleV2.resp.subtitle2_sm}; } `; diff --git a/components/home/GridSection/index.tsx b/components/home/GridSection/index.tsx index 3e2e5e2..144b6bc 100644 --- a/components/home/GridSection/index.tsx +++ b/components/home/GridSection/index.tsx @@ -25,7 +25,12 @@ function GridSection(): ReactElement { > - + theme.palette.black}; + background-color: ${({ theme }) => theme.palette.white}; width: auto; padding: 160px 80px; diff --git a/components/home/IntroSection/Banner28th.tsx b/components/home/IntroSection/Banner28th.tsx new file mode 100644 index 0000000..1745ef8 --- /dev/null +++ b/components/home/IntroSection/Banner28th.tsx @@ -0,0 +1,141 @@ +import { useEffect, useState } from 'react'; +import styled from 'styled-components'; +import media from 'styles/media'; +import Image from 'next/image'; + +const Banner28th = () => { + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + return ( + <> + + + 28th Title + + + 28th Title + + + 28th Title + + + + + + ); +}; + +export default Banner28th; + +const BannerBackgroundInner = styled.div` + position: relative; + width: 100vw; + height: 100vh; + margin: 0 auto; + display: flex; + justify-content: center; + align-items: center; + + opacity: 0; + transition: transform 1s ease, opacity 1s ease; + + &.appear { + opacity: 1; + } + + background-size: cover; + background-repeat: no-repeat; + background-position: center center; + background-image: url('/assets/images/28th/banner_home_pc.png'); + + ${media.tablet} { + background-image: url('/assets/images/28th/banner_home_tablet.png'); + } + + ${media.mobile} { + background-image: url('/assets/images/28th/banner_home_mobile.png'); + } +`; + +const TitlePc = styled.div` + display: block; + ${media.tablet} { + display: none; + } +`; + +const TitleTablet = styled.div` + display: none; + ${media.tablet} { + display: block; + } + ${media.mobile} { + display: none; + } +`; + +const TitleMobile = styled.div` + display: none; + ${media.mobile} { + display: block; + } +`; + +const Banner28thTextContentBox = styled.div` + position: absolute; + left: 50%; + top: 80px; + z-index: 20; + display: flex; + height: fit-content; + flex-direction: column; + justify-content: center; + align-items: center; + white-space: nowrap; + + transition: transform 1s ease, opacity 1s ease; + transform: translate3d(-50%, -2rem, 0); + opacity: 0; + + &.appear { + transform: translate3d(-50%, 0, 0); + opacity: 1; + + animation: floatY 1s ease-in-out infinite alternate; + } + + ${media.tablet} { + top: 220px; + } + + @keyframes floatY { + 0% { + transform: translate3d(-50%, 0, 0); + } + 100% { + transform: translate3d(-50%, 10px, 0); + } + } +`; diff --git a/components/home/IntroSection/BannerPre.tsx b/components/home/IntroSection/BannerPre.tsx index a35e13d..80b2084 100644 --- a/components/home/IntroSection/BannerPre.tsx +++ b/components/home/IntroSection/BannerPre.tsx @@ -1,10 +1,10 @@ import { Button } from 'components/common'; -import { NEXT_GENERATION_RECRUIT_LINK } from 'database/recruit'; import YappuLogo from 'public/assets/images/Pre/illust_mini.svg'; import { useEffect, useState } from 'react'; import styled from 'styled-components'; import media from 'styles/media'; import Dday from '../Dday'; +import Yapp from '../../../constants/yapp'; const BannerPre = () => { const [mounted, setMounted] = useState(false); @@ -29,7 +29,9 @@ const BannerPre = () => { (window.location.href = NEXT_GENERATION_RECRUIT_LINK)} + onClick={() => + (window.location.href = Yapp.NEXT_GENERATION_RECRUIT_LINK) + } > ⏰ 26기 모집 알림 신청하기 diff --git a/components/home/RecuitBtn/index.tsx b/components/home/RecuitBtn/index.tsx index e1e49ee..85a10ac 100644 --- a/components/home/RecuitBtn/index.tsx +++ b/components/home/RecuitBtn/index.tsx @@ -1,19 +1,29 @@ import { + type ReactElement, useCallback, useEffect, useRef, useState, - type ReactElement, } from 'react'; import styled from 'styled-components'; import media from 'styles/media'; import { motion, useAnimation } from 'framer-motion'; import theme from 'styles/theme'; import Yapp from 'constants/yapp'; +import { + LINK_BY_STATUS, + RECRUITING_STATUS, + RecruitStatus, +} from '../../../constants/status'; +import { RECRUIT_BANNER_BY_STATUS } from '../../../database/recruit'; + +interface RecuitBtnProps { + status: RecruitStatus; +} -function RecuitBtn(): ReactElement { +function RecuitBtn({ status }: RecuitBtnProps): ReactElement | null { const controls = useAnimation(); - const [visible, setVisible] = useState(true); + const [isSectionInView, setIsSectionInView] = useState(false); const joinSectionRef = useRef(null); useEffect(() => { @@ -21,20 +31,14 @@ function RecuitBtn(): ReactElement { if (!section) return; joinSectionRef.current = section as HTMLElement; - const observer = new IntersectionObserver( ([entry]) => { - if (entry.isIntersecting) { - setVisible(true); // JoinSection 전까지 범위에서만 FAB 노출 - } else { - setVisible(false); // JoinSection 벗어나면 FAB 숨김 - } + setIsSectionInView(entry.isIntersecting); }, { threshold: 0.1 }, ); observer.observe(section); - return () => observer.disconnect(); }, []); @@ -56,16 +60,20 @@ function RecuitBtn(): ReactElement { }); }, [controls]); + const isVisible = status === RecruitStatus.ACTIVE && isSectionInView; + const targetLink = LINK_BY_STATUS[status]; + const BannerInfo = RECRUIT_BANNER_BY_STATUS[status]; + return ( window.open(Yapp.YAPP_RECRUIT_ALL, '_blank')} + $visible={isVisible} + onClick={() => window.open(targetLink, '_blank')} onMouseEnter={handleHoverStart} onMouseLeave={handleHoverEnd} > - 10.16(목) - 10.25(토) + 4.17(금) - 4.26(일) - {Yapp.YAPP_GENERATION}기 지원하기 + {BannerInfo.buttonName} ); diff --git a/components/home/SponsorSection/index.tsx b/components/home/SponsorSection/index.tsx index 30fcd0d..ac1469f 100644 --- a/components/home/SponsorSection/index.tsx +++ b/components/home/SponsorSection/index.tsx @@ -81,6 +81,7 @@ const SectionInner = styled.div` const SponsorList = styled.ul` display: flex; + justify-content: center; gap: 1.6rem; margin: 48px 0; width: 100%; diff --git a/components/recruit/FindMember/index.tsx b/components/recruit/FindMember/index.tsx index 3c39e5e..afe3053 100644 --- a/components/recruit/FindMember/index.tsx +++ b/components/recruit/FindMember/index.tsx @@ -7,54 +7,49 @@ import { motion } from 'framer-motion'; function FindMember(): ReactElement { return ( - <> - - - {FIND_YAPPU.map((item, idx) => ( - - {item.textParts.map((part, j) => - typeof part === 'string' ? ( - part.split('\n').map((line, k) => ( - - {line} - {k !== part.split('\n').length - 1 &&
} -
- )) - ) : ( - {part.img} - ), - )} -
- ))} -
-
- - + + + {FIND_YAPPU.map((item, idx) => ( + + {item.textParts.map((part, j) => + typeof part === 'string' ? ( + part.split('\n').map((line, k) => ( + + {line} + {k !== part.split('\n').length - 1 &&
} +
+ )) + ) : ( + + ), + )} +
+ ))} +
+
); } const SectionTemplate = styled.section` display: flex; justify-content: center; - background-color: ${({ theme }) => theme.palette.black}; - width: auto; - padding: 234px 80px; - - ${media.mobile} { - padding: 204px 12px; - } + background-color: #f6f6f6; + width: 100%; + padding: 80px 0; `; const SectionContent = styled.ul` @@ -63,37 +58,44 @@ const SectionContent = styled.ul` align-items: center; gap: 84px; width: 100%; - max-width: 1200px; - justify-content: space-between; + max-width: 1040px; + justify-content: center; + + ${media.mobile} { + gap: 48px; + } `; const TextList = styled.li` text-align: center; width: 100%; - height: 100vh; +`; - & > img { - margin: 0 10px; - ${media.mobile} { - width: 28px; - height: 22px; - } +const YappuIcon = styled(Image)<{ + $mobileWidth: number; + $mobileHeight: number; +}>` + margin: 0 8px; + vertical-align: middle; + + ${media.mobile} { + width: ${({ $mobileWidth }) => $mobileWidth}px !important; + height: ${({ $mobileHeight }) => $mobileHeight}px !important; } `; const MotionTextPart = styled(motion.span)` - color: ${({ theme }) => theme.palette.white_100}; - ${({ theme }) => theme.textStyleV2.resp.subtitle2_md}; + color: ${({ theme }) => theme.palette.black_100}; + font-weight: 600; + font-size: 40px; + line-height: 64px; + letter-spacing: -0.8px; ${media.mobile} { - ${({ theme }) => theme.textStyleV2.resp.subtitle2_sm}; + font-size: 20px; + line-height: 32px; + letter-spacing: -0.4px; } `; -const GradientSection = styled.div` - width: 100%; - height: 100vh; - background: linear-gradient(180deg, #000000 50%, rgb(255, 255, 255) 90%); -`; - export default FindMember; diff --git a/components/recruit/RecruitBanner/index.tsx b/components/recruit/RecruitBanner/index.tsx index 64a7308..f69face 100644 --- a/components/recruit/RecruitBanner/index.tsx +++ b/components/recruit/RecruitBanner/index.tsx @@ -1,61 +1,97 @@ -import { Button } from 'components/common'; -import Path from 'constants/path'; import { - IS_RECRUITING, - NEXT_GENERATION_RECRUIT_LINK, - RECRUIT_BANNER, - RECRUIT_BANNER_ACTIVE, -} from 'database/recruit'; + LINK_BY_STATUS, + RECRUITING_DEADLINE, + RECRUITING_START, + RECRUITING_STATUS, + RecruitStatus, +} from '../../../constants/status'; +import { RECRUIT_BANNER_BY_STATUS } from 'database/recruit'; import { useDday } from 'hooks/useDday'; -import { useRouter } from 'next/router'; import styled, { keyframes } from 'styled-components'; import media from 'styles/media'; import TimeBlock from '../TimeBlock'; -import Yapp from 'constants/yapp'; +import { useEffect, useState } from 'react'; function RecruitBanner() { - const BannerInfo = IS_RECRUITING ? RECRUIT_BANNER_ACTIVE : RECRUIT_BANNER; - const { days, hrs, mins, secs } = useDday(new Date('2025-10-25T23:59:59')); + const [isMounted, setIsMounted] = useState(false); + const [currentStatus, setCurrentStatus] = useState( + RecruitStatus.PRE, + ); + + useEffect(() => { + setIsMounted(true); + setCurrentStatus(RECRUITING_STATUS()); + + const timer = setInterval(() => { + const nextStatus = RECRUITING_STATUS(); + setCurrentStatus(nextStatus); + }, 1000); + + return () => clearInterval(timer); + }, []); + + const targetDate = (() => { + switch (currentStatus) { + case RecruitStatus.PRE: + return new Date(RECRUITING_START); + case RecruitStatus.ACTIVE: + return new Date(RECRUITING_DEADLINE); + default: + return new Date(); + } + })(); + + const { days, hrs, mins, secs } = useDday(targetDate); - const router = useRouter(); + if (!isMounted) return null; + + const BannerInfo = RECRUIT_BANNER_BY_STATUS[currentStatus]; + const targetLink = LINK_BY_STATUS[currentStatus]; return ( - - {BannerInfo.title} - - - : - - : - - : - - - - + + + {BannerInfo.title} + + + : + + : + + : + + + { + window.open(targetLink, '_blank'); + }} + > + {BannerInfo.buttonName} + + + ); } const RecruitBannerContainer = styled.div` - position: relative; display: flex; justify-content: center; width: 100vw; - height: 100vh; - background: url('/assets/images/27th/recruit.png') no-repeat center/cover; + height: 960px; + background: ${({ theme }) => theme.palette.white}; + + ${media.mobile} { + height: 100vh; + } +`; + +const BannerImageBox = styled.div` + position: relative; + width: 100%; + height: 100%; + background: url('/assets/images/28th/recruit_bg.png') no-repeat center/cover; `; const slideUp = keyframes` @@ -69,26 +105,27 @@ const slideUp = keyframes` } `; -const BannerTitle = styled.div` - ${({ theme }) => theme.textStyleV2.resp.title1_md}; - color: ${({ theme }) => theme.palette.white_80}; - - ${media.mobile} { - ${({ theme }) => theme.textStyleV2.resp.title1_sm}; - } -`; - const InnerContainer = styled.div` - padding-top: 238px; display: flex; flex-direction: column; - gap: 8px; + gap: 32px; align-items: center; text-align: center; + padding-top: 238px; animation: ${slideUp} 1s ease-in-out forwards; ${media.mobile} { padding-top: 144px; + gap: 24px; + } +`; + +const BannerTitle = styled.div` + ${({ theme }) => theme.textStyleV2.resp.title1_md}; + color: ${({ theme }) => theme.palette.discovery_28th_text_80}; + + ${media.mobile} { + ${({ theme }) => theme.textStyleV2.resp.title1_sm}; } `; @@ -97,11 +134,15 @@ const TimeList = styled.ul` justify-content: center; align-items: center; gap: 20px; - margin: 0 0 32px 0; + + ${media.mobile} { + gap: 14px; + } `; const Colon = styled.span` - color: ${({ theme }) => theme.palette.white_100}; + color: ${({ theme }) => theme.palette.discovery_28th_text}; + opacity: 0.8; ${({ theme }) => theme.textStyleV2.resp.subtitle_md}; ${media.mobile} { @@ -109,4 +150,31 @@ const Colon = styled.span` } `; +const ApplyButton = styled.button` + all: unset; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 7px 18px 8px; + border-radius: 99px; + background-color: ${({ theme }) => theme.palette.discovery_28th_button}; + color: ${({ theme }) => theme.palette.white_100}; + ${({ theme }) => theme.textStyleV2.resp.body_point_md}; + transition: opacity 0.2s ease, transform 0.2s ease; + + &:hover { + opacity: 0.85; + } + + &:active { + transform: scale(0.97); + } + + ${media.mobile} { + padding: 8px 18px; + ${({ theme }) => theme.textStyleV2.resp.body_point_sm}; + } +`; + export default RecruitBanner; diff --git a/components/recruit/RecruitField/index.tsx b/components/recruit/RecruitField/index.tsx index d1ddceb..78ac67e 100644 --- a/components/recruit/RecruitField/index.tsx +++ b/components/recruit/RecruitField/index.tsx @@ -1,16 +1,12 @@ -import { - IS_RECRUITING, - RECRUIT_FIELD_NAMES, - RECRUIT_TITLE, -} from 'database/recruit'; -import { ReactElement, useEffect, useState } from 'react'; +import { ReactElement, useState } from 'react'; +import { RECRUITING_STATUS, RecruitStatus } from '../../../constants/status'; +import { RECRUIT_FIELD_NAMES, RECRUIT_TITLE } from 'database/recruit'; import SectionTitle from 'components/common/SectionTitle'; import styled from 'styled-components'; import media from 'styles/media'; import theme from 'styles/theme'; import RecruitCard from '../RecuitCard'; -import { motion, useAnimation, AnimatePresence } from 'framer-motion'; -import { useInView } from 'react-intersection-observer'; +import { motion } from 'framer-motion'; import { useScrollAnimation } from 'hooks/useScrollAnimation'; function RecruitField(): ReactElement { @@ -35,7 +31,7 @@ function RecruitField(): ReactElement { key={field.name} variants={itemVariants} onClick={() => { - if (IS_RECRUITING && field.url) { + if (RECRUITING_STATUS() === RecruitStatus.ACTIVE && field.url) { window.open(field.url, '_blank'); } }} @@ -45,10 +41,11 @@ function RecruitField(): ReactElement { description={field.description} backInfo={field.backInfo} backgroundColor={field.backgroundColor as any} + position={index} isFlipped={flippedIndex === index} onHoverStart={() => setFlippedIndex(index)} onHoverEnd={() => setFlippedIndex(null)} - isRecruiting={IS_RECRUITING} + recruitingStatus={RECRUITING_STATUS()} /> ))} @@ -60,7 +57,7 @@ function RecruitField(): ReactElement { export default RecruitField; const SectionLayout = styled.section` - background-color: ${theme.palette.black}; + background-color: ${theme.palette.white}; display: flex; flex-direction: column; align-items: center; diff --git a/components/recruit/RecruitSchedule/index.tsx b/components/recruit/RecruitSchedule/index.tsx index c781ced..b37000a 100644 --- a/components/recruit/RecruitSchedule/index.tsx +++ b/components/recruit/RecruitSchedule/index.tsx @@ -16,7 +16,7 @@ const additionalSchedule = { { label: '1차 서류', text: '지원서 작성 및 포트폴리오 제출' }, { label: '2차 면접', text: '온라인 인터뷰 후 최종 합격' }, ], - color: 'circus_blue', + color: 'discovery_28th_blue', fontColor: 'white_100', }; @@ -151,7 +151,7 @@ const CardLabel = styled.span` white-space: nowrap; padding: 4px; border-radius: 4px; - background-color: ${({ theme }) => theme.palette.black_100}; + background-color: ${({ theme }) => theme.palette.white_20}; color: ${({ theme }) => theme.palette.white_100}; ${({ theme }) => theme.textStyleV2.resp.caption_md}; diff --git a/components/recruit/RecuitCard/index.tsx b/components/recruit/RecuitCard/index.tsx index ea95464..dde7360 100644 --- a/components/recruit/RecuitCard/index.tsx +++ b/components/recruit/RecuitCard/index.tsx @@ -3,6 +3,7 @@ import styled from 'styled-components'; import { motion } from 'framer-motion'; import theme, { PaletteKeyTypes } from 'styles/theme'; import { CircleArrow } from 'public/assets/icons'; +import { RecruitStatus } from '../../../constants/status'; interface CardProps { name: string; @@ -12,7 +13,8 @@ interface CardProps { isFlipped: boolean; onHoverStart: () => void; onHoverEnd: () => void; - isRecruiting?: boolean; + recruitingStatus?: RecruitStatus; + position?: number; } function RecruitCard({ @@ -23,7 +25,8 @@ function RecruitCard({ isFlipped, onHoverStart, onHoverEnd, - isRecruiting = true, + recruitingStatus, + position, }: CardProps): ReactElement { return ( -
+

{name}

{description}

-

지원하기

+
+

지원하기

+
@@ -50,7 +67,7 @@ function RecruitCard({ {backInfo.map((info, idx) => (

{info}

))} - +

지원하기

@@ -133,7 +150,6 @@ const ApplyBtn = styled.button<{ display: flex; align-items: center; justify-content: center; - display: flex; gap: 6px; color: ${({ back, color }) => back || !color ? theme.palette.white_100 : theme.palette[color]}; diff --git a/components/recruit/SessionOverview/index.tsx b/components/recruit/SessionOverview/index.tsx index b9adcdf..2e5d6bf 100644 --- a/components/recruit/SessionOverview/index.tsx +++ b/components/recruit/SessionOverview/index.tsx @@ -38,26 +38,24 @@ function SessionOverview(): ReactElement { animate={controls} variants={containerVariants} > - {overviewContents.map( - ({ date, programs, backgroundColor }, index) => ( - ( + + - - {date} - - - {programs.map((program, i) => ( - {program} - ))} - - - ), - )} + {date} + + + {programs.map((program, i) => ( + {program} + ))} + + + ))} @@ -92,6 +90,8 @@ const SectionContent = styled.ul` const OverviewContentBox = styled.li` list-style: none; width: 100%; + display: flex; + flex-direction: column; `; const OverviewContentSubTitle = styled.div<{ @@ -113,11 +113,25 @@ const OverviewContentSubTitle = styled.div<{ const OverviewContentContent = styled.div` border-radius: 0 0 8px 8px; display: flex; - justify-content: space-around; + justify-content: space-between; + align-items: stretch; ${({ theme }) => theme.textStyleV2.fix.font_15}; background-color: ${({ theme }) => theme.palette.black_5}; color: ${({ theme }) => theme.palette.black_80}; padding: 22px 0; + flex: 1; + + & > span { + flex: 1 1 0; + min-width: 0; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + white-space: pre-line; + padding: 0 12px; + } `; export default SessionOverview; diff --git a/components/recruit/TimeBlock/index.tsx b/components/recruit/TimeBlock/index.tsx index 0ff3964..3d429e9 100644 --- a/components/recruit/TimeBlock/index.tsx +++ b/components/recruit/TimeBlock/index.tsx @@ -29,7 +29,7 @@ const TimeText = styled.span` justify-content: center; align-items: center; ${({ theme }) => theme.textStyleV2.resp.timer_md}; - color: ${({ theme }) => theme.palette.white_100}; + color: ${({ theme }) => theme.palette.discovery_28th_text}; font-variant-numeric: tabular-nums; text-align: center; @@ -41,7 +41,7 @@ const TimeText = styled.span` const TimeLabel = styled.span` ${({ theme }) => theme.textStyleV2.resp.subtitle_md}; - color: ${({ theme }) => theme.palette.white_50}; + color: ${({ theme }) => theme.palette.discovery_28th_text_50}; ${media.mobile} { ${({ theme }) => theme.textStyleV2.resp.subtitle_sm}; diff --git a/constants/headerMenus.ts b/constants/headerMenus.ts index b087908..86e5c17 100644 --- a/constants/headerMenus.ts +++ b/constants/headerMenus.ts @@ -13,8 +13,8 @@ export const HEADER_MENUS = [ name: '프로젝트', path: Path.Project, }, - { - name: '얍 활동', - path: Path.Story, - }, + // { + // name: '얍 활동', + // path: Path.Story, + // }, ]; diff --git a/constants/status.ts b/constants/status.ts new file mode 100644 index 0000000..9257769 --- /dev/null +++ b/constants/status.ts @@ -0,0 +1,27 @@ +import Yapp from './yapp'; + +/* 리크루팅 상태: PRE(모집 오픈 전), ACTIVE(모집 중), POST(모집 마감) */ +export enum RecruitStatus { + PRE = 'PRE', + ACTIVE = 'ACTIVE', + POST = 'POST', +} + +export const RECRUITING_START = '2026-04-17T00:00:00'; +export const RECRUITING_DEADLINE = '2026-04-26T23:59:59'; + +export const RECRUITING_STATUS = (): RecruitStatus => { + const now = new Date(); + const start = new Date(RECRUITING_START); + const deadline = new Date(RECRUITING_DEADLINE); + + if (now < start) return RecruitStatus.PRE; + if (now > deadline) return RecruitStatus.POST; + return RecruitStatus.ACTIVE; +}; + +export const LINK_BY_STATUS: Record = { + [RecruitStatus.PRE]: Yapp.PREVIOUS_GENERATION_RECRUIT_LINK, + [RecruitStatus.ACTIVE]: Yapp.YAPP_RECRUIT_ALL, + [RecruitStatus.POST]: Yapp.NEXT_GENERATION_RECRUIT_LINK, +}; diff --git a/constants/yapp.ts b/constants/yapp.ts index e064c57..0fdb6c7 100644 --- a/constants/yapp.ts +++ b/constants/yapp.ts @@ -1,6 +1,6 @@ const Yapp = { YAPP_NAME: 'YAPP', - YAPP_GENERATION: 27, // 기수 + YAPP_GENERATION: 28, // 기수 YAPP_OFFICIAL_EMAIL: 'support@yapp.co.kr', YAPP_OFFICIAL_KAKAO: '@YAPP', YAPP_OFFICIAL_FACEBOOK: '@YAPP', @@ -9,26 +9,28 @@ const Yapp = { YAPP_INSTAGRAM: 'https://www.instagram.com/about.yapp/', YAPP_KAKAO: 'http://pf.kakao.com/_aGxofd', YAPP_GITHUB: 'https://github.com/YAPP-Github', - // 지원하기 관련 링크 + YAPP_MEDIUM: 'https://medium.com/@about.yapp', + YAPP_LINKEDIN: 'https://www.linkedin.com/company/yappu/', + + // 공고 링크 YAPP_RECRUIT_ALL: 'https://yapp-recruit.career.greetinghr.com/ko/apply', YAPP_RECRUIT_PROJECT_MANAGER: - 'https://yapp-recruit.career.greetinghr.com/ko/o/177927', - YAPP_RECRUIT_DESIGNER: - 'https://yapp-recruit.career.greetinghr.com/ko/o/177931', - YAPP_RECRUIT_IOS: 'https://yapp-recruit.career.greetinghr.com/ko/o/177938', - YAPP_RECRUIT_ANDROID: - 'https://yapp-recruit.career.greetinghr.com/ko/o/177936', - YAPP_RECRUIT_FRONT_END: - 'https://yapp-recruit.career.greetinghr.com/ko/o/177934', - YAPP_RECRUIT_BACK_END: - 'https://yapp-recruit.career.greetinghr.com/ko/o/176953', + 'https://yapp-recruit.career.greetinghr.com/o/210447', + YAPP_RECRUIT_DESIGNER: 'https://yapp-recruit.career.greetinghr.com/o/210451', + YAPP_RECRUIT_IOS: 'https://yapp-recruit.career.greetinghr.com/o/210434', + YAPP_RECRUIT_ANDROID: 'https://yapp-recruit.career.greetinghr.com/o/210373', + YAPP_RECRUIT_FRONT_END: 'https://yapp-recruit.career.greetinghr.com/o/210439', + YAPP_RECRUIT_BACK_END: 'https://yapp-recruit.career.greetinghr.com/o/210444', YAPP_RECRUIT_CROSS_PLATFORM: 'https://yapp-recruit.career.greetinghr.com/o/106740', - YAPP_MEDIUM: 'https://medium.com/@about.yapp', - YAPP_LINKEDIN: 'https://www.linkedin.com/company/yappu/', - // FAQ 관련 링크 - YAPP_FAQ_NOTION: - 'https://www.notion.so/yapp-workspace/YAPP-27-FAQ-2812106a0e8480b28cc3f89e3bd6ffe1', + // FAQ 링크 + YAPP_FAQ_NOTION: 'https://yapp-workspace.notion.site/yapp-28-faq', + + // 사전 모집 링크 + PREVIOUS_GENERATION_RECRUIT_LINK: + 'https://docs.google.com/forms/d/e/1FAIpQLSeAtEn6VTKxoWlzkYv_Sp_JHrzILJCl6l2tT4ccWfhq-UuEbg/viewform', + NEXT_GENERATION_RECRUIT_LINK: + 'https://docs.google.com/forms/d/e/1FAIpQLSeAtEn6VTKxoWlzkYv_Sp_JHrzILJCl6l2tT4ccWfhq-UuEbg/viewform', }; export default Yapp; diff --git a/database/home.ts b/database/home.ts index 2b147e4..eda994c 100644 --- a/database/home.ts +++ b/database/home.ts @@ -1,47 +1,48 @@ import Yapp from 'constants/yapp'; +import { RecruitStatus } from '../constants/status'; /** Grid Section */ export const CURRENT_INFO_DATA = [ { title: '운영 기간', - content: '15년', - icon: '/assets/icons/running_year.svg', - color: 'circus_red', + content: '16년', + icon: '/assets/images/28th/icons/running_year.png', + color: 'discovery_28th_red', fontColor: 'white_100', }, { title: '운영기수', - content: '26기', - icon: '/assets/icons/cohort.svg', - color: 'white', + content: '27기', + icon: '/assets/images/28th/icons/cohort.png', + color: 'discovery_28th_beige', fontColor: 'black_100', }, { title: '현재 활동 회원', content: '65명', - icon: '/assets/icons/members.svg', - color: 'circus_blue', + icon: '/assets/images/28th/icons/active_members.png', + color: 'discovery_28th_blue', fontColor: 'white_100', }, { title: '누적 활동 인원', - content: '500+명', - icon: '/assets/icons/total_members.svg', - color: 'circus_red', + content: '600+명', + icon: '/assets/images/28th/icons/total_members.png', + color: 'discovery_28th_red', fontColor: 'white_100', }, { title: '런칭 서비스', - content: '60+개', - icon: '/assets/icons/service.svg', - color: 'white', + content: '70+개', + icon: '/assets/images/28th/icons/service.png', + color: 'discovery_28th_beige', fontColor: 'black_100', }, { title: '누적 앱 다운로드', content: '400,000+', - icon: '/assets/icons/download.svg', - color: 'circus_blue', + icon: '/assets/images/28th/icons/download.png', + color: 'discovery_28th_blue', fontColor: 'white_100', }, ]; @@ -49,39 +50,34 @@ export const CURRENT_INFO_DATA = [ /** Carousel에 들어갈 프로젝트 데이터 */ export const CAROUSEL_DATA = [ { - title: 'Lettie', - link: '/project/26th/lettie', - image: '/assets/project/26_thumbnail_lettie.png', + title: 'keepiluv', + link: '/project/27th/keepluv', + image: '/assets/project/27_thumbnail_keepluv.png', }, { - title: 'Ssok', - link: '/project/26th/ssok', - image: '/assets/project/26_thumbnail_ssok.png', + title: 'Lokit', + link: '/project/27th/lokit', + image: '/assets/project/27_thumbnail_lokit.jpg', }, { - title: '잇다', - link: '/project/26th/eatda', - image: '/assets/project/26_thumbnail_eatda.png', + title: 'moa', + link: '/project/27th/moa', + image: '/assets/project/27_thumbnail_moa.png', }, { - title: 'FitRun', - link: '/project/26th/fitrun', - image: '/assets/project/26_thumbnail_fitrun.png', + title: 'moit & weddin', + link: '/project/27th/moit&weddin', + image: '/assets/project/27_thumbnail_moitweddin.png', }, { - title: '빛나길', - link: '/project/26th/bitnagil', - image: '/assets/project/26_thumbnail_bitnagil.png', + title: '나도갈래', + link: '/project/27th/nadogalrae', + image: '/assets/project/27_thumbnail_nadogalrae.jpg', }, { - title: 'brake', - link: '/project/26th/brake', - image: '/assets/project/26_thumbnail_brake.png', - }, - { - title: 'Reed', - link: '/project/26th/reed', - image: '/assets/project/26_thumbnail_reed.jpg', + title: '네키', + link: '/project/27th/neki', + image: '/assets/project/27_thumbnail_neki.jpg', }, ]; @@ -165,40 +161,64 @@ export const SPONSOR_SECTION = { /** Sponsor 이미지 경로 */ export const SPONSOR_DATA = [ { - image: '/assets/sponsors/sponsor_flab.png', - alt: 'sponsor F-Lab', + image: '/assets/sponsors/sponsor_greeting.png', + alt: 'sponsor greeting', }, { image: '/assets/sponsors/sponsor_elice.png', alt: 'sponsor elice', }, { - image: '/assets/sponsors/sponsor_goorm.png', - alt: 'sponsor goorm', + image: '/assets/sponsors/sponsor_dcamp.png', + alt: 'sponsor dcamp', }, { - image: '/assets/sponsors/sponsor_fiveSpot.png', - alt: 'sponsor fiveSpot', - }, - { - image: '/assets/sponsors/sponsor_greeting.png', - alt: 'sponsor greeting', + image: '/assets/sponsors/sponsor_flab.png', + alt: 'sponsor F-Lab', }, + // { + // image: '/assets/sponsors/sponsor_goorm.png', + // alt: 'sponsor goorm', + // }, + // { + // image: '/assets/sponsors/sponsor_fiveSpot.png', + // alt: 'sponsor fiveSpot', + // }, ]; +export interface RecruitBannerInfo { + title: string; + subTitle: string; + date: string; + buttonName: string; +} + /* 모집 관련 상수 */ -export const RECRUIT_BANNER = { - title: 'FIND YOUR BALANCE', - subTitle: `다음 기수의 모집 소식을 가장 먼저 만나보세요`, - date: '지금은 모집 기간이 아닙니다', - buttonName: `${Number(Yapp.YAPP_GENERATION) + 1}기 모집 알림 신청하기`, +export const HOME_BANNER_PRE = { + title: 'MOMENT OF DISCOVERY', + subTitle: `YAPP ${Number(Yapp.YAPP_GENERATION)}기 모집이\n곧 시작됩니다`, + date: '4.17(금) - 4.26(일)', + buttonName: `${Number(Yapp.YAPP_GENERATION)}기 모집 알림 신청하기`, }; -export const RECRUIT_BANNER_PRE = { - title: 'FIND YOUR BALANCE', +export const HOME_BANNER_ACTIVE = { + title: 'MOMENT OF DISCOVERY', subTitle: `지원하기 버튼 하나로\nYAPP ${Number( Yapp.YAPP_GENERATION, )}기의 야뿌가 되어보세요.`, - date: '10.16(목) - 10.25(토)', + date: '4.17(금) - 4.26(일)', buttonName: `${Number(Yapp.YAPP_GENERATION)}기 지원하기`, }; + +export const HOME_BANNER_POST = { + title: 'MOMENT OF DISCOVERY', + subTitle: `다음 기수의 모집 소식을 가장 먼저 만나보세요`, + date: '지금은 모집 기간이 아닙니다', + buttonName: `${Number(Yapp.YAPP_GENERATION) + 1}기 모집 알림 신청하기`, +}; + +export const HOME_BANNER_BY_STATUS: Record = { + [RecruitStatus.PRE]: HOME_BANNER_PRE, + [RecruitStatus.ACTIVE]: HOME_BANNER_ACTIVE, + [RecruitStatus.POST]: HOME_BANNER_POST, +}; diff --git a/database/recruit.ts b/database/recruit.ts index 50932bf..cdc4c1d 100644 --- a/database/recruit.ts +++ b/database/recruit.ts @@ -1,27 +1,38 @@ import Yapp from 'constants/yapp'; - -/* 현재 모집중이면 true 아니면 false */ -export const IS_RECRUITING = false; +import { RecruitStatus } from '../constants/status'; /** Banner */ -export const RECRUIT_BANNER = { - title: '지금은 모집기간이 아닙니다', - buttonName: `${Number(Yapp.YAPP_GENERATION) + 1}기 모집 알림 신청하기`, -}; -export const RECRUIT_BANNER_PRE = { - title: `${Number(Yapp.YAPP_GENERATION)}기 모집 마감까지`, - buttonName: `${Number(Yapp.YAPP_GENERATION)}기 지원하기`, +interface RecruitBannerInfo { + title: string; + description?: string; + buttonName: string; +} + +const RECRUIT_BANNER_PRE: RecruitBannerInfo = { + title: `${Number(Yapp.YAPP_GENERATION)}기 모집 오픈까지`, + buttonName: `${Number(Yapp.YAPP_GENERATION)}기 모집 알림 신청하기`, }; -export const RECRUIT_BANNER_ACTIVE = { +const RECRUIT_BANNER_ACTIVE: RecruitBannerInfo = { title: `${Number(Yapp.YAPP_GENERATION)}기 모집 마감까지`, description: `YAPP ${Yapp.YAPP_GENERATION}기에서 4개월간 활동할
PM(기획자)/디자이너/개발자 신입 회원을
모집합니다.
IT 분야에 대한 열정과 의지가
넘치고, 동아리에서 다양한 사람들과 즐겁게
활동하고 싶은 분들의 많은 지원 바랍니다!`, buttonName: `${Yapp.YAPP_GENERATION}기 지원하기`, }; -export const NEXT_GENERATION_RECRUIT_LINK = - 'https://docs.google.com/forms/d/e/1FAIpQLSeAtEn6VTKxoWlzkYv_Sp_JHrzILJCl6l2tT4ccWfhq-UuEbg/viewform'; +const RECRUIT_BANNER_POST: RecruitBannerInfo = { + title: '지금은 모집기간이 아닙니다', + buttonName: `${Number(Yapp.YAPP_GENERATION) + 1}기 모집 알림 신청하기`, +}; + +export const RECRUIT_BANNER_BY_STATUS: Record< + RecruitStatus, + RecruitBannerInfo +> = { + [RecruitStatus.PRE]: RECRUIT_BANNER_PRE, + [RecruitStatus.ACTIVE]: RECRUIT_BANNER_ACTIVE, + [RecruitStatus.POST]: RECRUIT_BANNER_POST, +}; /** 세션일정 개요 */ export const SESSION_OVERVIEW = { @@ -30,29 +41,29 @@ export const SESSION_OVERVIEW = { overviewContents: [ { date: '1-4주차', - programs: ['OT', '팀매칭', '팀세션', '팀세션'], - backgroundColor: 'circus_red', + programs: ['OT', '팀빌딩', '친해지길바래', '팀세션'], + backgroundColor: 'black_100', }, { date: '5-8주차', - programs: ['휴-얍', '기획세션', '팀세션', `1차 데브캠프\n(UT)`], - backgroundColor: 'circus_blue', + programs: ['기획세션', '팀세션', `1차 데브캠프\n(UT)`, '팀세션'], + backgroundColor: 'discovery_28th_blue', }, { date: '9-12주차', + programs: [`개발/디자인\n세션`, '팀세션', `2차 데브캠프\n(UT)`, '팀세션'], + backgroundColor: 'discovery_28th_red', + }, + { + date: '13-17주차', programs: [ + `3차 데브캠프\n(해커톤)`, '팀세션', - `개발/디자인\n세션`, - '팀세션', - `2차 데브캠프\n(해커톤)`, + '데모데이', + '회고 & 마무리', ], backgroundColor: 'black_100', }, - { - date: '13-17주차', - programs: [`3차 데브캠프\n(UT)`, '팀세션', '데모데이', '최종 발표회'], - backgroundColor: 'circus_red', - }, ], }; @@ -61,9 +72,15 @@ export const FIND_YAPPU = [ { textParts: [ '새로운 가능성을', - { img: '/assets/icons/yappu_red.svg' }, + { + img: '/assets/icons/yappu_red.svg', + width: 62, + height: 49, + mobileWidth: 28, + mobileHeight: 22, + }, '탐색하고,\n', - '주도적인 협업을 통해 ', + '주도적인 협업을 통해\n', '의미있는 프로젝트를 만들어가는 사람을 찾아요', ], }, @@ -71,7 +88,13 @@ export const FIND_YAPPU = [ textParts: [ '매주 토요일 정규 세션에\n', '참여 가능한 분을', - { img: '/assets/icons/yappu_blue.svg' }, + { + img: '/assets/icons/yappu_blue.svg', + width: 76, + height: 54, + mobileWidth: 38, + mobileHeight: 27, + }, '찾아요', ], }, @@ -79,7 +102,13 @@ export const FIND_YAPPU = [ textParts: [ '타 직군과의 1회 이상\n', '협업 경험이 있는 분', - { img: '/assets/icons/yappu_white.svg' }, + { + img: '/assets/icons/yappu_white.svg', + width: 68, + height: 54, + mobileWidth: 34, + mobileHeight: 27, + }, '을 찾아요', ], }, @@ -93,38 +122,38 @@ export const RECRUIT_SCHEDULE = { schedules: [ { title: '서류 접수', - content: '10.16', - icon: '/assets/icons/running_year.svg', - color: 'circus_red', + content: '4.17', + icon: '/assets/images/28th/icons/running_year.png', + color: 'discovery_28th_red', fontColor: 'white_100', }, { title: '서류 마감', - content: '10.25', - icon: '/assets/icons/cohort.svg', - color: 'circus_gray', - fontColor: 'black_100', + content: '4.26', + icon: '/assets/images/28th/icons/cohort.png', + color: 'discovery_28th_beige', + fontColor: 'discovery_28th_text', }, { title: '서류 결과 발표', - content: '10.29', - icon: '/assets/icons/members.svg', - color: 'circus_blue', + content: '4.29', + icon: '/assets/images/28th/icons/active_members.png', + color: 'discovery_28th_blue', fontColor: 'white_100', }, { title: '면접', - content: '11.01-05', - icon: '/assets/icons/total_members.svg', - color: 'circus_red', + content: '5.1-5.5', + icon: '/assets/images/28th/icons/total_members.png', + color: 'discovery_28th_red', fontColor: 'white_100', }, { title: '최종 발표', - content: '11.07', - icon: '/assets/icons/service.svg', - color: 'circus_gray', - fontColor: 'black_100', + content: '5.8', + icon: '/assets/images/28th/icons/service.png', + color: 'discovery_28th_beige', + fontColor: 'discovery_28th_text', }, ], }; @@ -136,7 +165,7 @@ export const RECRUIT_FAQ = { faqs: [ { subTitle: 'YAPP은 어떤 동아리인가요?', - description: `YAPP은 PM(기획자), 디자이너, 개발자로 팀을 구성하여 4개월간 하나의 IT 서비스(웹,앱,etc.)를 제작하는 기업형 IT연합 커뮤니티입니다.
+ description: `YAPP은 PM(기획자), 디자이너, 개발자로 팀을 구성하여 4개월간 하나의 IT 웹/앱 서비스를 제작하는 기업형 IT연합 커뮤니티입니다.
서비스 문제 정의, 출시, 제작, 운영까지 팀원들의 아이디어를 실제 IT 서비스로 구체화하며 성장할 수 있습니다.`, isOpen: false, }, @@ -144,23 +173,23 @@ export const RECRUIT_FAQ = { subTitle: '대학생이 아닌 고졸/재직자/졸업자 등도 YAPP에서 활동할 수 있을까요?', description: `4개월간 꾸준히 활동할 수 있고 배우고자 하는 열의가 충분하다면, 누구든 지원이 가능합니다.
- 현재도 고졸/재직자/졸업자 중 활발히 활동하시는 분들이 계십니다.
- 하지만 매주 진행하는 정기 세션과 기수당 2-3회 열리는 해커톤 Dev Camp에 필수적으로 참여해야 하며,
+ 고졸/재직자/졸업자 중 활발히 활동하시는 분들이 계십니다.
+ 하지만 매주 진행하는 정기 세션에 필수적으로 참여해야 하며,
특히 방학 중에는 원활한 프로젝트 진행을 위해 추가적인 팀 활동에 모여야 한다는 점을 숙지해주세요!`, isOpen: false, }, { subTitle: '실력이 뛰어난 사람만 지원할 수 있나요?', description: `YAPP에서는 4개월간 꾸준히 활동할 수 있는지, 그리고 발전하고자 하는 의지가 충분한지를 가장 중요하게 생각합니다.
- 그러나 교육보다는 프로젝트 진행이 중심이기 때문에 자율 스터디나 특강 이외의 교육 커리큘럼을 따로 진행하고 있지 않습니다.
+ 교육보다는 프로젝트 진행이 중심이기 때문에 자율 스터디나 특강 이외의 교육 커리큘럼을 따로 진행하고 있지 않습니다.
따라서 동아리 활동 이외에 개인적으로도 시간과 노력을 투자해야 한다는 점을 알아주시길 바랍니다.`, isOpen: false, }, { subTitle: '정기 모임(세션)은 언제, 어디서 하나요?', - description: `매주 토요일 오후 2시-5시, 세션은 서로 간의 지식 공유&친목 도모를 위해 진행되며 가벼운 뒤풀이도 있을 수 있습니다.
+ description: `매주 토요일 오후 1시-5시, 세션은 서로 간의 지식 공유&친목 도모를 위해 진행되며 가벼운 뒤풀이도 있을 수 있습니다.
오프라인 대면으로 진행되고 있으며 각 기수별 상황에 따라 달라질 수 있습니다.
- 오프라인으로 대부분 수도권에서 세션이 진행되며, 장소 섭외 상황에 따라 변경될 수 있습니다.
+ 오프라인으로 수도권에서 세션이 진행되며, 장소 섭외 상황에 따라 변경될 수 있습니다.
일정, 장소 등 자세한 정보는 내부 채널을 통해 사전 공지해드릴 예정입니다.`, isOpen: false, }, @@ -180,7 +209,7 @@ export const RECRUIT_FAQ = { }, { subTitle: '더 궁금한 사항이 있어요!', - description: `궁금하신 내용은 27기 채용 FAQ를 참고해주시고, 기타 사항은 카카오톡 채널을 통해 문의주세요!`, + description: `궁금하신 내용은 28기 채용 FAQ를 참고해주시고, 기타 사항은 카카오톡 채널을 통해 문의주세요!`, isOpen: false, }, ], @@ -199,7 +228,7 @@ export const RECRUIT_FIELD_NAMES = [ '아이디어를 제시하고 협업을 이끌며 프로젝트를 관리할 수 있는 사람을 찾습니다.', '디자이너·개발자와의 협업 경험, UX 설계나 발표 경험이 있다면 더욱 좋습니다.', ], - backgroundColor: 'circus_red', + backgroundColor: 'discovery_28th_red', }, { name: '디자인', @@ -209,7 +238,7 @@ export const RECRUIT_FIELD_NAMES = [ `UI/UX 설계 역량과 기획·개발 직군과의 협업 능력, 피드백을 반영하는 태도를 가진 분을 찾습니다. `, `프로젝트 경험이나 기획·리서치·데이터 기반 문제 해결 경험이 있다면 더욱 환영합니다.`, ], - backgroundColor: 'white', + backgroundColor: 'discovery_28th_beige', }, { name: 'Web', @@ -219,7 +248,7 @@ export const RECRUIT_FIELD_NAMES = [ `HTML, CSS, JavaScript, React에 대한 이해를 바탕으로 프로젝트를 끝까지 책임감 있게 완수할 수 있는 분을 찾습니다. 협업 경험이나 GitHub 활용, 새로운 기술에 도전한 경험이 있다면 더욱 환영합니다.`, ], - backgroundColor: 'circus_blue', + backgroundColor: 'discovery_28th_blue', }, { name: 'Android', @@ -228,7 +257,7 @@ export const RECRUIT_FIELD_NAMES = [ backInfo: [ `Kotlin 기반 프로젝트 경험과 책임감, 기술 논의에 적극적인 자세를 갖춘 분을 찾습니다. 타 직군 협업 경험이나 Git 활용, MVP, MVVM 등 디자인 패턴 이해도가 있다면 더욱 환영합니다.`, ], - backgroundColor: 'circus_red', + backgroundColor: 'discovery_28th_red', }, { name: 'iOS', @@ -238,7 +267,7 @@ export const RECRUIT_FIELD_NAMES = [ `Swift 기반 프로젝트 경험이 있고, 책임감과 개발 열정으로 문제 해결과 협업에 적극적인 분을 찾습니다.`, `타 직군 협업 경험이나 Git 활용, MVC, MVVM 등 디자인 패턴 이해도가 있다면 더욱 환영합니다.`, ], - backgroundColor: 'white', + backgroundColor: 'discovery_28th_beige', }, { name: 'Server', @@ -248,7 +277,7 @@ export const RECRUIT_FIELD_NAMES = [ `Kotlin/Java와 Spring, 데이터베이스 및 RESTful에 대한 이해를 바탕으로 책임감 있게 프로젝트를 완수할 수 있는 분을 찾습니다.`, `PM과의 소통 경험 또는 Git 활용 경험이 있다면 더욱 환영합니다.`, ], - backgroundColor: 'circus_blue', + backgroundColor: 'discovery_28th_blue', }, ]; @@ -257,5 +286,5 @@ export const RECRUIT_ENQUIRY = { title: `더 궁금하신 내용이 있거나\n문의 사항이 있으신가요?`, description: `리쿠르팅 관련 문의는\n카카오톡 채널을 이용해 주세요.`, caution: `(페이스북 메시지 및 인스타그램 DM은 받지 않습니다)`, - buttonName: '문의 하기', + buttonName: '채널톡 문의 하기', }; diff --git a/pages/_document.tsx b/pages/_document.tsx index 2a578ed..0f2dca5 100644 --- a/pages/_document.tsx +++ b/pages/_document.tsx @@ -48,16 +48,21 @@ export default class MyDocument extends Document { type="text/css" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css" /> - {/* 27th 배너 이미지 프리로드 */} + {/* 28th 배너 이미지 프리로드 */} + diff --git a/pages/index.tsx b/pages/index.tsx index c6183b6..b0bf7cf 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,4 +1,4 @@ -import type { ReactElement } from 'react'; +import { ReactElement, useEffect, useState } from 'react'; import { AnimatedTextSection, GridSection, @@ -7,11 +7,15 @@ import { ProjectSection, SponsorSection, } from 'components/home'; -import { IS_RECRUITING, NEXT_GENERATION_RECRUIT_LINK } from 'database/recruit'; -import { RECRUIT_BANNER, RECRUIT_BANNER_PRE } from 'database/home'; +import { + LINK_BY_STATUS, + RECRUITING_STATUS, + RecruitStatus, +} from '../constants/status'; +import { HOME_BANNER_BY_STATUS } from 'database/home'; import fs from 'fs'; import path from 'path'; -import Banner27th from 'components/home/IntroSection/Banner27th'; +import Banner28th from 'components/home/IntroSection/Banner28th'; import { Medium } from 'types/medium'; import RecuitBtn from 'components/home/RecuitBtn'; import styled from 'styled-components'; @@ -27,25 +31,43 @@ export async function getStaticProps() { } function Home({ data }: { data: Medium[] }): ReactElement { - const BannerInfo = IS_RECRUITING ? RECRUIT_BANNER_PRE : RECRUIT_BANNER; + const [isMounted, setIsMounted] = useState(false); + const [status, setStatus] = useState(RECRUITING_STATUS); + + useEffect(() => { + setIsMounted(true); + setStatus(RECRUITING_STATUS()); + + const timer = setInterval(() => { + setStatus(RECRUITING_STATUS()); + }, 1000); + + return () => clearInterval(timer); + }, []); + + if (!isMounted) return ; + + const BannerInfo = HOME_BANNER_BY_STATUS[status]; + return ( - {/* FAB 노출 범위 */}
- + -
+ - {IS_RECRUITING && } + + {status === RecruitStatus.ACTIVE && }
); } diff --git a/public/assets/images/28th/banner_home_mobile.png b/public/assets/images/28th/banner_home_mobile.png new file mode 100644 index 0000000..f91ba18 Binary files /dev/null and b/public/assets/images/28th/banner_home_mobile.png differ diff --git a/public/assets/images/28th/banner_home_pc.png b/public/assets/images/28th/banner_home_pc.png new file mode 100644 index 0000000..a6236bc Binary files /dev/null and b/public/assets/images/28th/banner_home_pc.png differ diff --git a/public/assets/images/28th/banner_home_tablet.png b/public/assets/images/28th/banner_home_tablet.png new file mode 100644 index 0000000..5b6089a Binary files /dev/null and b/public/assets/images/28th/banner_home_tablet.png differ diff --git a/public/assets/images/28th/icons/active_members.png b/public/assets/images/28th/icons/active_members.png new file mode 100644 index 0000000..db74982 Binary files /dev/null and b/public/assets/images/28th/icons/active_members.png differ diff --git a/public/assets/images/28th/icons/cohort.png b/public/assets/images/28th/icons/cohort.png new file mode 100644 index 0000000..beada6e Binary files /dev/null and b/public/assets/images/28th/icons/cohort.png differ diff --git a/public/assets/images/28th/icons/download.png b/public/assets/images/28th/icons/download.png new file mode 100644 index 0000000..d7d40ff Binary files /dev/null and b/public/assets/images/28th/icons/download.png differ diff --git a/public/assets/images/28th/icons/running_year.png b/public/assets/images/28th/icons/running_year.png new file mode 100644 index 0000000..9d5553c Binary files /dev/null and b/public/assets/images/28th/icons/running_year.png differ diff --git a/public/assets/images/28th/icons/service.png b/public/assets/images/28th/icons/service.png new file mode 100644 index 0000000..66cde6e Binary files /dev/null and b/public/assets/images/28th/icons/service.png differ diff --git a/public/assets/images/28th/icons/total_members.png b/public/assets/images/28th/icons/total_members.png new file mode 100644 index 0000000..b8048b4 Binary files /dev/null and b/public/assets/images/28th/icons/total_members.png differ diff --git a/public/assets/images/28th/news_card.png b/public/assets/images/28th/news_card.png new file mode 100644 index 0000000..536e6f2 Binary files /dev/null and b/public/assets/images/28th/news_card.png differ diff --git a/public/assets/images/28th/project_page_mo.png b/public/assets/images/28th/project_page_mo.png new file mode 100644 index 0000000..bbdf8f7 Binary files /dev/null and b/public/assets/images/28th/project_page_mo.png differ diff --git a/public/assets/images/28th/project_page_pc.png b/public/assets/images/28th/project_page_pc.png new file mode 100644 index 0000000..f876046 Binary files /dev/null and b/public/assets/images/28th/project_page_pc.png differ diff --git a/public/assets/images/28th/project_page_tablet.png b/public/assets/images/28th/project_page_tablet.png new file mode 100644 index 0000000..f5fbd5a Binary files /dev/null and b/public/assets/images/28th/project_page_tablet.png differ diff --git a/public/assets/images/28th/recruit_bg.png b/public/assets/images/28th/recruit_bg.png new file mode 100644 index 0000000..1d4eb9f Binary files /dev/null and b/public/assets/images/28th/recruit_bg.png differ diff --git a/public/assets/images/28th/sponsor_1.png b/public/assets/images/28th/sponsor_1.png new file mode 100644 index 0000000..2e88fbd Binary files /dev/null and b/public/assets/images/28th/sponsor_1.png differ diff --git a/public/assets/images/28th/sponsor_2.png b/public/assets/images/28th/sponsor_2.png new file mode 100644 index 0000000..925ece5 Binary files /dev/null and b/public/assets/images/28th/sponsor_2.png differ diff --git a/public/assets/images/28th/sponsor_greeting.png b/public/assets/images/28th/sponsor_greeting.png new file mode 100644 index 0000000..a080daa Binary files /dev/null and b/public/assets/images/28th/sponsor_greeting.png differ diff --git a/public/assets/images/28th/title_mobile.png b/public/assets/images/28th/title_mobile.png new file mode 100644 index 0000000..c56e1ab Binary files /dev/null and b/public/assets/images/28th/title_mobile.png differ diff --git a/public/assets/images/28th/title_pc.png b/public/assets/images/28th/title_pc.png new file mode 100644 index 0000000..38c480c Binary files /dev/null and b/public/assets/images/28th/title_pc.png differ diff --git a/public/assets/images/28th/title_tablet.png b/public/assets/images/28th/title_tablet.png new file mode 100644 index 0000000..aebe61c Binary files /dev/null and b/public/assets/images/28th/title_tablet.png differ diff --git a/public/assets/images/28th/topbanner.png b/public/assets/images/28th/topbanner.png new file mode 100644 index 0000000..eaa0557 Binary files /dev/null and b/public/assets/images/28th/topbanner.png differ diff --git a/public/assets/sponsors/sponsor_dcamp.png b/public/assets/sponsors/sponsor_dcamp.png new file mode 100644 index 0000000..c9edf42 Binary files /dev/null and b/public/assets/sponsors/sponsor_dcamp.png differ diff --git a/styles/theme.ts b/styles/theme.ts index fd634b9..92a27c7 100644 --- a/styles/theme.ts +++ b/styles/theme.ts @@ -36,6 +36,16 @@ const palette = { circus_blue: '#837FF3', circus_gray: '#E8E8E8', + // 28th Branding Colors (Discovery Concept) + discovery_28th_red: '#FF8038', + discovery_28th_beige: '#FFEFD3', + discovery_28th_blue: '#48ADEC', + discovery_28th_text: '#54290F', + discovery_28th_text_80: 'rgba(84, 41, 15, 0.8)', + discovery_28th_text_50: 'rgba(84, 41, 15, 0.5)', + discovery_28th_title: '#66300F', + discovery_28th_button: '#974F08', + // Yellow yellow_100: '#FFEFBE', yellow_200: '#FFE69A',