diff --git a/next.config.mjs b/next.config.mjs
index 714926b5..707c5664 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -26,14 +26,23 @@ const nextConfig = {
},
];
},
-
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack'],
});
+
+ // 추가된 부분
+ config.resolve.fallback = {
+ fs: false,
+ net: false,
+ tls: false,
+ };
+
return config;
},
+ reactStrictMode: false, // 추가
+ transpilePackages: ['@fullpage/react-fullpage'], // 추가
};
export default nextConfig;
diff --git a/package-lock.json b/package-lock.json
index c51b8b3b..f8915f38 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,7 @@
"name": "my-project",
"version": "0.1.0",
"dependencies": {
+ "@fullpage/react-fullpage": "^0.1.48",
"@radix-ui/react-dropdown-menu": "^2.1.6",
"@radix-ui/react-progress": "^1.1.2",
"@radix-ui/react-slot": "^1.1.2",
@@ -18,6 +19,7 @@
"axios": "^1.7.9",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
+ "framer-motion": "^12.5.0",
"lucide-react": "^0.475.0",
"next": "14.1.0",
"react": "^18.2.0",
@@ -1568,6 +1570,21 @@
"@babel/core": "^7.0.0"
}
},
+ "node_modules/@babel/polyfill": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.12.1.tgz",
+ "integrity": "sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g==",
+ "deprecated": "🚨 This package has been deprecated in favor of separate inclusion of a polyfill and regenerator-runtime (when needed). See the @babel/polyfill docs (https://babeljs.io/docs/en/babel-polyfill) for more information.",
+ "dependencies": {
+ "core-js": "^2.6.5",
+ "regenerator-runtime": "^0.13.4"
+ }
+ },
+ "node_modules/@babel/polyfill/node_modules/regenerator-runtime": {
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
+ },
"node_modules/@babel/preset-env": {
"version": "7.26.9",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.9.tgz",
@@ -1882,6 +1899,15 @@
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz",
"integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg=="
},
+ "node_modules/@fullpage/react-fullpage": {
+ "version": "0.1.48",
+ "resolved": "https://registry.npmjs.org/@fullpage/react-fullpage/-/react-fullpage-0.1.48.tgz",
+ "integrity": "sha512-QeIfQJyMW/35Ckj7FksOJHxypvarzTgrdM8UAas5kTf6W+8WEybt0CYPfsy1jEStl8SoRPrmYjGWwxBeja7pxA==",
+ "dependencies": {
+ "@babel/polyfill": "^7.2.5",
+ "fullpage.js": "^4.0.33"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
@@ -5360,6 +5386,13 @@
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
},
+ "node_modules/core-js": {
+ "version": "2.6.12",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
+ "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
+ "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
+ "hasInstallScript": true
+ },
"node_modules/core-js-compat": {
"version": "3.41.0",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz",
@@ -7104,6 +7137,32 @@
"url": "https://github.com/sponsors/rawify"
}
},
+ "node_modules/framer-motion": {
+ "version": "12.5.0",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.5.0.tgz",
+ "integrity": "sha512-buPlioFbH9/W7rDzYh1C09AuZHAk2D1xTA1BlounJ2Rb9aRg84OXexP0GLd+R83v0khURdMX7b5MKnGTaSg5iA==",
+ "dependencies": {
+ "motion-dom": "^12.5.0",
+ "motion-utils": "^12.5.0",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "@emotion/is-prop-valid": "*",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/is-prop-valid": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -7123,6 +7182,17 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
+ "node_modules/fullpage.js": {
+ "version": "4.0.34",
+ "resolved": "https://registry.npmjs.org/fullpage.js/-/fullpage.js-4.0.34.tgz",
+ "integrity": "sha512-jLZrqhK9PDRdpN82UwbNLYaINjZTGbBahV6FASP4b1yXaS8U3G+ty2nZ+XIIfjN08Ej0UgvSfPnmWDR7CWxwNw==",
+ "funding": [
+ {
+ "type": "GitHub Sponsors",
+ "url": "https://github.com/sponsors/alvarotrigo"
+ }
+ ]
+ },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -9978,6 +10048,19 @@
"node": ">=16 || 14 >=14.17"
}
},
+ "node_modules/motion-dom": {
+ "version": "12.5.0",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.5.0.tgz",
+ "integrity": "sha512-uH2PETDh7m+Hjd1UQQ56yHqwn83SAwNjimNPE/kC+Kds0t4Yh7+29rfo5wezVFpPOv57U4IuWved5d1x0kNhbQ==",
+ "dependencies": {
+ "motion-utils": "^12.5.0"
+ }
+ },
+ "node_modules/motion-utils": {
+ "version": "12.5.0",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.5.0.tgz",
+ "integrity": "sha512-+hFFzvimn0sBMP9iPxBa9OtRX35ZQ3py0UHnb8U29VD+d8lQ8zH3dTygJWqK7av2v6yhg7scj9iZuvTS0f4+SA=="
+ },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
diff --git a/package.json b/package.json
index d683e0c4..1b35a64d 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
"test": "jest --coverage"
},
"dependencies": {
+ "@fullpage/react-fullpage": "^0.1.48",
"@radix-ui/react-dropdown-menu": "^2.1.6",
"@radix-ui/react-progress": "^1.1.2",
"@radix-ui/react-slot": "^1.1.2",
@@ -25,6 +26,7 @@
"axios": "^1.7.9",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
+ "framer-motion": "^12.5.0",
"lucide-react": "^0.475.0",
"next": "14.1.0",
"react": "^18.2.0",
diff --git a/public/deving.svg b/public/deving.svg
new file mode 100644
index 00000000..1fc61d2e
--- /dev/null
+++ b/public/deving.svg
@@ -0,0 +1,8 @@
+
diff --git a/public/github.svg b/public/github.svg
new file mode 100644
index 00000000..80ed2072
--- /dev/null
+++ b/public/github.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/landingLogo.svg b/public/landingLogo.svg
new file mode 100644
index 00000000..fecf9864
--- /dev/null
+++ b/public/landingLogo.svg
@@ -0,0 +1,17 @@
+
diff --git a/public/main.png b/public/main.png
new file mode 100644
index 00000000..811d0565
Binary files /dev/null and b/public/main.png differ
diff --git a/public/notion.svg b/public/notion.svg
new file mode 100644
index 00000000..08b1c06d
--- /dev/null
+++ b/public/notion.svg
@@ -0,0 +1,9 @@
+
diff --git a/public/section1.png b/public/section1.png
new file mode 100644
index 00000000..811d0565
Binary files /dev/null and b/public/section1.png differ
diff --git a/public/section2.png b/public/section2.png
new file mode 100644
index 00000000..b7aaf2cb
Binary files /dev/null and b/public/section2.png differ
diff --git a/src/app/(user-page)/mypage/MyPageClient.tsx b/src/app/(user-page)/mypage/MyPageClient.tsx
index b8ade619..0ff1181d 100644
--- a/src/app/(user-page)/mypage/MyPageClient.tsx
+++ b/src/app/(user-page)/mypage/MyPageClient.tsx
@@ -33,6 +33,9 @@ const MyPageClient = () => {
const searchParams = useSearchParams();
const queryClient = useQueryClient();
+ // 데이터가 이미 있는지 확인
+ const hasData = queryClient.getQueryData(QUERY_KEYS.profile());
+
// URL에서 탭 값만 가져오기
const tabFromUrl = searchParams.get('tab') || TAB_TYPES.BASIC;
@@ -51,10 +54,12 @@ const MyPageClient = () => {
[TAB_TYPES.PASSWORD]: null,
});
- // 컴포넌트 마운트 시 프로필 데이터 prefetch
+ // 데이터가 없을 때만 prefetch (서버에서 가져오지 못한 경우의 백업)
useEffect(() => {
- prefetchProfileData(queryClient);
- }, [queryClient]);
+ if (!hasData) {
+ prefetchProfileData(queryClient);
+ }
+ }, [queryClient, hasData]);
// URL 변경 감지 및 상태 업데이트 (중요: 뒤로가기/앞으로가기 처리)
useEffect(() => {
diff --git a/src/app/(user-page)/mypage/page.tsx b/src/app/(user-page)/mypage/page.tsx
index eee8a6d8..6ba08b1a 100644
--- a/src/app/(user-page)/mypage/page.tsx
+++ b/src/app/(user-page)/mypage/page.tsx
@@ -16,7 +16,7 @@ export default async function MyPage() {
await prefetchProfileData(queryClient);
return (
-
+
diff --git a/src/app/meeting/_features/skeletons/SkeletonUserInfo.tsx b/src/app/meeting/_features/skeletons/SkeletonUserInfo.tsx
index 3e88a8b3..15051e42 100644
--- a/src/app/meeting/_features/skeletons/SkeletonUserInfo.tsx
+++ b/src/app/meeting/_features/skeletons/SkeletonUserInfo.tsx
@@ -1,17 +1,17 @@
const SkeletonUserInfo = () => {
return (
);
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 105ebdb7..82c500e2 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,264 +1,497 @@
+'use client';
+
+import Section1Image from '@/assets/images/section1.png';
+import Section2Image from '@/assets/images/section2.png';
+import { Button } from '@/components/ui/Button';
+import { motion } from 'framer-motion';
+import dynamic from 'next/dynamic';
import Image from 'next/image';
-import Link from 'next/link';
+import { useCallback, useEffect, useMemo, useState } from 'react';
-export default function Home() {
- const categories = [
- {
- title: '취미',
- description: '개발 관련 취미 활동을 함께할 동료를 찾아보세요.',
- icon: '🎨',
- color: 'bg-blue',
- },
- {
- title: '스터디',
- description: '함께 성장할 수 있는 개발 스터디를 시작하세요.',
- icon: '📚',
- color: 'bg-green',
- },
- {
- title: '모각코',
- description: '모여서 각자 코딩하며 집중력을 높여보세요.',
- icon: '💻',
- color: 'bg-red',
+import DevingLogo from '../assets/icon/devingLogo.svg';
+import GithubIcon from '../assets/icon/github_icon.svg';
+import LandingLogo from '../assets/icon/landing_logo.svg';
+import MediumCheckIcon from '../assets/icon/medium_check_icon.svg';
+import NotionIcon from '../assets/icon/notion_icon.svg';
+import SmallCheckIcon from '../assets/icon/small_check_Icon.svg';
+
+// 타입 정의 - 라이브러리에서 필요한 속성 정확하게 지정
+interface FullPageProps {
+ credits: {
+ enabled: boolean;
+ position?: 'left' | 'right';
+ label?: string;
+ };
+ scrollingSpeed: number;
+ navigation: boolean;
+ navigationPosition: string;
+ responsiveWidth?: number;
+ scrollOverflow: boolean;
+ licenseKey: string;
+ afterLoad: (destination: { index: number }) => void;
+ touchSensitivity: number;
+ bigSectionsDestination: 'top' | 'bottom' | null;
+ render: (props: { fullpageApi?: unknown }) => JSX.Element;
+}
+
+// 클라이언트 사이드에서만 ReactFullpage 로드
+const FullPage = dynamic(
+ () => import('@fullpage/react-fullpage').then((mod) => mod.default),
+ { ssr: false },
+);
+
+const FullPageWrapper = dynamic(
+ () => import('@fullpage/react-fullpage').then((mod) => mod.default.Wrapper),
+ { ssr: false },
+);
+
+// 애니메이션 설정을 객체로 분리하여 관리
+const animations = {
+ fadeInUp: {
+ hidden: { opacity: 0, y: 60 },
+ visible: {
+ opacity: 1,
+ y: 0,
+ transition: { duration: 0.6, ease: 'easeOut' },
},
- {
- title: '사이드 프로젝트',
- description: '실무 경험을 쌓을 수 있는 사이드 프로젝트를 찾아보세요.',
- icon: '🚀',
- color: 'bg-solid',
+ },
+ staggerContainer: {
+ hidden: { opacity: 0 },
+ visible: {
+ opacity: 1,
+ transition: {
+ staggerChildren: 0.3,
+ },
},
- ];
-
- const featuredGroups = [
- {
- title: 'Next.js 스터디 그룹',
- category: '스터디',
- members: 8,
- maxMembers: 10,
- location: '온라인',
- // imageUrl: '/api/placeholder/300/160',
+ },
+ popIn: {
+ hidden: { scale: 0.8, opacity: 0 },
+ visible: {
+ scale: 1,
+ opacity: 1,
+ transition: {
+ type: 'spring',
+ stiffness: 200,
+ damping: 10,
+ },
},
- {
- title: '주말 모각코 모임',
- category: '모각코',
- members: 12,
- maxMembers: 20,
- location: '서울 강남',
- // imageUrl: '/api/placeholder/300/160',
+ },
+ imageAnimation: {
+ hidden: { opacity: 0, scale: 0.9 },
+ visible: {
+ opacity: 1,
+ scale: 1,
+ transition: { duration: 0.7, ease: 'easeOut' },
},
- {
- title: 'AI 챗봇 프로젝트',
- category: '사이드 프로젝트',
- members: 4,
- maxMembers: 6,
- location: '온라인/오프라인',
- // imageUrl: '/api/placeholder/300/160',
+ },
+};
+
+// 언마운트 오류를 방지하기 위한 래퍼 컴포넌트
+const SafeFullPage: React.FC
= (props) => {
+ const [mounted, setMounted] = useState(false);
+
+ useEffect(() => {
+ setMounted(true);
+
+ // 콘솔 경고 필터링을 위한 원본 콘솔 참조 저장
+ const originalConsoleError = console.error;
+
+ // fullPage 라이센스 경고 필터링 함수
+ const filterConsoleError = (...args: Parameters) => {
+ if (
+ typeof args[0] === 'string' &&
+ (args[0].includes('fullPage:') ||
+ args[0].includes('licenseKey') ||
+ args[0].includes('alvarotrigo'))
+ ) {
+ return; // fullPage 라이센스 메시지 무시
+ }
+ originalConsoleError(...args);
+ };
+
+ // 콘솔 오류 필터링 적용
+ console.error = filterConsoleError;
+
+ // 스타일 요소 생성 및 적용
+ const style = document.createElement('style');
+ style.innerHTML = `
+ .fp-watermark, #fp-nav ul li .fp-tooltip, .fp-warning {
+ display: none !important;
+ }
+
+ /* 첫 번째 섹션 스크롤 제거 */
+ #fp-nav + .fp-section:first-of-type {
+ overflow: hidden !important;
+ }
+
+ /* fp-auto-height 섹션이 올바르게 표시되도록 스타일 조정 */
+ .fp-auto-height.fp-section {
+ height: auto !important;
+ }
+
+ .fp-auto-height .fp-tableCell {
+ height: auto !important;
+ padding-bottom: 0 !important;
+ }
+ `;
+ document.head.appendChild(style);
+
+ return () => {
+ setMounted(false);
+ // 원래의 console.error 복원
+ console.error = originalConsoleError;
+
+ // 언마운트 전에 정리를 위한 지연
+ setTimeout(() => {
+ const fpNav = document.querySelector('#fp-nav');
+ if (fpNav) fpNav.remove();
+
+ const sections = document.querySelectorAll('.section');
+ sections.forEach((section) => {
+ section.classList.remove('active', 'fp-section', 'fp-table');
+ });
+
+ if (document.head.contains(style)) {
+ document.head.removeChild(style);
+ }
+ }, 0);
+ };
+ }, []);
+
+ if (!mounted) return null;
+
+ return ;
+};
+
+export default function Home() {
+ const [isClient, setIsClient] = useState(false);
+ const [currentSection, setCurrentSection] = useState(0);
+ const [isMobile, setIsMobile] = useState(false);
+
+ // 모바일 감지 함수를 useCallback으로 최적화
+ const checkMobile = useCallback(() => {
+ setIsMobile(window.innerWidth < 768);
+ }, []);
+
+ // afterLoad 핸들러를 useCallback으로 최적화
+ const handleAfterLoad = useCallback(
+ (destination: { index: number }): void => {
+ setCurrentSection(destination.index);
},
- ];
+ [],
+ );
+
+ // 동적 모듈 사전 로드 함수
+ const preloadModules = useCallback(async () => {
+ try {
+ await import('@fullpage/react-fullpage');
+ // console.log 대신 주석으로 처리
+ // console.log('FullPage 모듈 로드 성공');
+ } catch (error) {
+ console.error('FullPage 모듈 로드 실패:', error);
+ }
+ }, []);
+
+ useEffect(() => {
+ // 컴포넌트 마운트 즉시 상태 변경
+ setIsClient(true);
+
+ // 초기 모바일 체크
+ checkMobile();
+
+ // 리사이즈 이벤트에 대응
+ window.addEventListener('resize', checkMobile);
+
+ // 모듈 사전 로드
+ preloadModules();
+
+ return () => {
+ // 이벤트 리스너 정리
+ window.removeEventListener('resize', checkMobile);
+ };
+ }, [checkMobile, preloadModules]);
+
+ // 로딩 상태일 때 표시될 컴포넌트
+ if (!isClient) {
+ return (
+
+ 로딩 중...
+ Loading...
+
+ );
+ }
return (
-
- {/* 헤더바는 이미 준비되어 있음 */}
-
- {/* Hero Section */}
-
-
-
-
- 개발자를 위한 커뮤니티
-
-
- 함께 성장하고 배울 개발자 친구들을 만나보세요. 취미 활동부터
- 사이드 프로젝트까지, 다양한 모임에 참여할 수 있습니다.
-
-
-
-
+
{
+ return (
+
+
+ {/* 메인 히어로 섹션 */}
+
+
+
+ 개발자와 디자이너의 공간,
+
+ Deving에서 함께해요!
+
+
+
+
+
+
-
-
-
-
-
- {/* Categories Section */}
-
-
-
카테고리
-
- {categories.map((category, index) => (
-
-
+ {/* 섹션 1: 성장하는 모임 */}
+
-
{category.title}
-
- {category.description}
-
-
- ))}
-
-
-
-
- {/* Featured Groups */}
-
-
-
-
인기 모임
-
- 더 보기 →
-
-
-
- {featuredGroups.map((group, index) => (
-
-
-
-
- {group.category}
-
-
-
-
{group.title}
-
- {group.location}
-
-
-
- 멤버 {group.members}/{group.maxMembers}
+
+

+
+
+ 모임 시작
+
+
+
+ D-
+
+
+ 7
+
+
+ 일
+
+
-
-
-
- ))}
-
-
-
-
- {/* CTA Section */}
-
-
-
나만의 개발자 모임을 시작해보세요
-
- 취미, 스터디, 모각코, 사이드 프로젝트 등 다양한 주제로 모임을 만들고
- 함께할 개발자들을 찾아보세요.
-
-
- 모임 생성하기
-
-
-
-
- {/* Bottom Banner */}
-
-
-
-
-
DEVING과 함께 성장하세요
-
- 개발자 커뮤니티에서 함께 성장할 동료를 찾아보세요.
-
+
+
+
+
+ 코드만큼 성장하는 모임,
+
+ 지금 시작하세요!
+
+
+ 스터디/모각코/사이드프로젝트/취미까지
+
+ 다양한 모임을 원하는 기술스택으로 필터링 해보세요!
+
+
+
+
-
-
- 로그인
-
-
- 회원가입
-
+
+
+ {/* 섹션 2: 기능 소개 */}
+
+
+
+
+ 모임 스타일에 맞게
+
+ 모임을 개설할 수 있어요!
+
+
+ 신청자 정보를 확인하고 승인할 수 있어요.
+
+ 모임 안에서 서로의 정보를 파악하고 교류를 시작하세요!
+
+
+
+
+
+

+
+
+ 모임 공개 여부
+
+
+ 비공개
+
+
+
+
+ {isMobile ? (
+
+ ) : (
+
+ )}
+
+ 모임 생성이 완료 되었습니다!
+
+
+
+ 확인하기
+
+
+
+
+
-
-
-
-
- {/* ✅ 이슈 제보 섹션 추가 ✅ */}
-
-
-
- 사이트에서 문제가 발생했나요?
-
-
- 오류를 발견하셨다면 아래 버튼을 눌러 이슈를 제보해주세요.
-
-
- 🛠 이슈 제보하기
-
-
-
-
- {/* Footer */}
-