From cdb57ba2e991f21b3b60e66d50226266473deed5 Mon Sep 17 00:00:00 2001 From: kevinmj12 Date: Tue, 19 Nov 2024 16:58:34 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat/#14/=EC=9D=B4=EB=AF=B8=EC=A7=80=20?= =?UTF-8?q?=EB=B6=99=EC=97=AC=EB=84=A3=EA=B8=B0=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MDEditor/mdeditor-styles.module.css | 29 +++++++++ src/components/newpost/MDEditor/mdeditor.tsx | 62 +++++++++++++++++++ src/components/newpost/mdeditor.tsx | 22 ------- src/components/newpost/newpost.tsx | 2 +- .../api/NewPost/mdeditor-image-upload.ts | 38 ++++++++++++ 5 files changed, 130 insertions(+), 23 deletions(-) create mode 100644 src/components/newpost/MDEditor/mdeditor-styles.module.css create mode 100644 src/components/newpost/MDEditor/mdeditor.tsx delete mode 100644 src/components/newpost/mdeditor.tsx create mode 100644 src/pages/api/NewPost/mdeditor-image-upload.ts diff --git a/src/components/newpost/MDEditor/mdeditor-styles.module.css b/src/components/newpost/MDEditor/mdeditor-styles.module.css new file mode 100644 index 0000000..6b2da0e --- /dev/null +++ b/src/components/newpost/MDEditor/mdeditor-styles.module.css @@ -0,0 +1,29 @@ +.w-md-editor { + height: 600px !important; + @media (max-width: 695px) { + height: 640px !important; + } +} + +.w-md-editor-toolbar { + height: 40px !important; + @media (max-width: 695px) { + height: 80px !important; + } +} +.w-md-editor-toolbar-divider { + margin: 0px 0px 0px 0px !important; + height: 25px !important; +} + +.w-md-editor-content { + height: 560px !important; +} + +.w-md-editor .w-md-editor-text { + font-size: 20px !important; + line-height: 26px !important; +} +.wmde-markdown { + font-size: 20px !important; +} diff --git a/src/components/newpost/MDEditor/mdeditor.tsx b/src/components/newpost/MDEditor/mdeditor.tsx new file mode 100644 index 0000000..258d189 --- /dev/null +++ b/src/components/newpost/MDEditor/mdeditor.tsx @@ -0,0 +1,62 @@ +import "@uiw/react-md-editor/markdown-editor.css"; +import "@uiw/react-markdown-preview/markdown.css"; +import { uploadImage } from "@/pages/api/NewPost/mdeditor-image-upload"; +import dynamic from "next/dynamic"; +import { useState } from "react"; + +const MDEditor = dynamic(() => import("@uiw/react-md-editor"), { ssr: false }); + +function MdEditor() { + const [value, setValue] = useState("**프로젝트 소개를 입력하세요**"); + const [loading, setLoading] = useState(false); + + const handleChange = (text?: string) => { + const updatedText = text || ""; + setValue(updatedText); + }; + + const handlePaste = async (event: React.ClipboardEvent) => { + const clipboardData = event.clipboardData; + if (!clipboardData) { + return; + } + + const clipboardItems = clipboardData.items; + + console.log(clipboardItems); + + if (clipboardItems[0].type.startsWith("image/")) { + const file = clipboardItems[0].getAsFile(); + + if (file) { + setLoading(true); + const imageUrl = await uploadImage(file); + if (imageUrl) { + setValue( + (prev) => + prev + + `\n![image](https://www.kookmin.ac.kr/content/05sub/style0005/images/sub/ui_5_col_image_2.jpg)\n` + ); + } + setLoading(false); + } + } + }; + + return ( +
+ +
+ ); +} + +export default MdEditor; diff --git a/src/components/newpost/mdeditor.tsx b/src/components/newpost/mdeditor.tsx deleted file mode 100644 index de5167c..0000000 --- a/src/components/newpost/mdeditor.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import "@uiw/react-md-editor/markdown-editor.css"; -import "@uiw/react-markdown-preview/markdown.css"; -import dynamic from "next/dynamic"; -import { useState } from "react"; - -const MDEditor = dynamic(() => import("@uiw/react-md-editor"), { ssr: false }); - -function MdEditor() { - const [value, setValue] = useState("**프로젝트 소개를 입력하세요**"); - - const handleChange = (val?: string) => { - setValue(val ?? ""); - }; - - return ( -
- -
- ); -} - -export default MdEditor; diff --git a/src/components/newpost/newpost.tsx b/src/components/newpost/newpost.tsx index 3050951..4f3e938 100644 --- a/src/components/newpost/newpost.tsx +++ b/src/components/newpost/newpost.tsx @@ -1,6 +1,6 @@ import * as Style from "./styles"; import SelectStackType from "../SelectStackType/selectStackType"; -import NewpostEditor from "./mdeditor"; +import NewpostEditor from "./MDEditor/mdeditor"; import { useEffect, useRef, useState } from "react"; import NewpostImages from "./ImageUpload/image-upload"; import { useAppDispatch } from "@/stores"; diff --git a/src/pages/api/NewPost/mdeditor-image-upload.ts b/src/pages/api/NewPost/mdeditor-image-upload.ts new file mode 100644 index 0000000..344e8bd --- /dev/null +++ b/src/pages/api/NewPost/mdeditor-image-upload.ts @@ -0,0 +1,38 @@ +const delay = (ms: number) => { + return new Promise((resolve) => setTimeout(resolve, ms)); +}; + +// 사용 예시 +const runWithDelay = async () => { + console.log("대기 시작"); + await delay(2000); // 2초 대기 + console.log("2초 후 실행"); +}; + +export const uploadImage = async (file: File) => { + try { + const formData = new FormData(); + formData.append("file", file); + + // 예: 서버로 업로드 요청 + // const response = await fetch("https://your-server.com/upload", { + // method: "POST", + // body: formData, + // }); + + // if (response.ok) { + // const result = await response.json(); + // return result.url; // 업로드된 이미지 URL 반환 + // } else { + // console.error("Image upload failed"); + // return null; + // } + + await runWithDelay(); + + return "https://www.kookmin.ac.kr/content/05sub/style0005/images/sub/ui_5_col_image_2.jpg"; + } catch (error) { + console.error("Error uploading image:", error); + return null; + } +}; From 820de21ecabde26ea5f5915b6ab6708267210dc1 Mon Sep 17 00:00:00 2001 From: jihunchoi Date: Sat, 23 Nov 2024 14:47:15 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat/#11-=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 105 ++++++++++++++++++++++- package.json | 4 +- public/icons/user.svg | 3 + src/components/LoginModal/LoginModel.tsx | 24 ++++++ src/components/Navigation/Navigation.tsx | 51 ++++++++++- src/components/Navigation/styles.ts | 1 + src/pages/api/hello.ts | 13 --- src/pages/api/login.ts | 5 ++ src/pages/api/logout.ts | 5 ++ src/services/auth.ts | 13 +++ src/stores/authStore.ts | 15 ++++ 11 files changed, 218 insertions(+), 21 deletions(-) create mode 100644 public/icons/user.svg delete mode 100644 src/pages/api/hello.ts create mode 100644 src/pages/api/login.ts create mode 100644 src/pages/api/logout.ts create mode 100644 src/services/auth.ts create mode 100644 src/stores/authStore.ts diff --git a/package-lock.json b/package-lock.json index dd80a5f..ffc8418 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,13 +12,15 @@ "@emotion/styled": "^11.13.0", "@reduxjs/toolkit": "^2.2.8", "@uiw/react-md-editor": "^3.6.0", + "axios": "^1.7.7", "next": "^14.2.14", "next-remove-imports": "^1.0.12", "polished": "^4.3.1", "react": "^18", "react-dom": "^18", "react-icons": "^5.3.0", - "react-redux": "^9.1.2" + "react-redux": "^9.1.2", + "zustand": "^5.0.1" }, "devDependencies": { "@types/node": "^20", @@ -1765,6 +1767,11 @@ "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", "dev": true }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -1789,6 +1796,16 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -2073,6 +2090,17 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", @@ -2309,6 +2337,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -3162,6 +3198,25 @@ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -3187,6 +3242,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -5408,7 +5476,6 @@ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -5418,7 +5485,6 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", - "peer": true, "dependencies": { "mime-db": "1.52.0" }, @@ -6059,6 +6125,11 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -8165,6 +8236,34 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zustand": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.1.tgz", + "integrity": "sha512-pRET7Lao2z+n5R/HduXMio35TncTlSW68WsYBq2Lg1ASspsNGjpwLAsij3RpouyV6+kHMwwwzP0bZPD70/Jx/w==", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/package.json b/package.json index 1bb2736..35145f6 100644 --- a/package.json +++ b/package.json @@ -14,13 +14,15 @@ "@emotion/styled": "^11.13.0", "@reduxjs/toolkit": "^2.2.8", "@uiw/react-md-editor": "^3.6.0", + "axios": "^1.7.7", "next": "^14.2.14", "next-remove-imports": "^1.0.12", "polished": "^4.3.1", "react": "^18", "react-dom": "^18", "react-icons": "^5.3.0", - "react-redux": "^9.1.2" + "react-redux": "^9.1.2", + "zustand": "^5.0.1" }, "devDependencies": { "@types/node": "^20", diff --git a/public/icons/user.svg b/public/icons/user.svg new file mode 100644 index 0000000..af388cb --- /dev/null +++ b/public/icons/user.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/LoginModal/LoginModel.tsx b/src/components/LoginModal/LoginModel.tsx index 9649d74..2281544 100644 --- a/src/components/LoginModal/LoginModel.tsx +++ b/src/components/LoginModal/LoginModel.tsx @@ -3,6 +3,8 @@ import * as S from "./styles"; import close from "../../../public/icons/close.svg"; import chevron_left from "../../../public/icons/chevron_left.svg"; import Image from "next/image"; +import { useAuthStore } from "@/stores/authStore"; +import { login } from "@/services/auth"; interface ModalProps { onClose: () => void; @@ -17,11 +19,25 @@ interface ModalProps { const Modal: React.FC = ({ onClose, initialStep = "main" }) => { const [modalStep, setModalStep] = useState(initialStep); + const { login: setLoginState } = useAuthStore(); useEffect(() => { setModalStep(initialStep); }, [initialStep]); + const handleLogin = async (e: React.FormEvent) => { + e.preventDefault(); + try { + const user = await login("email", "password"); + setLoginState(user); + console.log(user); + alert("로그인 성공!"); + } catch (error) { + console.error(error); + alert("로그인 실패!"); + } + }; + const handleBackdropClick = (event: React.MouseEvent) => { if (event.target === event.currentTarget) { onClose(); @@ -78,6 +94,14 @@ const Modal: React.FC = ({ onClose, initialStep = "main" }) => { > 이메일로 로그인 + + 로그인 테스트 + diff --git a/src/components/Navigation/Navigation.tsx b/src/components/Navigation/Navigation.tsx index 9e27361..b279430 100644 --- a/src/components/Navigation/Navigation.tsx +++ b/src/components/Navigation/Navigation.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { LoginText, SignUpButton, @@ -13,11 +13,32 @@ import { import LoginModal from "../LoginModal/LoginModel"; import hamburger from "../../../public/icons/hamburger.svg"; import Image from "next/image"; +import { useAuthStore } from "@/stores/authStore"; +import userIcon from "../../../public/icons/user.svg"; +import { logout } from "@/services/auth"; const Navigation: React.FC = () => { const [isModalOpen, setIsModalOpen] = useState(false); const [isMenuOpen, setIsMenuOpen] = useState(false); const [initialStep, setInitialStep] = useState<"main" | "signup">("main"); + const { isLoggedIn, logout: clearAuthState } = useAuthStore(); + + useEffect(() => { + if (isLoggedIn) { + setIsModalOpen(false); + } + }, [isLoggedIn]); + + const handleLogout = async () => { + try { + await logout(); + clearAuthState(); + alert("로그아웃 성공!"); + } catch (error) { + console.error(error); + alert("로그아웃 실패!"); + } + }; const handleOpenLoginModal = () => { setInitialStep("main"); @@ -67,9 +88,31 @@ const Navigation: React.FC = () => { -
- 로그인 - 회원가입 +
+ {isLoggedIn ? ( +
+ 로그아웃 + mypage +
+ ) : ( + <> + 로그인 + + 회원가입 + + + )}
{isMenuOpen && ( <> diff --git a/src/components/Navigation/styles.ts b/src/components/Navigation/styles.ts index a617847..dae5d72 100644 --- a/src/components/Navigation/styles.ts +++ b/src/components/Navigation/styles.ts @@ -11,6 +11,7 @@ export const NavContainer = styled.nav` position: sticky; top: 0; width: 100%; + height: 80px; z-index: 1000; justify-content: space-between; diff --git a/src/pages/api/hello.ts b/src/pages/api/hello.ts deleted file mode 100644 index ea77e8f..0000000 --- a/src/pages/api/hello.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Next.js API route support: https://nextjs.org/docs/api-routes/introduction -import type { NextApiRequest, NextApiResponse } from "next"; - -type Data = { - name: string; -}; - -export default function handler( - req: NextApiRequest, - res: NextApiResponse, -) { - res.status(200).json({ name: "John Doe" }); -} diff --git a/src/pages/api/login.ts b/src/pages/api/login.ts new file mode 100644 index 0000000..0fc55ed --- /dev/null +++ b/src/pages/api/login.ts @@ -0,0 +1,5 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +export default function handler(req: NextApiRequest, res: NextApiResponse) { + res.status(200).json({ id: "QWE", name: "ASD" }); +} diff --git a/src/pages/api/logout.ts b/src/pages/api/logout.ts new file mode 100644 index 0000000..0fc55ed --- /dev/null +++ b/src/pages/api/logout.ts @@ -0,0 +1,5 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +export default function handler(req: NextApiRequest, res: NextApiResponse) { + res.status(200).json({ id: "QWE", name: "ASD" }); +} diff --git a/src/services/auth.ts b/src/services/auth.ts new file mode 100644 index 0000000..6264b5b --- /dev/null +++ b/src/services/auth.ts @@ -0,0 +1,13 @@ +import axios from "axios"; + +const BASE_URL = "/api"; +// const BASE_URL = "백엔드 api"; + +export const login = async (email: string, password: string) => { + const response = await axios.post(`${BASE_URL}/login`, { email, password }); + return response.data; +}; + +export const logout = async () => { + await axios.post(`${BASE_URL}/logout`); +}; diff --git a/src/stores/authStore.ts b/src/stores/authStore.ts new file mode 100644 index 0000000..7b32f82 --- /dev/null +++ b/src/stores/authStore.ts @@ -0,0 +1,15 @@ +import { create } from "zustand"; + +interface AuthState { + isLoggedIn: boolean; + user: { id: string; name: string } | null; + login: (user: { id: string; name: string }) => void; + logout: () => void; +} + +export const useAuthStore = create((set) => ({ + isLoggedIn: false, + user: null, + login: (user) => set({ isLoggedIn: true, user }), + logout: () => set({ isLoggedIn: false, user: null }), +})); From 18108960c238480aeb4fa8cf0c4311cc3cf3c4a8 Mon Sep 17 00:00:00 2001 From: Jihun Choi Date: Sat, 30 Nov 2024 17:02:38 +0900 Subject: [PATCH 3/4] test --- src/data/cardDummyDatas.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/cardDummyDatas.ts b/src/data/cardDummyDatas.ts index 2b29ab3..cdfc14d 100644 --- a/src/data/cardDummyDatas.ts +++ b/src/data/cardDummyDatas.ts @@ -4,7 +4,7 @@ const dummyData = Array.from({ length: 100 }, (_, index) => ({ "https://velog.velcdn.com/images/yena1025/post/295eb434-5b73-421f-bbe4-6bc13acd4c33/image.png", title: `프로젝트 ${index + 1}`, description: "외국인 유학생을 위한 앱", - likes: 123 + index, + likes: 124 + index, author: "캡스톤 30조", })); From d67c3d7bd9279995da4ceaec841f5cac9c3c27c1 Mon Sep 17 00:00:00 2001 From: kevinmj12 Date: Mon, 16 Dec 2024 11:40:25 +0900 Subject: [PATCH 4/4] =?UTF-8?q?feat/#14-mdeditor=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Newpost/ImageUpload/ImageUpload.tsx | 8 ++--- src/components/Newpost/MDEditor/styles.ts | 4 --- src/components/Newpost/styles.ts | 2 +- src/components/newpost/MDEditor/mdeditor.tsx | 29 +++++++------------ 4 files changed, 15 insertions(+), 28 deletions(-) diff --git a/src/components/Newpost/ImageUpload/ImageUpload.tsx b/src/components/Newpost/ImageUpload/ImageUpload.tsx index 73769e5..2016c99 100644 --- a/src/components/Newpost/ImageUpload/ImageUpload.tsx +++ b/src/components/Newpost/ImageUpload/ImageUpload.tsx @@ -11,8 +11,8 @@ export default function UploadBox() { const [showModal, setShowModal] = useState(false); const [selectedImage, setSelectedImage] = useState(null); - const handleDragStart = () => setActive(true); - const handleDragEnd = (event: React.DragEvent) => { + const handleDragEnter = () => setActive(true); + const handleDragLeave = (event: React.DragEvent) => { // 드래그가 완전히 벗어난 경우에만 setActive(false)를 호출 if (!event.currentTarget.contains(event.relatedTarget as Node)) { setActive(false); @@ -113,9 +113,9 @@ export default function UploadBox() { ))} diff --git a/src/components/Newpost/MDEditor/styles.ts b/src/components/Newpost/MDEditor/styles.ts index 90048b2..08409ad 100644 --- a/src/components/Newpost/MDEditor/styles.ts +++ b/src/components/Newpost/MDEditor/styles.ts @@ -1,7 +1,5 @@ import styled from "@emotion/styled"; -const lightgrey = "#d7e2eb"; - interface DragProps { isActive: boolean; } @@ -10,6 +8,4 @@ export const ImageDragDiv = styled.div` align-items: center; border-radius: 5px; - background-color: ${({ isActive }) => (isActive ? lightgrey : "white")}; - opacity: ${({ isActive }) => (isActive ? "0.3" : "1.0")}; `; diff --git a/src/components/Newpost/styles.ts b/src/components/Newpost/styles.ts index 0396013..e247a55 100644 --- a/src/components/Newpost/styles.ts +++ b/src/components/Newpost/styles.ts @@ -5,7 +5,7 @@ const lightgrey = "#d7e2eb"; const grey = "#b2c0cc"; export const NewpostContainer = styled.div` - max-width: 800px; + max-width: 1200px; min-height: 100svh; align-items: center; padding: 20px 20px 20px 20px; diff --git a/src/components/newpost/MDEditor/mdeditor.tsx b/src/components/newpost/MDEditor/mdeditor.tsx index e832da2..c6e308d 100644 --- a/src/components/newpost/MDEditor/mdeditor.tsx +++ b/src/components/newpost/MDEditor/mdeditor.tsx @@ -3,7 +3,7 @@ import "@uiw/react-markdown-preview/markdown.css"; import Spinners from "@/components/Common/Spinners"; import { uploadImage } from "@/pages/api/NewPost/mdeditor-image-upload"; import dynamic from "next/dynamic"; -import { useCallback, useState } from "react"; +import { useState } from "react"; import * as Style from "./styles"; const MDEditor = dynamic(() => import("@uiw/react-md-editor"), { ssr: false }); @@ -22,13 +22,9 @@ function MdEditor() { setIsActive(false); } }; - const handleDragOver = useCallback( - (event: React.DragEvent) => { - event.preventDefault(); - event.stopPropagation(); - }, - [] - ); + const handleDragOver = (event: React.DragEvent) => { + event.preventDefault(); + }; const handleDrop = (event: React.DragEvent) => { event.preventDefault(); @@ -47,8 +43,9 @@ function MdEditor() { if (imageUrl) { setValue( (prev) => - prev + - `\n![image](https://www.kookmin.ac.kr/content/05sub/style0005/images/sub/ui_5_col_image_3.jpg)\n` + prev.substring(0, cursorPosition) + + `\n![image](https://www.kookmin.ac.kr/content/05sub/style0005/images/sub/ui_5_col_image_3.jpg)\n` + + prev.substring(cursorPosition) ); } setLoading(false); @@ -133,18 +130,12 @@ function MdEditor() { onPaste={handlePaste} textareaProps={{ onFocus: handleFocus, - onSelect: handleSelect, // 텍스트 선택 시 커서 위치 추적 - onMouseUp: handleMouseUp, // 마우스 클릭 시 커서 위치 추적 - onKeyUp: handleKeyUp, // 방향키로 커서 이동 시 커서 위치 추적 + onSelect: handleSelect, + onMouseUp: handleMouseUp, + onKeyUp: handleKeyUp, disabled: loading, }} - style={{ - pointerEvents: loading ? "none" : "auto", - opacity: loading ? 0.3 : 1, - backgroundColor: "#ffffff", - }} /> - {loading && (