diff --git a/next.config.ts b/next.config.ts index 996fbd9..0ecd118 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,13 +1,14 @@ import type { NextConfig } from 'next'; const nextConfig: NextConfig = { + // TurboPack 설정 experimental: { turbo: { rules: { - '.svg': { + '*.svg': { loaders: ['@svgr/webpack'], - as: '.js', + as: '*.js', }, }, }, @@ -20,11 +21,11 @@ const nextConfig: NextConfig = { config.module.rules.push( { ...fileLoaderRule, - test: /.svg$/i, + test: /\.svg$/i, resourceQuery: /url/, }, { - test: /.svg$/i, + test: /\.svg$/i, issuer: fileLoaderRule.issuer, resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, use: [ @@ -38,7 +39,7 @@ const nextConfig: NextConfig = { ], } ); - fileLoaderRule.exclude = /.svg$/i; + fileLoaderRule.exclude = /\.svg$/i; return config; }, }; diff --git a/package-lock.json b/package-lock.json index a2e3b32..0b1c61b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,13 @@ "version": "0.1.0", "license": "ISC", "dependencies": { + "class-variance-authority": "^0.7.1", "gsap": "^3.13.0", + "lottie-react": "^2.4.1", "next": "15.5.3", "react": "19.1.0", - "react-dom": "19.1.0" + "react-dom": "19.1.0", + "react-hot-toast": "^2.6.0" }, "devDependencies": { "@eslint/eslintrc": "^3", @@ -4521,6 +4524,18 @@ "node": ">=18" } }, + "node_modules/class-variance-authority": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", + "license": "Apache-2.0", + "dependencies": { + "clsx": "^2.1.1" + }, + "funding": { + "url": "https://polar.sh/cva" + } + }, "node_modules/cli-cursor": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", @@ -4564,7 +4579,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -4786,7 +4800,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, "license": "MIT" }, "node_modules/damerau-levenshtein": { @@ -6065,6 +6078,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/goober": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz", + "integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -7251,6 +7273,25 @@ "loose-envify": "cli.js" } }, + "node_modules/lottie-react": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/lottie-react/-/lottie-react-2.4.1.tgz", + "integrity": "sha512-LQrH7jlkigIIv++wIyrOYFLHSKQpEY4zehPicL9bQsrt1rnoKRYCYgpCUe5maqylNtacy58/sQDZTkwMcTRxZw==", + "license": "MIT", + "dependencies": { + "lottie-web": "^5.10.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/lottie-web": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.13.0.tgz", + "integrity": "sha512-+gfBXl6sxXMPe8tKQm7qzLnUy5DUPJPKIyRHwtpCpyUEYjHYRJC/5gjUvdkuO2c3JllrPtHXH5UJJK8LRYl5yQ==", + "license": "MIT" + }, "node_modules/lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", @@ -8030,6 +8071,23 @@ "react": "^19.1.0" } }, + "node_modules/react-hot-toast": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.6.0.tgz", + "integrity": "sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==", + "license": "MIT", + "dependencies": { + "csstype": "^3.1.3", + "goober": "^2.1.16" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", diff --git a/package.json b/package.json index cc5c7a0..3458d02 100644 --- a/package.json +++ b/package.json @@ -18,10 +18,13 @@ ] }, "dependencies": { + "class-variance-authority": "^0.7.1", "gsap": "^3.13.0", + "lottie-react": "^2.4.1", "next": "15.5.3", "react": "19.1.0", - "react-dom": "19.1.0" + "react-dom": "19.1.0", + "react-hot-toast": "^2.6.0" }, "devDependencies": { "@eslint/eslintrc": "^3", diff --git a/public/file.svg b/public/file.svg deleted file mode 100644 index 004145c..0000000 --- a/public/file.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/globe.svg b/public/globe.svg deleted file mode 100644 index 567f17b..0000000 --- a/public/globe.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/logo.svg b/public/logo.svg new file mode 100644 index 0000000..e664442 --- /dev/null +++ b/public/logo.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/logoDark.svg b/public/logoDark.svg new file mode 100644 index 0000000..709a21b --- /dev/null +++ b/public/logoDark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/next.svg b/public/next.svg deleted file mode 100644 index 5174b28..0000000 --- a/public/next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/vercel.svg b/public/vercel.svg deleted file mode 100644 index 7705396..0000000 --- a/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/window.svg b/public/window.svg deleted file mode 100644 index b2b2a44..0000000 --- a/public/window.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/@store/store.ts b/src/@store/store.ts deleted file mode 100644 index b9b9f5c..0000000 --- a/src/@store/store.ts +++ /dev/null @@ -1 +0,0 @@ -// zustand store diff --git a/src/api/test.tsx b/src/api/test.tsx deleted file mode 100644 index 5281734..0000000 --- a/src/api/test.tsx +++ /dev/null @@ -1,4 +0,0 @@ -function test() { - return
test
; -} -export default test; diff --git a/src/app/community/page.tsx b/src/app/community/page.tsx index 804c93f..84390d4 100644 --- a/src/app/community/page.tsx +++ b/src/app/community/page.tsx @@ -1,4 +1,37 @@ -function page() { - return
page
; +import CommunityFilter from '@/shared/components/community/CommunityFilter'; +import CommunityHeader from '@/shared/components/community/CommunityHeader'; +import CommunityTab from '@/shared/components/community/CommunityTab'; +import PostCard from '@/shared/components/community/PostCard'; +import WriteBtn from '@/shared/components/community/WriteBtn'; + +function Page() { + return ( +
+
+
+

+ 커뮤니티 페이지 +

+ +
+ +
+ + +
+ +
+ + + + + +
+
+
+ ); } -export default page; +export default Page; diff --git a/src/app/design-system/page.tsx b/src/app/design-system/page.tsx new file mode 100644 index 0000000..ad3e5cb --- /dev/null +++ b/src/app/design-system/page.tsx @@ -0,0 +1,164 @@ +'use client'; + +import Button from '@/shared/components/button/Button'; +import TextButton from '@/shared/components/button/TextButton'; +import Input from '@/shared/components/InputBox/Input'; +import { useState } from 'react'; +import { customToast } from '@/shared/components/toast/CustomToastUtils'; +import ModalLayout from '@/shared/components/modalPop/ModalLayout'; +import ConfirmPop from '@/shared/components/modalPop/ConfirmPop'; +import SelectBox from '@/shared/components/InputBox/SelectBox'; +import LikeBtn from '@/shared/components/like/LikeBtn'; +import Share from '@/shared/components/share/Share'; +import Keep from '@/shared/components/keep/Keep'; +import Spinner from '@/shared/components/spinner/Spinner'; + +function Page() { + const [isModalOpen, setModalOpen] = useState(false); + const [isConfirmOpen, setConfirmOpen] = useState(false); + + return ( +
+ {/* 페이지 제목 */} +

Design System

+ + {/* Form 영역 */} +
+

Form

+ + {/* Input */} +
+

Input

+ + + + +
+ + {/* select */} +
+

select

+ +
+
+ + {/* Button */} +
+

Button

+ +
+

Button

+ + + + + + + + 텍스트 버튼 + 텍스트 버튼 +
+
+ + {/* popup */} +
+

popup

+ +
+

toast

+
+ + + + + +
+
+ +
+

popup

+ {/* 모달 열기 버튼 */} + + + + setModalOpen(false)} + title="제목" + description="설명" + buttons={ + <> + + + } + > +
모달팝업 내용
+
+ + setConfirmOpen(false)} + title="Confirm제목" + description="설명" + /> +
+
+ +
+

Icons

+
+

like

+ +
+
+

Share

+ + +
+
+

keep

+ +
+
+ +
+

Spinner

+ +
+
+ ); +} +export default Page; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 9cc8854..16084e3 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,9 @@ import type { Metadata } from 'next'; -import '../styles/global.css'; - +import '@/shared/styles/global.css'; +import { Toaster } from 'react-hot-toast'; +import Header from '@/shared/components/header/Header'; +import FooterWrapper from '@/shared/components/footer/FooterWrapper'; +import ScrollTopBtnWrapper from '@/shared/components/scrollTop/ScrollTopBtnWrapper'; export const metadata: Metadata = { title: 'SSOUL', description: '칵테일을 좋아하는 사람들을 위한 서비스', @@ -13,7 +16,28 @@ export default function RootLayout({ }>) { return ( - {children} + +
+
+
+ {children} +
+ + + + + + + ); } diff --git a/src/app/login/SocialLogin.tsx b/src/app/login/SocialLogin.tsx new file mode 100644 index 0000000..1d60cbf --- /dev/null +++ b/src/app/login/SocialLogin.tsx @@ -0,0 +1,56 @@ +'use client'; + +import Naver from '@/shared/assets/icons/naver.svg'; +import Kakao from '@/shared/assets/icons/kakao.svg'; +import Google from '@/shared/assets/icons/google.svg'; +import tw from '@/shared/utills/tw'; +import { useAuthStore } from '@/shared/@store/auth'; + +function SocialLogin() { + const { loginWithProvider } = useAuthStore(); + + const socialButtons = [ + { + id: 'naver', + label: 'Naver 로그인', + icon: , + style: 'bg-[#00C73C]', + }, + { + id: 'kakao', + label: 'Kakao 로그인', + icon: , + style: 'bg-[#FEE500] text-primary', + }, + { + id: 'google', + label: 'Google 로그인', + icon: , + style: 'bg-[#EBEBEB] text-primary', + }, + ]; + + // TODO: 백엔드 연동 로직 구현 필요 + const handleLogin = (id: string) => { + loginWithProvider(id as 'naver' | 'kakao' | 'google'); + }; + + return ( + <> +
+ {socialButtons.map(({ id, label, icon, style }) => ( + + ))} +
+ + ); +} +export default SocialLogin; diff --git a/src/app/login/first-user/page.tsx b/src/app/login/first-user/page.tsx new file mode 100644 index 0000000..7f902a4 --- /dev/null +++ b/src/app/login/first-user/page.tsx @@ -0,0 +1,7 @@ +import LoginRedirectHandler from '@/shared/components/auth/LoginRedirectHandler'; + +function Page() { + return ; +} + +export default Page; diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx new file mode 100644 index 0000000..d1e4fb8 --- /dev/null +++ b/src/app/login/page.tsx @@ -0,0 +1,36 @@ +import Image from 'next/image'; +import type { Metadata } from 'next'; +import loginBg from '@/shared/assets/images/login_bg.webp'; +import SocialLogin from './SocialLogin'; + +export const metadata: Metadata = { + title: 'SSOUL | 로그인', + description: '칵테일을 좋아하는 사람들을 위한 서비스 로그인 페이지', +}; + +function Page() { + return ( +
+
+ +
+ +
+

로그인

+

3초 로그인으로 SSOUL을 가볍게 즐겨보세요🍸

+
+ + +
+ ); +} +export default Page; diff --git a/src/app/login/success/page.tsx b/src/app/login/success/page.tsx new file mode 100644 index 0000000..15766eb --- /dev/null +++ b/src/app/login/success/page.tsx @@ -0,0 +1,6 @@ +import LoginRedirectHandler from '@/shared/components/auth/LoginRedirectHandler'; + +function Page() { + return ; +} +export default Page; diff --git a/src/app/mypage/page.tsx b/src/app/mypage/page.tsx index 804c93f..3b9d3ac 100644 --- a/src/app/mypage/page.tsx +++ b/src/app/mypage/page.tsx @@ -1,4 +1,4 @@ -function page() { - return
page
; +function Page() { + return
mypage
; } -export default page; +export default Page; diff --git a/src/app/page.tsx b/src/app/page.tsx index 54fd584..14d51b2 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,9 +1,7 @@ export default function Home() { return ( -
-

이게 기본

-

this is Serif

-

테스트입니다

+
+

메인페이지

); } diff --git a/src/app/recipe/[id]/page.tsx b/src/app/recipe/[id]/page.tsx new file mode 100644 index 0000000..9d89ac4 --- /dev/null +++ b/src/app/recipe/[id]/page.tsx @@ -0,0 +1,10 @@ +import StarBg from '@/shared/components/starBg/StarBg'; + +function page() { + return ( +
+ +
+ ); +} +export default page; diff --git a/src/app/recipe/components/Accordion.tsx b/src/app/recipe/components/Accordion.tsx new file mode 100644 index 0000000..aff8c14 --- /dev/null +++ b/src/app/recipe/components/Accordion.tsx @@ -0,0 +1,36 @@ +'use client'; + +import SelectBox from '@/shared/components/InputBox/SelectBox'; + +const selectOption = [ + { + id: 'abv', + option: ['', '약한 도수', '가벼운 도수', '중간 도수', '센 도수', '매우 센 도수'], + title: '도수', + }, + { + id: 'base', + option: ['', '위스키', '진', '럼', '보드카', '데킬라', '리큐르'], + title: '베이스', + }, + { + id: 'glass', + option: ['', '클래식', '롱', '슈터', '숏'], + title: '글라스', + }, +]; + +function Accordion() { + return ( +
    + {selectOption.map(({ id, option, title }) => { + return ( +
  • + +
  • + ); + })} +
+ ); +} +export default Accordion; diff --git a/src/app/recipe/page.tsx b/src/app/recipe/page.tsx index 804c93f..9f5e417 100644 --- a/src/app/recipe/page.tsx +++ b/src/app/recipe/page.tsx @@ -1,4 +1,47 @@ -function page() { - return
page
; +import PageHeader from '@/shared/components/pageHeader/PageHeader'; +import { Metadata } from 'next'; +import Glass from '@/shared/assets/images/recipe_page_header.webp'; +import SelectBox from '@/shared/components/InputBox/SelectBox'; +import Input from '@/shared/components/InputBox/Input'; +import CocktailList from '@/shared/components/recipePage/cocktailList/CocktailList'; +import Accordion from './components/Accordion'; + +export const metadata: Metadata = { + title: 'SSOUL | 칵테일레시피', + description: '칵테일 레시피가 궁금하신 분들을 위한 레시피 페이지', +}; + +function Page() { + return ( +
+
+ +
+
+
+ + +
+
+
+

n개

+ +
+
+ +
+
+
+
+ ); } -export default page; +export default Page; diff --git a/src/app/recommend/components/ChatCocktailCard.tsx b/src/app/recommend/components/ChatCocktailCard.tsx new file mode 100644 index 0000000..19b6c4a --- /dev/null +++ b/src/app/recommend/components/ChatCocktailCard.tsx @@ -0,0 +1,23 @@ +import Image from 'next/image'; +import Dummy from '@/shared/assets/images/dummy/exampleCocktail.png'; +import Link from 'next/link'; +import Keep from '@/shared/components/keep/Keep'; + +function ChatCocktailCard() { + return ( +
+ +
+ 칵테일 이름 +
+ +
+ {'진피즈'} + + 상세보기 +
+ + +
+ ); +} +export default ChatCocktailCard; diff --git a/src/app/recommend/components/ChatForm.tsx b/src/app/recommend/components/ChatForm.tsx new file mode 100644 index 0000000..78e6a9a --- /dev/null +++ b/src/app/recommend/components/ChatForm.tsx @@ -0,0 +1,44 @@ +'use client'; + +import Send from '@/shared/assets/icons/send_36.svg'; +import { keyDown } from '@/shared/utills/keyDown'; +import { useState } from 'react'; + +function ChatForm() { + const handleInput = (e: React.FormEvent) => { + const target = e.currentTarget; + + if (target.value == '') { + target.style.height = ''; + } + target.style.height = `${target.scrollHeight}px`; + }; + + return ( +
+
e.preventDefault()}> +
+ +