diff --git a/src/App.css b/src/App.css index 83284eb..c7a6ee9 100644 --- a/src/App.css +++ b/src/App.css @@ -1,6 +1,29 @@ +:root { + /* width: 100vw; + height: 100vh; */ + /* height: calc(var(--vh, 1vh) * 100); */ +} + :root { font-family: "SUIT Variable", sans-serif; text-align: center; - width: 100vw; - height: calc(var(--vh, 1vh) * 100); -} + margin: 0 auto; + max-width: 430px; + width: 100%; + min-height: 100vh; + /* height: calc(var(--vh, 1vh) * 100); */ + background-color: white; + box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; + overflow-x: hidden; + overflow-y: hidden; + display: flex; + flex-direction: column; + align-items: center; + /* justify-content: center; */ + border-radius: 5px; + color: #1a1e27; + font-family: "SUIT Variable", -apple-system, BlinkMacSystemFont, Pretendard, + "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", + sans-serif; + font-weight: 400; +} \ No newline at end of file diff --git a/src/index.css b/src/index.css index b5e5210..7aad512 100644 --- a/src/index.css +++ b/src/index.css @@ -3,23 +3,189 @@ src: url(https://cdn.jsdelivr.net/gh/sunn-us/SUIT/fonts/variable/woff2/SUIT-Variable.css); } +button { + font-family: -apple-system, BlinkMacSystemFont, Pretendard, "Segoe UI", Roboto, + Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; +} + :root { - width: 100vw; - height: calc(var(--vh, 1vh) * 100); - font-family: "SUIT Variable", -apple-system, BlinkMacSystemFont, Pretendard, - "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", - sans-serif; - font-weight: 400; - color: #1a1e27; + --vh: 100%; +} + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, menu, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +main, menu, nav, output, ruby, section, summary, +time, mark, audio, video { margin: 0; - overflow-x: hidden; - overflow-y: hidden; - display: flex; - align-items: center; - justify-content: center; + border: 0; + padding: 0; + vertical-align: baseline; + font: inherit; + font-size: 100%; +} +article, aside, details, figcaption, figure, +footer, header, hgroup, main, menu, nav, section { + display: block; +} +*[hidden] { + display: none; +} +body { + touch-action: manipulation; + line-height: 1; +} +menu, ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; } +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} + +/* 폰트 설정 */ +body { + font-size: 9px; + font-family: "Pretendard"; +} + +@media (max-width: 768px) { + body { + font-size: 9px; + font-family: "Pretendard"; + } +} +@media (max-width: 1200px) { + body { + font-size: 9px; + font-family: "Pretendard"; + } +} + +* { + box-sizing: border-box; +} +html { + -webkit-touch-callout: none; + -webkit-tap-highlight-color:rgba(0, 0, 0, 0); + + scroll-behavior: smooth; + + font-family: sans-serif; + /* font-size: 62.5%; */ + user-select: none; + /* @media (min-width:1800px){ + font-size: 62.5%; + } + @media (min-width:1420px) and (max-width:1799px){ + font-size: 46.8%; + } + @media (min-width:900px) and (max-width:1419px){ + font-size: 42%; + } + @media (min-width: 768px) and (max-width:899px){ + font-size: 35%; + } + @media (max-width:767px){ + font-size: 32%; + } */ + +} +ul, li { + padding-left: 0rem; + list-style: none; +} +a { + text-decoration: none; + color: inherit; +} +input, button { + outline: none; + border: none; + background-color: transparent; +} button { - font-family: -apple-system, BlinkMacSystemFont, Pretendard, "Segoe UI", Roboto, - Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; + cursor: pointer; + padding: 0; +} +input { + appearance: none; + + &:focus { + outline: none; + } +} + + + +@font-face { + font-family: 'Pretendard-Regular'; + src: url('https://cdn.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff') format('woff'); + font-weight: 400; + font-style: normal; +} + +@font-face { + font-family: 'EsaManru'; + font-weight: 300; + font-style: normal; + src: url('https://cdn.jsdelivr.net/gh/webfontworld/gonggames/EsaManruLight.eot'); + src: url('https://cdn.jsdelivr.net/gh/webfontworld/gonggames/EsaManruLight.eot?#iefix') format('embedded-opentype'), + url('https://cdn.jsdelivr.net/gh/webfontworld/gonggames/EsaManruLight.woff2') format('woff2'), + url('https://cdn.jsdelivr.net/gh/webfontworld/gonggames/EsaManruLight.woff') format('woff'), + url('https://cdn.jsdelivr.net/gh/webfontworld/gonggames/EsaManruLight.ttf') format("truetype"); } + +@font-face { + font-family: 'Dovemayo_gothic'; + src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2302@1.1/Dovemayo_gothic.woff2') format('woff2'); + font-weight: normal; + font-style: normal; +} + +@font-face { +font-family: 'Dovemayo_gothic'; +src: url('https://cdn.jsdelivr.net/gh/projectnoonnu/noonfonts_2302/OTF/Dovemayo_gothic.otf') format('opentype'); +font-weight: normal; +font-style: normal; + + +} +@font-face { + font-family: 'EsaManru'; + font-weight: 500; + font-style: normal; + src: url('https://cdn.jsdelivr.net/gh/webfontworld/gonggames/EsaManruMedium.eot'); + src: url('https://cdn.jsdelivr.net/gh/webfontworld/gonggames/EsaManruMedium.eot?#iefix') format('embedded-opentype'), + url('https://cdn.jsdelivr.net/gh/webfontworld/gonggames/EsaManruMedium.woff2') format('woff2'), + url('https://cdn.jsdelivr.net/gh/webfontworld/gonggames/EsaManruMedium.woff') format('woff'), + url('https://cdn.jsdelivr.net/gh/webfontworld/gonggames/EsaManruMedium.ttf') format("truetype"); +} + +@font-face { + font-family: 'EsaManru'; + font-weight: 700; + font-style: normal; + src: url('https://cdn.jsdelivr.net/gh/webfontworld/gonggames/EsaManruBold.eot'); + src: url('https://cdn.jsdelivr.net/gh/webfontworld/gonggames/EsaManruBold.eot?#iefix') format('embedded-opentype'), + url('https://cdn.jsdelivr.net/gh/webfontworld/gonggames/EsaManruBold.woff2') format('woff2'), + url('https://cdn.jsdelivr.net/gh/webfontworld/gonggames/EsaManruBold.woff') format('woff'), + url('https://cdn.jsdelivr.net/gh/webfontworld/gonggames/EsaManruBold.ttf') format("truetype"); +} \ No newline at end of file diff --git a/src/pages/Frame/ApplyFrame.jsx b/src/pages/Frame/ApplyFrame.jsx index 221b4ff..a0bf3a5 100644 --- a/src/pages/Frame/ApplyFrame.jsx +++ b/src/pages/Frame/ApplyFrame.jsx @@ -5,7 +5,7 @@ import left from "../../img/left.png"; import trash from "../../img/trash.png"; import photobook from "../../img/book.png"; import frameline from "../../img/frame-line.png"; -import { Link, useLocation } from "react-router-dom"; +import { Link, useLocation, useNavigate } from "react-router-dom"; import { useAtom } from "jotai"; import { accessTokenAtom } from "../../store/jotaiAtoms"; import html2canvas from "html2canvas"; @@ -18,6 +18,7 @@ const ApplyFrame = () => { const [selectedButton, setSelectedButton] = useState("프레임 제작"); const [accessToken] = useAtom(accessTokenAtom); const [uploadedImage, setUploadedImage] = useState(null); + const router = useNavigate(); console.log(selectedFrame); @@ -64,6 +65,7 @@ const ApplyFrame = () => { if (accessToken) { const config = { + data: frameUrl, headers: { Authorization: `Bearer ${accessToken}`, // 헤더에 accessToken을 추가 }, @@ -71,13 +73,12 @@ const ApplyFrame = () => { axios .delete( "http://ec2-3-35-208-177.ap-northeast-2.compute.amazonaws.com:8080/frame", - config, - { data: frameUrl } + config ) .then((res) => { console.log(res.data); // 성공적으로 데이터를 받아온 경우 - setFrames(res.data); // 받아온 데이터로 frames 상태 업데이트 + // setFrames(res.data); // 받아온 데이터로 frames 상태 업데이트 }) .catch((err) => { // 오류 처리 @@ -173,6 +174,7 @@ const ApplyFrame = () => { ) .then((res) => { console.log("프레임 적용한 사진 저장 API 응답:", res.data); + alert("저장 완료되었습니다.") }) .catch((err) => { console.error("API 요청 중 오류 발생:", err); diff --git a/src/pages/Frame/Frame.jsx b/src/pages/Frame/Frame.jsx index 66718fc..6158a4e 100644 --- a/src/pages/Frame/Frame.jsx +++ b/src/pages/Frame/Frame.jsx @@ -10,7 +10,7 @@ import framelist from "../../img/framelist.png"; import styles from "./Frame.module.css"; import Template from "../../component/MakeFrameCpn/Template"; import FrameList from "../../component/AllFrameCpn/FrameList"; -import Photobook from "../Photobook/PhotoSelect"; +import PhotoList from "../Photobook/PhotoList"; import { Link } from "react-router-dom"; const Frame = () => { @@ -37,7 +37,7 @@ const Frame = () => { middleContent = ; break; case "포토북": - middleContent = ; + middleContent = ; break; default: middleContent = ; diff --git a/src/pages/Main/Main.module.scss b/src/pages/Main/Main.module.scss index 8180911..14b973a 100644 --- a/src/pages/Main/Main.module.scss +++ b/src/pages/Main/Main.module.scss @@ -3,6 +3,7 @@ flex-direction: column; align-items: center; justify-items: center; + width: 100%; } .logoBtn { width: 100%; @@ -12,14 +13,17 @@ margin-bottom: 100px; img { - width: 56%; - height: 50%; + width: 50%; + height: auto; display: inline-flex; } } +.linkBtn_container{ + width: 100%; +} .logoutBtn, .loginBtn { - width: 50vw; + width: 50%; height: 45px; background-color: #009eff; border: none; diff --git a/src/pages/Photobook/PhotoList.jsx b/src/pages/Photobook/PhotoList.jsx new file mode 100644 index 0000000..db893b0 --- /dev/null +++ b/src/pages/Photobook/PhotoList.jsx @@ -0,0 +1,117 @@ +import { useEffect, useState } from "react"; +import styles from "./PhotoList.module.scss"; +// import circleCheck from "../../img/circle-check-filled.png"; +import useAxios from "../../apis/axiosWithToken"; +import { useNavigate } from "react-router-dom"; + +export default function PhotoList() { + const axios = useAxios(); + const [getPhotos, setGetPhotos] = useState([]); + const [selectedPhotos, setSelectedPhotos] = useState([]); + const [isPhotobookExist, setIsPhotobookExist] = useState(false); + const [selectedButton, setSelectedButton] = useState("프레임 제작"); + const router = useNavigate(); + + const handlePhotoClick = (index) => { + setSelectedPhotos((prevSelectedPhotos) => { + // 이미 선택된 사진이면 제거, 아니면 추가 + if (prevSelectedPhotos.includes(index)) { + const newSelectedPhotos = prevSelectedPhotos.filter( + (selectedIndex) => selectedIndex !== index + ); + console.log("삭제 후:", newSelectedPhotos); + return newSelectedPhotos; + } else { + const newSelectedPhotos = [...prevSelectedPhotos, index]; + console.log("추가 후:", newSelectedPhotos); + return newSelectedPhotos; + } + }); + }; + + useEffect(() => { + console.log("세팅 후:", selectedPhotos); + console.log( + "api 보내기전: ", + selectedPhotos.map((index) => getPhotos[index]) + ); + axios + .get("/photo") + .then((response) => { + setGetPhotos(response.data.photoList); + setIsPhotobookExist(response.data.present); + }) + .catch((error) => console.error(error)); + }, [selectedPhotos]); + + const handlePostData = async () => { + const data = { + name: "토리", + addPhotoList: selectedPhotos.map((index) => getPhotos[index]), + }; + + if (selectedPhotos.length === 0) { + // 선택된 사진이 없을 경우 알림 창 띄우기 + alert("사진을 선택해주세요."); + return; + } + else { + try { + const response = await axios.post("/photoBook", data); + console.log("API 응답:", response.data); + router("/photobook"); + } catch (error) { + console.error("API 오류:", error); + } + } + }; + + const checkPhotobook = () => { + router("/photobook"); + } + + return ( +
+
+ {isPhotobookExist ? ( + + ) : ( + + )} +
+
+
+ {/* 이미지 배열을 map 함수를 사용하여 렌더링 */} + {getPhotos.map((photo, index) => ( +
handlePhotoClick(index)} + className={styles.photoBox} + > + {`photo-${index}`} + {selectedPhotos.includes(index) && ( +
+
+ {selectedPhotos.indexOf(index) + 1} +
+
+ )} +
+ ))} +
+
+
+ ); +} diff --git a/src/pages/Photobook/PhotoList.module.scss b/src/pages/Photobook/PhotoList.module.scss new file mode 100644 index 0000000..8c0cb18 --- /dev/null +++ b/src/pages/Photobook/PhotoList.module.scss @@ -0,0 +1,89 @@ +.wrapper { + width: 100vw; + height: 100vh; + overflow-x: hidden; + display: flex; + flex-direction: column; +} + +.header { + width: 100vw; + height: 12vh; + display: flex; + align-items: center; + justify-content: center; + background-color: white; + padding: 20px 0; + position: absolute; + z-index: 10; + margin-top: -1px; + .inactive, .active { + height: 50px; + width: 340px; + border-radius: 10px; + border: 2px solid #009eff; + color: #009eff; + text-align: center; + font-size: 14px; + font-weight: 500; + background-color: white; + } + .active { + background-color: #009eff; + color: white; + } +} + +.bodySection { + width: 100vw; + min-height: 400px; + display: flex; + justify-content: center; + margin-top: 12vh; + .boxWrapper { + position: relative; + width: 340px; + min-height: 673px; + display: grid; + grid-template-columns: repeat(2, 1fr); /* 2열로 나열 */ + grid-template-rows: repeat(auto-fill, minmax(150px, 1fr)); + grid-gap: 20px; /* 각 요소 사이의 간격 설정 */ + } + .photoBox { + position: relative; + width: 160px; + height: 160px; + background-color: #f7f7f7; + img { + position: absolute; + z-index: 1; + height: 160px; + left: 26.22px; + width: auto; + } + .selectBox { + position: absolute; + z-index: 5; + width: 160px; + height: 160px; + background-color: rgba(255, 255, 255, 0.4); + border: 2.5px solid #009eff; + box-sizing: border-box; + display: flex; + flex-direction: row-reverse; + .selectNumber { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + color: white; + font-size: 14px; + font-weight: 600; + background-color: #009eff; + border-radius: 40px; + margin: 8px; + } + } + } +} diff --git a/src/pages/Photobook/PhotoSelect.jsx b/src/pages/Photobook/PhotoSelect.jsx index 12d92eb..afdc046 100644 --- a/src/pages/Photobook/PhotoSelect.jsx +++ b/src/pages/Photobook/PhotoSelect.jsx @@ -1,116 +1,81 @@ -import { useEffect, useState } from "react"; -import styles from "./Photoselect.module.scss"; -// import circleCheck from "../../img/circle-check-filled.png"; -import useAxios from "../../apis/axiosWithToken"; -import { useNavigate } from "react-router-dom"; - -export default function PhotoSelect() { - const axios = useAxios(); - const [getPhotos, setGetPhotos] = useState([]); - const [selectedPhotos, setSelectedPhotos] = useState([]); - const [isPhotobookExist, setIsPhotobookExist] = useState(false); - const router = useNavigate(); - - const handlePhotoClick = (index) => { - setSelectedPhotos((prevSelectedPhotos) => { - // 이미 선택된 사진이면 제거, 아니면 추가 - if (prevSelectedPhotos.includes(index)) { - const newSelectedPhotos = prevSelectedPhotos.filter( - (selectedIndex) => selectedIndex !== index - ); - console.log("삭제 후:", newSelectedPhotos); - return newSelectedPhotos; - } else { - const newSelectedPhotos = [...prevSelectedPhotos, index]; - console.log("추가 후:", newSelectedPhotos); - return newSelectedPhotos; - } - }); - }; - - useEffect(() => { - console.log("세팅 후:", selectedPhotos); - console.log( - "api 보내기전: ", - selectedPhotos.map((index) => getPhotos[index]) - ); - axios - .get("/photo") - .then((response) => { - setGetPhotos(response.data.photoList); - setIsPhotobookExist(response.data.present); - }) - .catch((error) => console.error(error)); - }, [selectedPhotos]); - - const handlePostData = async () => { - const data = { - name: "토리", - addPhotoList: selectedPhotos.map((index) => getPhotos[index]), - }; - - if (selectedPhotos.length === 0) { - // 선택된 사진이 없을 경우 알림 창 띄우기 - alert("사진을 선택해주세요."); - return; - } - else { - try { - const response = await axios.post("/photoBook", data); - console.log("API 응답:", response.data); - router("/photobook"); - } catch (error) { - console.error("API 오류:", error); - } - } - }; - - const checkPhotobook = () => { - router("/photobook"); - } - - return ( -
-
- {isPhotobookExist ? ( - - ) : ( - - )} -
-
-
- {/* 이미지 배열을 map 함수를 사용하여 렌더링 */} - {getPhotos.map((photo, index) => ( -
handlePhotoClick(index)} - className={styles.photoBox} - > - {`photo-${index}`} - {selectedPhotos.includes(index) && ( -
-
- {selectedPhotos.indexOf(index) + 1} -
-
- )} -
- ))} -
-
-
- ); -} +import React, { useState } from "react"; +import { useDrag } from "react-use-gesture"; +import { useSpring, animated } from "react-spring"; +import home from "../../img/home.png"; +import map from "../../img/map.png"; +import frame from "../../img/frame-line.png"; +import book from "../../img/book.png"; +import person from "../../img/person.png"; +import framelist from "../../img/framelist.png"; +import styles from "./PhotoSelect.module.scss"; +import Template from "../../component/MakeFrameCpn/Template"; +import FrameList from "../../component/AllFrameCpn/FrameList"; +import PhotoList from "./PhotoList"; +import { Link } from "react-router-dom"; + +export default function PhotoSelect() { + const [selectedButton, setSelectedButton] = useState("전체 포토"); + // const [logoPos, setlogoPos] = useState({ x: 0, y: 0 }); + const logoPos = useSpring({ x: 0, y: 0 }); + const bindLogoPos = useDrag((params) => { + // setlogoPos({ + // x: params.offset[0], + // y: params.offset[1], + // }); + logoPos.x.set(params.offset[0]); + logoPos.y.set(params.offset[1]); + }); + + const handleButtonClick = (button) => { + setSelectedButton(button); + }; + + let middleContent; + + switch (selectedButton) { + case "프레임 제작": + middleContent = ; + break; + case "포토북": + middleContent = ; + break; + default: + middleContent = ; + break; + } + + const topSpan = selectedButton === "프레임 제작" ? "Home" : "전체 포토"; + + return ( +
+
+ + + +
+ {topSpan} +
+
+ +
+
+
{middleContent}
+
+
+ + +
+
+
+ ); +} diff --git a/src/pages/Photobook/PhotoSelect.module.scss b/src/pages/Photobook/PhotoSelect.module.scss index b5b75bd..98ecf06 100644 --- a/src/pages/Photobook/PhotoSelect.module.scss +++ b/src/pages/Photobook/PhotoSelect.module.scss @@ -1,87 +1,123 @@ -.wrapper { - width: 100vw; - height: 100vh; - overflow-x: hidden; +.Frame { + width: 390px; + height: calc(var(--vh, 1vh) * 100); + background: #ffffff; display: flex; flex-direction: column; - gap: 30px; + justify-content: center; + user-select: none; } -.header { - width: 100vw; - height: 12vh; +.Top { + width: 100%; + height: 86px; display: flex; + flex-direction: row; + justify-content: space-between; align-items: center; +} + +.Top span { + flex: 1; + text-align: center; + font-size: 18px; + font-weight: 600; +} + +.Top button { + width: 24px; + height: 24px; + background-color: #ffffff; + border: none; + padding-left: 30px; + padding-right: 50px; +} + +.Center { + flex: 1; /* 가운데 영역이 남은 공간을 모두 차지하도록 설정 */ + text-align: center; /* 텍스트 가운데 정렬 */ +} + +.mylistBtn { + width: 47px; + height: 47px; + font-size: 10px; + background-color: #ffffff; + border-radius: 30px; + margin-left: auto; + border: none; +} + +.Middle { + width: 390px; + height: 689px; + display: flex; + flex-direction: column; justify-content: center; - background-color: white; - margin-top: 20px; - margin-bottom: 20px; - .inactive, .active { - height: 50px; - width: 340px; - border-radius: 10px; - border: 2px solid #009eff; - color: #009eff; - text-align: center; - font-size: 14px; - font-weight: 500; - background-color: white; - } - .active { - background-color: #009eff; - color: white; - } + align-items: center; + background-color: #ffffff; + gap: 13px; +} + +.Bottom { + width: 100%; + height: 70px; +} + +.ListTop { + height: 40px; + padding: 14px 14px 14px 18px; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + font-size: 10px; + font-weight: 400; +} + +.ListTop button { + background-color: #ffffff; +} + +.ListView { + display: inline-flex; + height: 160px; + padding: 15px 0px 15px 18px; + flex-direction: row; + gap: 18px; +} + +.ListView span { + width: 72px; + height: 130px; + border-radius: 10px; + background: #d9d9d9; } -.bodySection { - width: 100vw; - min-height: 673px; +.ListBottom { + width: 390px; + height: 70px; + background: #f7f8f8; display: flex; + flex-direction: row; + justify-content: space-evenly; + align-items: center; + gap: 20px; +} + +.ListBottom button { + display: flex; + flex-direction: column; justify-content: center; - .boxWrapper { - position: relative; - width: 340px; - min-height: 673px; - display: grid; - grid-template-columns: repeat(2, 1fr); /* 2열로 나열 */ - grid-template-rows: repeat(auto-fill, minmax(150px, 1fr)); - grid-gap: 20px; /* 각 요소 사이의 간격 설정 */ - } - .photoBox { - position: relative; - width: 160px; - height: 160px; - background-color: #f7f7f7; - img { - position: absolute; - z-index: 1; - height: 160px; - left: 26.22px; - width: auto; - } - .selectBox { - position: absolute; - z-index: 5; - width: 160px; - height: 160px; - background-color: rgba(255, 255, 255, 0.4); - border: 2.5px solid #009eff; - box-sizing: border-box; - display: flex; - flex-direction: row-reverse; - .selectNumber { - display: flex; - align-items: center; - justify-content: center; - width: 32px; - height: 32px; - color: white; - font-size: 14px; - font-weight: 600; - background-color: #009eff; - border-radius: 40px; - margin: 8px; - } - } - } + align-items: center; + text-align: center; + font-size: 10px; + font-weight: 400; + border: none; + background-color: #f7f8f8; +} + +.ListBottom button img { + width: 24px; + height: 24px; } diff --git a/src/pages/Photobook/PhotobookUuid.jsx b/src/pages/Photobook/PhotobookUuid.jsx index b27965e..2ebc179 100644 --- a/src/pages/Photobook/PhotobookUuid.jsx +++ b/src/pages/Photobook/PhotobookUuid.jsx @@ -342,9 +342,6 @@ export default function Photobook() {

쪽지 입력하기

-
- {navBottom} -
{/* 모달 */}
{memoModal}