Skip to content

Commit

Permalink
✨Feat - 세미나 페이지 모션 적용 #43
Browse files Browse the repository at this point in the history
  • Loading branch information
bianbbc87 committed May 4, 2024
1 parent ff7d6f2 commit fbe6d28
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 36 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
},
"dependencies": {
"clsx": "^2.1.0",
"framer-motion": "^11.1.7",
"next": "14.1.3",
"react": "^18",
"react-dom": "^18.2.0",
Expand Down
17 changes: 17 additions & 0 deletions src/components/seminar/header/SeminarHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import BannerImg from '@/svg/seminar/seminar_banner.svg';
import { motion } from 'framer-motion';
import Link from 'next/link';
import { OpenSeminar } from '@/interfaces/seminar/openSeminar';
import { OPEN_SEMINAR_DATA } from '@/constants/seminar/openSeminarData';

/**
* @description
Expand All @@ -12,12 +16,25 @@ import BannerImg from '@/svg/seminar/seminar_banner.svg';
* @returns The rendered header component.
*/
const SeminarHeader = () => {
// 현재 진행 세미나
const active_seminar_id = OPEN_SEMINAR_DATA.find(seminar => seminar.status)?.id;

return (
<>
<div className="w-full px-3 pt-10 H3 font-normal">Seminar</div>
<div className="px-3 pt-3 H6 font-medium">여러분과 함께 나누고싶은 이야기</div>
<p className="mt-6 border border-solid text-mono_700 h-0"/>
<motion.section
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.8 }}
transition={{ duration: 0.2 }}
>
<Link
href={`seminar/open/${active_seminar_id}`}
>
<BannerImg className='mt-10 scale-100' />
</Link>
</motion.section>
</>
);
};
Expand Down
23 changes: 14 additions & 9 deletions src/components/seminar/menubar/SeminarMenuBar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
'use client';

import { SEMINAR_CATEGORYS } from '@/constants/seminar/seminarCategory';
import React, { useState } from 'react';
import React from 'react';
import { motion } from 'framer-motion';
import { seminarCardVariants } from '@/constants/seminar/seminarCardVariants';

/**
* @description
Expand All @@ -26,15 +28,18 @@ const SeminarMenuBar = ({
return (
<div className="mt-10 px-3 flex gap-3 items-center">
{SEMINAR_CATEGORYS.map((category) => (
<button
key={category.value}
className={`text-[0.75rem] border py-2 px-3 border-solid rounded-lg ${
selectedCategory === category.value ? 'mono_white' : 'border-mono_500 text-mono_500'
}`}
onClick={() => handleCategoryChange(category.value)}
>
<motion.button
key={category.value}
className={`text-[0.75rem] border py-2 px-3 border-solid rounded-lg ${
selectedCategory === category.value ? 'mono_white' : 'border-mono_500 text-mono_500'
}`}
onClick={() => handleCategoryChange(category.value)}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.8 }}
transition={{ duration: 0.2}}
>
{category.label}
</button>
</motion.button>
))}
</div>
);
Expand Down
29 changes: 29 additions & 0 deletions src/components/seminar/thumbnail/SeminarPagination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { motion } from 'framer-motion';

interface PaginationProps {
pageNumbers: number[];
currentPage: number;
paginate: (pageNumber: number) => void;
}

const SeminarPagination: React.FC<PaginationProps> = ({ pageNumbers, currentPage, paginate }) => {
return (
<div className="pt-10 mt-5 desktop:flex tablet:hidden hidden justify-center gap-3">
{/* desktop에서만 보이기 */}
{pageNumbers.map(number => (
<motion.button
key={number}
onClick={() => paginate(number)}
className={`text-[0.75rem] font-medium w-5 h-5 justify-center items-center text-center border rounded ${currentPage === number ? 'text-mono_white border-mono_white' : 'text-mono_500 border-mono_500'}`}
whileHover={{ scale: 1.2 }}
whileTap={{ scale: 0.8 }}
transition={{ duration: 0.2 }}
>
{number}
</motion.button>
))}
</div>
);
};

