diff --git a/next.config.mjs b/next.config.mjs index 0fcad50..1f85e95 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,6 +1,9 @@ /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, + + // notion image doamin + images: { domains: ['prod-files-secure.s3.us-west-2.amazonaws.com'], }, @@ -27,6 +30,7 @@ const nextConfig = { fileLoaderRule.exclude = /\.svg$/i; return config; }, + staticPageGenerationTimeout: 120, // 타임아웃 시간을 120초로 설정 }; export default nextConfig; diff --git a/package.json b/package.json index 450067c..687a30e 100644 --- a/package.json +++ b/package.json @@ -13,10 +13,14 @@ "clsx": "^2.1.0", "framer-motion": "^11.1.7", "next": "14.1.3", + "notion-client": "^6.16.0", + "notion-to-md": "^3.1.1", "react": "^18", "react-dom": "^18.2.0", "react-icons": "^5.0.1", - "swiper": "^11.1.1" + "react-markdown": "^9.0.1", + "swiper": "^11.1.1", + "unified": "^11.0.4" }, "devDependencies": { "@svgr/webpack": "^8.1.0", diff --git a/public/GDSC-logo.gif b/public/GDSC-logo.gif new file mode 100644 index 0000000..61b51fc Binary files /dev/null and b/public/GDSC-logo.gif differ diff --git a/public/GDSC-logo_out.gif b/public/GDSC-logo_out.gif new file mode 100644 index 0000000..883fd59 Binary files /dev/null and b/public/GDSC-logo_out.gif differ diff --git a/public/svg/seminar/seminar_thumbnail_card.png b/public/images/seminar/default_open_seminar.png similarity index 100% rename from public/svg/seminar/seminar_thumbnail_card.png rename to public/images/seminar/default_open_seminar.png diff --git a/public/images/seminar/default_seminar.png b/public/images/seminar/default_seminar.png new file mode 100644 index 0000000..0c8bb6f Binary files /dev/null and b/public/images/seminar/default_seminar.png differ diff --git a/public/svg/seminar/presenter_profile_img.png b/public/images/seminar/presenter/default_presenter.png similarity index 100% rename from public/svg/seminar/presenter_profile_img.png rename to public/images/seminar/presenter/default_presenter.png diff --git a/public/svg/seminar/translate_img.png b/public/images/seminar/translate_img.png similarity index 100% rename from public/svg/seminar/translate_img.png rename to public/images/seminar/translate_img.png diff --git a/src/app/api/member/route.tsx b/src/app/api/member/route.tsx index 6cf5556..5db7534 100644 --- a/src/app/api/member/route.tsx +++ b/src/app/api/member/route.tsx @@ -5,6 +5,7 @@ const notion = new Client({ auth: process.env.NOTION_SECRET_KEY, }); + async function queryAllMemberData(): Promise { try { const response = await notion.databases.query({ @@ -13,10 +14,12 @@ async function queryAllMemberData(): Promise { return response.results; } catch (error) { console.error(JSON.stringify(error)); + throw error; } } + export async function GET(req: NextRequest) { try { const data = await queryAllMemberData(); @@ -28,6 +31,7 @@ export async function GET(req: NextRequest) { }, }); } catch (error) { + return new Response( JSON.stringify({ message: `Failed: ${error?.toString()}` }), { @@ -39,3 +43,4 @@ export async function GET(req: NextRequest) { ); } } + diff --git a/src/app/api/seminar/all/route.tsx b/src/app/api/seminar/all/route.tsx new file mode 100644 index 0000000..7cdc3ee --- /dev/null +++ b/src/app/api/seminar/all/route.tsx @@ -0,0 +1,52 @@ +import { Client } from '@notionhq/client'; +import { NextRequest } from 'next/server'; + +const notion = new Client({ + auth: process.env.NOTION_SECRET_KEY, +}); + +// seminar 데이터 query select, 오름차순 +async function queryAllSeminarData(databaseId: string): Promise { + try { + const response = await notion.databases.query({ + database_id: databaseId, + sorts: [ + { + property: 'Date', + direction: 'ascending' + } + ] + }); + + return response.results; + } catch (error) { + console.error('Error querying Notion database and fetching member data:', JSON.stringify(error)); + throw error; + } +} + +type Data = { + items?: any[]; + message: string; +}; + +export async function GET(req: NextRequest) { + const databaseId = process.env.NOTION_SEMINAR_DATABASE_ID || ''; + + try { + const data = await queryAllSeminarData(databaseId); + return new Response(JSON.stringify({ data, message: 'Success' }), { + status: 200, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (error) { + return new Response(JSON.stringify({ message: `Failed: ${error?.toString()}` }), { + status: 500, + headers: { + 'Content-Type': 'application/json', + }, + }); + } +} \ No newline at end of file diff --git a/src/app/api/seminar/open/info/route.tsx b/src/app/api/seminar/open/info/route.tsx new file mode 100644 index 0000000..b537c3d --- /dev/null +++ b/src/app/api/seminar/open/info/route.tsx @@ -0,0 +1,48 @@ +import { Client } from '@notionhq/client'; +import { NotionToMarkdown } from "notion-to-md"; +import { NextRequest } from 'next/server'; + +const notion = new Client({ + auth: process.env.NOTION_SECRET_KEY, +}); + +const n2m = new NotionToMarkdown({ notionClient: notion }); + +async function getPageMarkdown(pageId: string): Promise { + const mdblocks = await n2m.pageToMarkdown(pageId); + const mdString = n2m.toMarkdownString(mdblocks); + return mdString; +} + + +// Next.js의 API 라우트 핸들러 +export async function GET(req: NextRequest) { + const url = new URL(req.url); + const pageId = url.searchParams.get('pageId'); + + if (!pageId) { + return new Response(JSON.stringify({ message: 'pageId is required' }), { + status: 400, + headers: { + 'Content-Type': 'application/json', + }, + }); + } + + try { + const pageContent = await getPageMarkdown(pageId); + return new Response(JSON.stringify({ data: pageContent, message: 'Success' }), { + status: 200, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (error) { + return new Response(JSON.stringify({ message: `Failed: ${error?.toString()}` }), { + status: 500, + headers: { + 'Content-Type': 'application/json', + }, + }); + } +} \ No newline at end of file diff --git a/src/app/api/seminar/open/route.tsx b/src/app/api/seminar/open/route.tsx new file mode 100644 index 0000000..ee213fe --- /dev/null +++ b/src/app/api/seminar/open/route.tsx @@ -0,0 +1,51 @@ +import { Client } from '@notionhq/client'; +import { NextRequest } from 'next/server'; + +const notion = new Client({ + auth: process.env.NOTION_SECRET_KEY, +}); + +async function queryOpenSeminarData(databaseId: string): Promise { + try { + const response = await notion.databases.query({ + database_id: databaseId, + sorts: [ + { + property: 'Date', + direction: 'ascending' + } + ] + }); + + return response.results; + } catch (error) { + console.error('Error querying Notion database and fetching seminar data:', JSON.stringify(error)); + throw error; + } +} + +type Data = { + items?: any[]; + message: string; + }; + + export async function GET(req: NextRequest) { + const databaseId = process.env.NOTION_OPEN_SEMINAR_DATABASE_ID || ''; + + try { + const data = await queryOpenSeminarData(databaseId); + return new Response(JSON.stringify({ data, message: 'Success' }), { + status: 200, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (error) { + return new Response(JSON.stringify({ message: `Failed: ${error?.toString()}` }), { + status: 500, + headers: { + 'Content-Type': 'application/json', + }, + }); + } + } \ No newline at end of file diff --git a/src/app/api/seminar/review/route.tsx b/src/app/api/seminar/review/route.tsx new file mode 100644 index 0000000..aa24851 --- /dev/null +++ b/src/app/api/seminar/review/route.tsx @@ -0,0 +1,59 @@ +import { Client } from '@notionhq/client'; +import { NextRequest } from 'next/server'; + +const notion = new Client({ + auth: process.env.NOTION_SECRET_KEY, +}); + +// seminar id와 연결된 리뷰 불러오기 +async function queryReviewData(databaseId: string, seminarId: string): Promise { + try { + const response = await notion.databases.query({ + database_id: databaseId, + filter: { + property: 'Seminar', + relation: { + contains: seminarId + } + } + }); + + return response.results; + } catch (error) { + console.error('Error querying Notion database by Seminar ID:', error); + throw error; + } +} + +export async function GET(req: NextRequest) { + const url = new URL(req.url); + const seminarId = url.searchParams.get('seminarId'); // 쿼리 파라미터에서 세미나 ID 가져오기 + + if (!seminarId) { + return new Response(JSON.stringify({ message: 'Seminar ID is required' }), { + status: 400, + headers: { + 'Content-Type': 'application/json', + }, + }); + } + + const databaseId = process.env.NOTION_REVIEW_DATABASE_ID || ''; // 리뷰 데이터베이스 ID + + try { + const reviews = await queryReviewData(databaseId, seminarId); + return new Response(JSON.stringify({ reviews, message: 'Success' }), { + status: 200, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (error) { + return new Response(JSON.stringify({ message: `Failed: ${error?.toString()}` }), { + status: 500, + headers: { + 'Content-Type': 'application/json', + }, + }); + } +} \ No newline at end of file diff --git a/src/app/api/seminar/route.tsx b/src/app/api/seminar/route.tsx new file mode 100644 index 0000000..e1b3b90 --- /dev/null +++ b/src/app/api/seminar/route.tsx @@ -0,0 +1,70 @@ +import { Client } from '@notionhq/client'; +import { NextRequest } from 'next/server'; + +const notion = new Client({ + auth: process.env.NOTION_SECRET_KEY, +}); + +// seminar 데이터 query select, 오름차순 +async function querySeminarData(databaseId: string, tag: string): Promise { + try { + const response = await notion.databases.query({ + database_id: databaseId, + filter: { + property: 'Tags', + multi_select: { + contains: tag + } + }, + sorts: [ + { + property: 'Date', + direction: 'ascending' + } + ] + }); + + return response.results; + } catch (error) { + console.error('Error querying Notion database and fetching member data:', JSON.stringify(error)); + throw error; + } +} + +type Data = { + items?: any[]; + message: string; +}; + +export async function GET(req: NextRequest) { + const url = new URL(req.url); + const tag = url.searchParams.get('Tag'); // 쿼리 파라미터에서 세미나 ID 가져오기 + + if (!tag) { + return new Response(JSON.stringify({ message: 'Tag is required' }), { + status: 400, + headers: { + 'Content-Type': 'application/json', + }, + }); + } + + const databaseId = process.env.NOTION_SEMINAR_DATABASE_ID || ''; + + try { + const data = await querySeminarData(databaseId, tag); + return new Response(JSON.stringify({ data, message: 'Success' }), { + status: 200, + headers: { + 'Content-Type': 'application/json', + }, + }); + } catch (error) { + return new Response(JSON.stringify({ message: `Failed: ${error?.toString()}` }), { + status: 500, + headers: { + 'Content-Type': 'application/json', + }, + }); + } +} \ No newline at end of file diff --git a/src/app/seminar/[id]/page.tsx b/src/app/seminar/[id]/page.tsx index 2dfea36..8ef239b 100644 --- a/src/app/seminar/[id]/page.tsx +++ b/src/app/seminar/[id]/page.tsx @@ -1,46 +1,59 @@ -'use client'; - -import React from 'react'; -import { usePathname } from 'next/navigation'; import SeminarDetailHeader from '@/components/seminar/seminarDetail/header/SeminarDetailHeader'; import SeminarDetailBanner from '@/components/seminar/seminarDetail/banner/SeminarDetailBanner'; -import { SEMINAR_DATA } from '@/constants/seminar/seminarData'; import SeminarDetailPdf from '@/components/seminar/seminarDetail/pdf/SeminarDetailPdf'; import NotFoundPage from '@/app/not-found'; import SeminarDetailReview from '@/components/seminar/seminarDetail/review/SeminarDetailReview'; -import { changePathtoNumber } from '@/hooks/seminar/changePathtoNumber'; - -const SeminarDetailPage = () => { - const pathname = usePathname(); - // 숫자 추출 - var id = changePathtoNumber(pathname); - - // 객체 찾기 - const seminar = SEMINAR_DATA.find(seminar => Number(seminar.id) === id); - - if (!id || !seminar) { - // 세미나를 찾지 못한 경우 - return ; - } - +import { refactorSeminarData, refactorSeminarMemberData, refactorSeminarReviewData } from '@/hooks/seminar/notionDataRefactor'; +import { headers } from "next/headers"; +import { changePathtoSeperate } from '@/hooks/seminar/changePathtoNumber'; +import { SEMINAR_MEMBER_DATA } from '@/constants/seminar/seminarMemberData'; + +export const dynamic = "force-dynamic"; + +const SeminarDetailPage = async () => { + // server comp에서 path 가져오기 + const header = headers(); + const pathname = header.get('next-url') + + const seminarId = changePathtoSeperate(pathname ?? '', 'seminar'); + + // all seminar data 정의 + const seminarResponse = await fetch(`${process.env.SERVER_HOST}/api/seminar/all`); + const seminarList = await seminarResponse.json(); + const seminars = refactorSeminarData(seminarList.data ?? []); + // 세미나 디테일 데이터로 분리 + let seminar = seminars.find(seminar => `${seminar.id}` === `${seminarId}`); + + if(!seminar) { + return ; + } + + // reviews 데이터 정의 + const seminarReviewResponse = await fetch(`${process.env.SERVER_HOST}/api/seminar/review?seminarId=${seminarId}`); + const seminarReviewList = await seminarReviewResponse.json(); + const reviews = refactorSeminarReviewData(seminarReviewList.reviews ?? []); + + // member 데이터 정의 + const memberResponse = await fetch(`${process.env.SERVER_HOST}/api/member?seminarId=${seminarId}`); + const memberList = await memberResponse.json(); + const member = refactorSeminarMemberData(memberList.data[0] ?? SEMINAR_MEMBER_DATA, seminar.id); return
-
+
- {/* header */} - - - {/* banner */} - + {/* header */} + - {/* pdf file */} - +{/* banner */} + - {/* review */} - +{/* pdf file */} + +{/* review */} +
-
+
; }; diff --git a/src/app/seminar/open/[id]/page.tsx b/src/app/seminar/open/[id]/page.tsx index aed1ba1..6474fee 100644 --- a/src/app/seminar/open/[id]/page.tsx +++ b/src/app/seminar/open/[id]/page.tsx @@ -1,41 +1,72 @@ -'use client'; - -import React from 'react'; -import { usePathname } from 'next/navigation'; import OpenSeminarDetailHeader from '@/components/seminar/openSeminarDetail/header/OpenSeminarDetailHeader'; import OpenSeminarDetailBanner from '@/components/seminar/openSeminarDetail/banner/OpenSeminarDetailBanner'; import OpenSeminarDetailSeminars from '@/components/seminar/openSeminarDetail/kindOfSeminar/OpenSeminarDetailSeminars'; import OpenSeminarDetailInformation from '@/components/seminar/openSeminarDetail/information/OpenSeminarDetailInformation'; -import { OPEN_SEMINAR_DATA } from '@/constants/seminar/openSeminarData'; +import { OPEN_SEMINAR_DATA, OPEN_SEMINAR_DETAIL_SEMINAR_DATA } from '@/constants/seminar/openSeminarData'; import NotFoundPage from '@/app/not-found'; -import { changeOpenPathtoNumber } from '@/hooks/seminar/changePathtoNumber'; +import { headers } from "next/headers"; +import { findSeminarsByIds, refactorOpenSeminarData, refactorOpenSeminarDetailSeminarsData, refactorSeminarData, refactorSeminarMemberData } from '@/hooks/seminar/notionDataRefactor'; +import { changePathtoSeperate } from '@/hooks/seminar/changePathtoNumber'; +import { SEMINAR_MEMBER_DATA } from '@/constants/seminar/seminarMemberData'; + +export const dynamic = "force-dynamic"; -const OpenSeminarDetailPage = () => { - const pathname = usePathname(); - // 숫자 추출 - var id = changeOpenPathtoNumber(pathname); +const OpenSeminarDetailPage = async () => { + // server comp에서 path 가져오기 + const header = headers(); + const pathname = header.get('next-url') + const openSeminarId = changePathtoSeperate(pathname ?? '', 'seminar/open'); - // 객체 찾기 - const seminar = OPEN_SEMINAR_DATA.find(seminar => Number(seminar.id) === id); + // seminar 데이터 가져오기 + const openSeminarResponse = await fetch(`${process.env.SERVER_HOST}/api/seminar/open`); + const openSeminarList = await openSeminarResponse.json(); + const openSeminars = refactorOpenSeminarData(openSeminarList.data || {}); + // 오픈 세미나 디테일 데이터로 분리 + const openSeminar = openSeminars.find(seminar => `${seminar.id}` === `${openSeminarId}`) || OPEN_SEMINAR_DATA[0]; - if (!seminar) { - // 세미나를 찾지 못한 경우 + // 오픈 세미나 데이터 + if (!openSeminar) { return ; } + // seminar 데이터 가져오기 + const tag = '🌲 Open Seminar' + const seminarResponse = await fetch(`${process.env.SERVER_HOST}/api/seminar?Tag=${tag}`); + const seminarList = await seminarResponse.json(); + const seminars = refactorSeminarData(seminarList.data || []); + const detailSeminarInfo = findSeminarsByIds(seminars, openSeminar.seminars); + + + // 각 세미나에 대한 멤버 데이터를 비동기로 불러오기 + const results = await Promise.all( + detailSeminarInfo.map(async seminar => { + const memberResponse = await fetch(`${process.env.SERVER_HOST}/api/member?seminarId=${seminar.id}`); + const memberList = await memberResponse.json(); + const member = refactorSeminarMemberData(memberList.data[0] ?? SEMINAR_MEMBER_DATA, seminar.id); + return refactorOpenSeminarDetailSeminarsData(seminar, member) ?? OPEN_SEMINAR_DETAIL_SEMINAR_DATA[0]; + }) + ); + + const markDownResponse = await fetch(`${process.env.SERVER_HOST}/api/seminar/open/info?pageId=${openSeminar.id}`); + const markdown = await markDownResponse.json(); + // console.log('real ::: ', markdown); + return
-
+
- {/* header */} - + + {/* header */} + {/* banner */} - + {/* seminars */} - + {/* information */} - + + +
-
+
; }; diff --git a/src/app/seminar/page.tsx b/src/app/seminar/page.tsx index c83cf82..cfd920b 100644 --- a/src/app/seminar/page.tsx +++ b/src/app/seminar/page.tsx @@ -1,29 +1,43 @@ -'use client'; - import SeminarHeader from '@/components/seminar/header/SeminarHeader'; -import SeminarMenuBar from '@/components/seminar/menubar/SeminarMenuBar'; import SeminarThumbnailList from '@/components/seminar/thumbnail/SeminarThumbnailList'; import SeminarToggle from '@/components/seminar/toggle/SeminarToggle'; -import React, { useState } from 'react'; +import { refactorOpenSeminarData, refactorSeminarData } from '@/hooks/seminar/notionDataRefactor'; +import NotFoundPage from '../not-found'; + + +export const dynamic = "force-dynamic"; + +const SeminarPage = async () => { + // seminar 데이터 가져오기 + const tag = '🏕️ Camping Seminar' + const seminarResponse = await fetch(`${process.env.SERVER_HOST}/api/seminar?Tag=${tag}`); + const seminarList = await seminarResponse.json(); + const seminars = refactorSeminarData(seminarList.data || []); -const SeminarPage = () => { - const [selectedCategory, setSelectedCategory] = useState('all'); + // open seminar 데이터 가져오기 + const openSeminarResponse = await fetch(`${process.env.SERVER_HOST}/api/seminar/open`); + const openSeminar = await openSeminarResponse.json(); + const openSeminars = refactorOpenSeminarData(openSeminar.data || {}); + // 세미나 데이터 + if (!seminars) { + return ; + } + return
-
+
-{/* header */} - -{/* toggle */} - + {/* header */} + -{/* select button */} - +{/* toggle */} + {/* seminar list */} - -
+ + +
; diff --git a/src/components/home/aboutGDSC/AboutGDSC.tsx b/src/components/home/aboutGDSC/AboutGDSC.tsx index 72abbf5..04c00c2 100644 --- a/src/components/home/aboutGDSC/AboutGDSC.tsx +++ b/src/components/home/aboutGDSC/AboutGDSC.tsx @@ -1,3 +1,7 @@ +'use client'; +import { motion } from 'framer-motion'; +import { aniSlideRight, aniSlideUp } from '../animation/animaiton'; + const NumberAbout: React.FC<{ label: string; number: string }> = ({ label, number, @@ -16,13 +20,25 @@ const AboutGDSC = () => {
{/* 텍스트 */}
-

+ Google Developer
Student Clubs -

+ -

+ 개발과 Google 기술에 관심있는 대학생 커뮤니티 그룹입니다.
Google Developers 에서 제공하는 프로그램으로 @@ -31,26 +47,44 @@ const AboutGDSC = () => {
공동체와 지역사회를 위한 솔루션 구축을 목표로 합니다.
-

+ -
+ GDSC 소개 바로가기
-
+ -
+ -
+
{/* 이미지 */} -
+
-
+
); diff --git a/src/components/home/aboutGDSCDGU/AboutGDSCDGU.tsx b/src/components/home/aboutGDSCDGU/AboutGDSCDGU.tsx index c3321b0..0320701 100644 --- a/src/components/home/aboutGDSCDGU/AboutGDSCDGU.tsx +++ b/src/components/home/aboutGDSCDGU/AboutGDSCDGU.tsx @@ -1,3 +1,7 @@ +'use client'; +import { motion } from 'framer-motion'; +import { aniSlideRight, aniSlideUp } from '../animation/animaiton'; + const MemberGuideLine: React.FC<{ label: string; description: string }> = ({ label, description, @@ -16,13 +20,19 @@ const PartCard: React.FC<{ description: string; }> = ({ icon, part, description }) => { return ( -
+
{part}

{description}

-
+ ); }; @@ -33,7 +43,14 @@ const AboutGDSCDGU = () => {
{/* title */}
-
+ {/*GDSC IN DOUGGUK UNIV*/} + GDSC in
@@ -42,18 +59,30 @@ const AboutGDSCDGU = () => { Dongguk University -
+ -
+ GDSC DGU는 자발적이고 주도적으로 학습하는 커뮤니티 그룹입니다.
저희는 이론과 산업 간의 격차를 줄이는 연구를 하기 위해 모였습니다. -
+
{/* title */} {/* member */} -
+

Members

{ label="DevRel" description="질 높은 컨텐츠를 제공하기 위해 돕습니다." /> -
+ {/* member */}
{/* title */} - -

모든 길은 로마로 흐른다

-

+ + + 모든 길은 로마로 흐른다 + + 어떤 목표에 도달하는데는 많은 경로가 있습니다.
이와 같이, 하나의 파트에 국한 되지 않고 세가지 분야로 이루어져
서로의 지식과 경험을 공유하며 함께 성장해나가고자 합니다. -

+
{/* title */} {/* part */} -
+
= ({ img, link }) => { + return ( + + + + ); +}; const ActivityCard: React.FC = ({ icon, title, description }) => { return ( -
+
{title}
@@ -18,16 +42,27 @@ const ActivityCard: React.FC = ({ icon, title, description }) => {

{item}

))}
-
+ ); }; +interface Seminar { + img: string; + link: string; +} + interface Activity { icon: string; title: string; description: string[]; } +const SeminarList: Seminar[] = [ + { img: '111', link: '@22' }, + { img: '111', link: '##' }, + { img: '111', link: '##' }, +]; + const ActivityList: Activity[] = [ { icon: '1stGDSC', @@ -89,32 +124,33 @@ const Activity = () => { {/* 제목 */} {/* 내용 */} -
+
{/* 풀페이지에서 overflow를 어떻게 보여줘야할지 모르겠네... */} {/*
*/} -
- - - +
+ {SeminarList.map((item, index) => { + return ; + })}
{/* 스크롤되는 부분 */} - +
+
- {[1, 2, 3].map((item, index) => { + {SeminarList.map((item, index) => { return ( - + ); })}
+ {/* 내용 */} {/* 세미나 */} diff --git a/src/components/home/animation/animaiton.tsx b/src/components/home/animation/animaiton.tsx new file mode 100644 index 0000000..d296511 --- /dev/null +++ b/src/components/home/animation/animaiton.tsx @@ -0,0 +1,26 @@ +export const aniSlideUp = { + hidden: { y: 20, opacity: 0 }, + visible: { + y: 0, + opacity: 1, + transition: { duration: 0.5 }, + }, +}; + +export const aniFadein = { + hidden: { opacity: 0 }, + visible: { + y: 0, + opacity: 1, + transition: { duration: 2 }, + }, +}; + +export const aniSlideRight = { + hidden: { x: -20, opacity: 0 }, + visible: { + x: 0, + opacity: 1, + transition: { duration: 0.5 }, + }, +}; diff --git a/src/components/home/banner/HomeBanner.tsx b/src/components/home/banner/HomeBanner.tsx index ccf2be4..8efd03f 100644 --- a/src/components/home/banner/HomeBanner.tsx +++ b/src/components/home/banner/HomeBanner.tsx @@ -1,18 +1,44 @@ +'use client'; +import { motion } from 'framer-motion'; +import { aniFadein, aniSlideUp } from '../animation/animaiton'; const HomeBanner = () => { return ( -
-
-

+

+
+ +
+ +
+ 같이 해서 가치를 만들고,
세상에 스며든다. -

+
-

+ GDSD DGU는 교내 개발자들과 지식 공유를 통해
긍정적 영향을 끼치는 커뮤니티로 성장하고자 합니다. -

+
); diff --git a/src/components/home/moreAbout/MoreAbout.tsx b/src/components/home/moreAbout/MoreAbout.tsx index 82f0c93..eb791d1 100644 --- a/src/components/home/moreAbout/MoreAbout.tsx +++ b/src/components/home/moreAbout/MoreAbout.tsx @@ -1,11 +1,21 @@ +'use client'; +import { aniSlideRight, aniSlideUp } from '../animation/animaiton'; import HomeTitle from '../title/HomeTitle'; +import { motion } from 'framer-motion'; const ChannelCard: React.FC = ({ title, description }) => { return ( -
+

{title}

{description}

-
+ ); }; @@ -48,7 +58,7 @@ const MoreAbout = () => { '이것도 세줄이상이면 좋겠습니다!', ]} /> -
+
{ChannelList.map((item, index) => ( = ({ label, img }) => { return ( -
- + +
{label}
-
+ ); }; @@ -33,16 +42,31 @@ const StoriesFrom = () => {
{/* title */}
-

+ Stories
from the community -

-

다양한 활동을 통해 함께 성장하는 우리의 이야기

+ + + 다양한 활동을 통해 함께 성장하는 우리의 이야기 +
{/* title */} {/* content */} + {/* 데스크탑, 테블릿 */}
@@ -55,22 +79,29 @@ const StoriesFrom = () => {
- - - {StoryList.map((item, index) => { - return ( - - - - ); - })} - + + {StoryList.map((item, index) => { + return ( + + + + ); + })} + + {/* content */}
diff --git a/src/components/home/title/HomeTitle.tsx b/src/components/home/title/HomeTitle.tsx index 86ea918..11a10ef 100644 --- a/src/components/home/title/HomeTitle.tsx +++ b/src/components/home/title/HomeTitle.tsx @@ -1,5 +1,8 @@ // 제목 // 설명까지 +'use client'; +import { motion } from 'framer-motion'; +import { aniSlideUp } from '../animation/animaiton'; const HomeTitle: React.FC<{ title: string[]; @@ -7,16 +10,30 @@ const HomeTitle: React.FC<{ }> = ({ title, description }) => { return (
-
+ {title.map((item, index) => (

{item}

))} -
-
+ + {description.map((item, index) => (

{item}

))} -
+
); }; diff --git a/src/components/layout/footer/Footer.tsx b/src/components/layout/footer/Footer.tsx index c6f9fe6..2bd604c 100644 --- a/src/components/layout/footer/Footer.tsx +++ b/src/components/layout/footer/Footer.tsx @@ -1,6 +1,5 @@ -'use client'; import React from 'react'; -import RightArrowIcon from 'public/svg/icons/common/right_arrow.svg'; +import CreatorLinkButton from "@/components/timeline/button/CreatorLinkButton"; /** * @description @@ -9,37 +8,29 @@ import RightArrowIcon from 'public/svg/icons/common/right_arrow.svg'; * @returns {JSX.Element} Footer * @since 2024.04.26 */ - const Footer = () => { - const handlePress = () => { - console.log('Arrow clicked'); - }; - return ( -