Skip to content

Commit

Permalink
[feat] 메인 페이지 프로젝트 section 구현 (#404)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jungjjeong authored Nov 25, 2024
2 parents 345b387 + 78a6027 commit e82da2a
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 17 deletions.
14 changes: 9 additions & 5 deletions src/components/ProjectTab/ProjectTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ export function ProjectTab({ currentTab, setCurrentTab }: ProjectTabProps) {

const tabWrapperCss = css`
display: flex;
${mediaQuery('mobile')} {
width: 100%;
overflow-x: scroll;
&::-webkit-scrollbar {
display: none;
}
}
`;

const tabContainerCss = css`
Expand All @@ -44,11 +53,6 @@ const tabCss = css`
${theme.typosV2.pretendard.semibold16};
padding: 16px 20px;
color: ${theme.colors.grey[300]};
${mediaQuery('mobile')} {
${theme.typosV2.pretendard.regular14};
padding: 16px 8px;
}
`;

const activeTabCss = css`
Expand Down
4 changes: 2 additions & 2 deletions src/components/Thumbnail/Thumbnail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export function Thumbnail({ title, subTitle, img, description, links }: Thumbnai

const articleCss = css`
position: relative;
height: 208px;
height: 220px;
max-width: 312px;
overflow: hidden;
border-radius: 12px;
Expand All @@ -80,7 +80,7 @@ const articleCss = css`
cursor: pointer;
}
&:hover img {
filter: blur(5px) brightness(0.4);
filter: brightness(0.3);
}
`;

Expand Down
205 changes: 201 additions & 4 deletions src/features/Main/sections/MainProjectSection.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,203 @@
/**
* * Main 페이지 프로젝트 section
*/
import { useState } from 'react';
import { useRouter } from 'next/router';
import { css } from '@emotion/react';
import { AnimatePresence, m } from 'framer-motion';

import { Icon } from '~/components/Icon/Icon';
import { Thumbnail } from '~/components/Thumbnail';
import { Link } from '~/components/Thumbnail/Thumbnail';
import { staggerHalf } from '~/constant/motion';
import { PROJECT_LIST } from '~/constant/project';
import { useCheckWindowSize } from '~/hooks/useCheckWindowSize';
import { mediaQuery } from '~/styles/media';
import { theme } from '~/styles/theme';
import { sliceByPage } from '~/utils/pagination';

const FIRST_PAGE = 1;

export const MainProjectSection = () => {
return <section>Project</section>;
const router = useRouter();
const [currentPage, setCurrentPage] = useState(FIRST_PAGE);
const { isTargetSize: isTabletSize } = useCheckWindowSize('tablet');
const { isTargetSize: isMobileSize } = useCheckWindowSize('mobile');

const isMaxCurrentPage = currentPage >= 3;

const onClickMore = () => {
if (isMaxCurrentPage) {
router.push('/project');
return;
}

setCurrentPage(prev => prev + 1);
};

return (
<section css={sectionCss(isMaxCurrentPage)}>
<div css={text.wrapperCss}>
<h1 css={text.headlineCss}>프로젝트</h1>
<p css={text.descriptionCss}>
디프만 멤버 &apos;디퍼(DEEPER)&apos; 들의
{isMobileSize && <br />}
다양한 프로젝트를 확인해보세요
</p>
</div>

<AnimatePresence mode="wait" initial={false}>
<m.div
css={projectContainerCss}
initial="initial"
animate="animate"
exit="exit"
variants={staggerHalf}
>
{sliceByPage(PROJECT_LIST, currentPage, isTabletSize, isMobileSize, 0).map(project => (
<Thumbnail
key={project.title}
img={`/images/project/${project.subTitle}/${project.title}.png`}
title={project.title}
subTitle={project.subTitle}
description={project.description}
links={project.links as Link[]}
/>
))}
</m.div>
</AnimatePresence>

<button css={button.containerCss(isMaxCurrentPage)} onClick={onClickMore}>
<div css={button.wrapperCss}>
{isMaxCurrentPage ? '프로젝트 보기' : '더보기'}
<span css={button.iconCss}>
<Icon icon="ic_arrow_black" size={24} direction={isMaxCurrentPage ? 'right' : 'down'} />
</span>
</div>
</button>
</section>
);
};

const sectionCss = (isMaxCurrentPage?: boolean) => css`
position: relative;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
background-color: black;
padding: 140px 0;
gap: 68px;
${mediaQuery('tablet')} {
padding: 140px 64px;
}
${mediaQuery('mobile')} {
padding: 80px 24px 100px;
}
${!isMaxCurrentPage &&
css`
&::after {
content: '';
position: absolute;
bottom: 140px;
height: 220px;
width: 100%;
background: linear-gradient(
180deg,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 0.4) 14%,
rgba(0, 0, 0, 0.71) 30.75%,
rgba(0, 0, 0, 0.88) 41%,
#000 50%,
#000 100%
);
${mediaQuery('mobile')} {
bottom: 100px;
}
}
`}
`;

const text = {
wrapperCss: css`
display: flex;
flex-direction: column;
gap: 24px;
color: white;
text-align: center;
`,

headlineCss: css`
${theme.typosV2.pretendard.bold44};
line-height: 150%;
${mediaQuery('mobile')} {
${theme.typosV2.pretendard.bold28};
line-height: 150%;
}
`,

descriptionCss: css`
${theme.typosV2.pretendard.semibold20};
line-height: 150%;
${mediaQuery('mobile')} {
${theme.typosV2.pretendard.semibold18};
line-height: 150%;
}
`,
};

const projectContainerCss = css`
width: 100%;
max-width: 960px;
margin-top: 36px;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 12px;
${mediaQuery('tablet')} {
grid-template-columns: repeat(2, 1fr);
}
${mediaQuery('mobile')} {
grid-template-columns: repeat(1, 1fr);
}
`;

const button = {
containerCss: (isMaxCurrentPage?: boolean) => css`
${!isMaxCurrentPage &&
css`
position: absolute;
bottom: 156px;
`}
padding: 12px 36px;
border-radius: 100px;
background-color: white;
z-index: 10;
`,

wrapperCss: css`
display: flex;
gap: 8px;
align-items: center;
color: black;
${theme.typosV2.pretendard.semibold20};
line-height: 150%;
${mediaQuery('mobile')} {
${theme.typosV2.pretendard.semibold16};
line-height: 150%;
}
`,

iconCss: css`
width: 24px;
height: 24px;
background-color: white;
border-radius: 400px;
`,
};
1 change: 1 addition & 0 deletions src/features/Main/sections/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export * from './MainReasonSection';
export * from './MainRecruitSection';
export * from './MainResultSection';
export * from './MainScheduleSection';
export * from './MainSubscribeSection';
export * from './MainSupportSection';
14 changes: 11 additions & 3 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import dynamic from 'next/dynamic';

import { SEO } from '~/components/SEO';
import {
MainBlogSection,
MainIntroSection,
MainProjectSection,
MainReasonSection,
MainRecruitSection,
MainResultSection,
MainScheduleSection,
MainSubscribeSection,
MainSupportSection,
} from '~/features/Main/sections';
import { MainSubscribeSection } from '~/features/Main/sections/MainSubscribeSection';

const DynamicMainProjectSection = dynamic(
() => import('~/features/Main/sections').then(({ MainProjectSection }) => MainProjectSection),
{
ssr: false,
}
);

export default function Root() {
return (
Expand All @@ -20,7 +28,7 @@ export default function Root() {
<MainResultSection />
<MainReasonSection />
<MainScheduleSection />
<MainProjectSection />
<DynamicMainProjectSection />
<MainSupportSection />
<MainRecruitSection />
<MainBlogSection />
Expand Down
9 changes: 6 additions & 3 deletions src/utils/pagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@ export const sliceByPage = (
projects: Project[],
page: number,
isTabletSize: boolean,
isMobileSize: boolean
isMobileSize: boolean,
startPage?: number
) => {
const initialPage = startPage !== undefined ? startPage : page - 1;

if (isMobileSize) {
return projects.slice(0, MOBILE_PAGE_SIZE * page);
}
if (isTabletSize) {
return projects.slice(TABLET_PAGE_SIZE * (page - 1), TABLET_PAGE_SIZE * page);
return projects.slice(TABLET_PAGE_SIZE * initialPage, TABLET_PAGE_SIZE * page);
}

return projects.slice(PC_PAGE_SIZE * (page - 1), PC_PAGE_SIZE * page);
return projects.slice(PC_PAGE_SIZE * initialPage, PC_PAGE_SIZE * page);
};

export const getTenUnderProjects = (projects: Project[]) =>
Expand Down

0 comments on commit e82da2a

Please sign in to comment.