export default SeminarPagination;
50 changes: 33 additions & 17 deletions src/components/seminar/thumbnail/SeminarThumbnailList.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
'use client';

import React, { useState } from 'react';
import { useRouter } from 'next/navigation';
import SeminarThumbnail from "./SeminarThumbnail";
import { SEMINAR_DATA } from '@/constants/seminar/seminarData';
import Link from 'next/link'
import { motion } from 'framer-motion';
import { seminarCardVariants } from '@/constants/seminar/seminarCardVariants';
import SeminarPagination from './SeminarPagination';

/**
* @description
Expand All @@ -20,8 +22,7 @@ import Link from 'next/link'
* @returns The rendered header component.
*/

const SeminarThumbnailList = ({ selectedCategory }: { selectedCategory: string }) => {
const router = useRouter();
const SeminarThumbnailList = ({ selectedCategory }: { selectedCategory: string }) => {
const [currentPage, setCurrentPage] = useState(1);
const itemsPerPage = 12; // 한 페이지당 표시할 항목 수

Expand Down Expand Up @@ -53,46 +54,61 @@ const SeminarThumbnailList = ({ selectedCategory }: { selectedCategory: string }
{/* desktop인 경우 */}
<div className="desktop:grid tablet:hidden hidden desktop:grid-cols-3 gap-x-8 gap-y-10">
{currentItems.map((seminar) => (
<motion.section
key={seminar.id}
whileHover={{ scale: 1.05, transition: { duration: 0.3 } }}
whileTap={{ scale: 0.8 }}
initial={{ y: 20, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}
transition={{ duration: 0.2 }}
viewport={{ once: true, amount: 0.9 }}
variants={seminarCardVariants}
style={{ transformOrigin: '10% 60%' }}
>
<Link
href={`/seminar/${seminar.id}`}
key={seminar.id}
>
<SeminarThumbnail
key={seminar.id}
data={seminar}
/>
</Link>
</motion.section>
))}
</div>

{/*tablet, mobile인 경우 */}
<div className="desktop:hidden grid tablet:grid-cols-2 grid-cols-1 gap-x-8 gap-y-10">
{SEMINAR_DATA.map((seminar) => (
<motion.section
key={seminar.id}
whileHover={{ scale: 1.05, transition: { duration: 0.3 } }}
whileTap={{ scale: 0.8 }}
initial={{ y: 20, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}
transition={{ duration: 0.5, delay: 0.5 }}
viewport={{ once: true, amount: 0.9 }}
variants={seminarCardVariants}
style={{ transformOrigin: '10% 60%' }}
>
<Link
href={`/seminar/${seminar.id}`}
key={seminar.id}
>
<SeminarThumbnail
key={seminar.id}
data={seminar}
/>
</Link>
</motion.section>
))}
</div>
{/* 페이지네이션 버튼 */}
<SeminarPagination
pageNumbers={pageNumbers}
currentPage={currentPage}
paginate={paginate}
/>

{/* desktop인 경우에만 보이기 */}
<div className="pt-10 mt-5 desktop:flex tablet:hidden hidden justify-center gap-3">
{pageNumbers.map(number => (
<button
key={number}
onClick={() => paginate(number)}
className={`text-[0.75rem] font-medium w-5 y-5 justify-center items-center text-center border rounded ${currentPage === number ? 'text-mono_white border-mono_white' : 'text-mono_500 border-mono_500'}`}
>
{number}
</button>
))}
</div>
</div>
);
};
Expand Down
27 changes: 19 additions & 8 deletions src/components/seminar/toggle/SeminarToggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import React, { useState } from 'react';
import SeminarToggleMenu from './SeminarToggleMenu';
import ChervonDownIcon from '@/svg/icons/common/chervon_down.svg';
import { OPEN_SEMINAR_DATA } from '@/constants/seminar/openSeminarData';
import { motion } from 'framer-motion';
import Link from 'next/link';
import { toggleVariants } from '@/constants/seminar/seminarToggleVariants';

/**
* @description
Expand All @@ -17,6 +19,7 @@ import Link from 'next/link';
* Renders the header component for the recruitment section.
* @returns The rendered header component.
*/

const SeminarToggle = () => {
const [isMenuVisible, setIsMenuVisible] = useState(false); // 오픈 세미나 목록 토클 버튼
const toggleMenuVisibility = () => {
Expand All @@ -26,18 +29,27 @@ const SeminarToggle = () => {
return (
<div className="flex-col">
<div className="mt-5 flex justify-end">
<button onClick={toggleMenuVisibility} className="flex B2 font-medium">
<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.8 }}
transition={{ duration: 0.2 }}
onClick={toggleMenuVisibility}
className="flex B2 font-medium"
>
목록 보기
<ChervonDownIcon className={`self-center ${isMenuVisible ? 'rotate-180' : ''}`} />
</button>
<ChervonDownIcon className={`self-center ${isMenuVisible ? 'rotate-180' : 'rotate-0'}`} />
</motion.button>
</div>
<div className={`overflow-hidden transition-max-height duration-500 ease-in-out ${!isMenuVisible && 'max-h-0'}`}>
{isMenuVisible && (
<motion.section
initial="closed"
animate={isMenuVisible ? "opened" : "closed"}
variants={toggleVariants}
className={isMenuVisible ? "" : "overflow-hidden"}
>
<div className="mt-5">
{OPEN_SEMINAR_DATA.map((seminar) => (
<Link
href={`/seminar/open/${seminar.id}`}
key={seminar.id}
>
<SeminarToggleMenu
key={seminar.id}
Expand All @@ -46,8 +58,7 @@ const SeminarToggle = () => {
</Link>
))}
</div>
)}
</div>
</motion.section>
</div>
);
};
Expand Down
13 changes: 11 additions & 2 deletions src/components/seminar/toggle/SeminarToggleMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { OpenSeminar } from "@/interfaces/seminar/openSeminar";
import { motion } from 'framer-motion';

/**
* @description
* 세미나 페이지 오픈 세미나 토클 메뉴
Expand All @@ -6,15 +9,20 @@
* @since 2024.04.18
*/

import { OpenSeminar } from "@/interfaces/seminar/openSeminar";

/**
* Renders the header component for the recruitment section.
* @returns The rendered header component.
*/

const SeminarToggleMenu = ({data}: {data:OpenSeminar}) => {
return (
<div>
<motion.section
key={data.id}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.8 }}
transition={{ duration: 0.2 }}
>
<div
className="p-3 flex justify-between items-center">
<div className="flex-col">
Expand All @@ -25,6 +33,7 @@ const SeminarToggleMenu = ({data}: {data:OpenSeminar}) => {
{data.status === false ? "종료" : "진행중"}
</p>
</div>
</motion.section>
<p className="mt-3 border border-solid text-mono_700 h-0"/>
</div>
);
Expand Down
16 changes: 16 additions & 0 deletions src/constants/seminar/seminarCardVariants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Variants } from 'framer-motion';

export const seminarCardVariants: Variants = {
offscreen: {
y: 300,
},
onscreen: {
y: 50,
rotate: -10,
transition: {
type: 'spring',
bounce: 0.4,
duration: 0.8,
},
},
};
32 changes: 32 additions & 0 deletions src/constants/seminar/seminarToggleVariants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export const toggleVariants = {
opened: {
maxHeight: '500px',
opacity: 1,
transition: {
maxHeight: {
duration: 0.5,
ease: 'easeInOut'
},
opacity: {
delay: 0.1,
duration: 0.4,
ease: 'easeInOut'
}
}
},
closed: {
maxHeight: 0,
opacity: 0,
transition: {
maxHeight: {
duration: 0.5,
ease: 'easeInOut'
},
opacity: {
delay: 0.1,
duration: 0.4,
ease: 'easeInOut'
}
}
}
};

0 comments on commit fbe6d28

Please sign in to comment.