Skip to content

Commit 1eaaa3a

Browse files
authored
Merge pull request #36 from DMU-DebugVisual/sunwoong
UI 개선: 로그인/회원가입 페이지 수정 및 커뮤니티 디자인 개선
2 parents 9dff04f + bb639cd commit 1eaaa3a

File tree

10 files changed

+389
-185
lines changed

10 files changed

+389
-185
lines changed

src/App.js

Lines changed: 42 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { HashRouter, Route, Routes } from "react-router-dom";
2-
import { useState, useEffect } from "react";
1+
import { HashRouter, Routes, Route, useLocation } from "react-router-dom";
2+
import { useEffect, useState } from "react";
33

44
import Header from "./components/header/Header";
55
import Footer from "./components/footer/Footer";
@@ -17,65 +17,32 @@ import Shared from "./components/mypage/Shared";
1717
import MyProject from "./components/mypage/MyProject";
1818
import MyCommunity from "./components/mypage/MyCommunity";
1919
import ScrollToTop from "./components/common/ScrollToTop";
20+
import CommunityWrite from "./components/community/CommunityWrite";
2021

21-
function App() {
22+
function AppContent() {
23+
const location = useLocation();
2224
const [isDark, setIsDark] = useState(false);
23-
24-
// 로그인 상태 관리 추가
2525
const [isLoggedIn, setIsLoggedIn] = useState(false);
2626
const [nickname, setNickname] = useState('');
27+
const [isLoginModalOpen, setIsLoginModalOpen] = useState(false);
28+
29+
const isSignupPage = location.pathname === "/signup";
2730

28-
// 로그인 상태 확인
2931
useEffect(() => {
3032
const token = localStorage.getItem('token');
3133
const storedUsername = localStorage.getItem('username');
32-
33-
console.log('🔍 App.js 로그인 상태 확인:', { token: !!token, username: storedUsername });
34-
3534
if (token && storedUsername) {
3635
setIsLoggedIn(true);
3736
setNickname(storedUsername);
38-
console.log('✅ App.js에서 로그인 상태로 설정됨');
3937
} else {
4038
setIsLoggedIn(false);
4139
setNickname('');
42-
console.log('❌ App.js에서 비로그인 상태로 설정됨');
4340
}
4441
}, []);
4542

46-
// 로그인 상태 변경을 감지하기 위한 이벤트 리스너 (선택사항)
47-
useEffect(() => {
48-
const handleStorageChange = () => {
49-
const token = localStorage.getItem('token');
50-
const storedUsername = localStorage.getItem('username');
51-
52-
if (token && storedUsername) {
53-
setIsLoggedIn(true);
54-
setNickname(storedUsername);
55-
} else {
56-
setIsLoggedIn(false);
57-
setNickname('');
58-
}
59-
};
60-
61-
// storage 이벤트 리스너 추가
62-
window.addEventListener('storage', handleStorageChange);
63-
64-
// 클린업
65-
return () => {
66-
window.removeEventListener('storage', handleStorageChange);
67-
};
68-
}, []);
69-
70-
useEffect(() => {
71-
document.body.classList.toggle("dark-mode", isDark);
72-
}, [isDark]);
73-
7443
useEffect(() => {
7544
const savedTheme = localStorage.getItem("theme");
76-
if (savedTheme === "dark") {
77-
setIsDark(true);
78-
}
45+
if (savedTheme === "dark") setIsDark(true);
7946
}, []);
8047

8148
useEffect(() => {
@@ -84,29 +51,29 @@ function App() {
8451
}, [isDark]);
8552

8653
return (
87-
<HashRouter>
88-
<Header
89-
isDark={isDark}
90-
setIsDark={setIsDark}
91-
isLoggedIn={isLoggedIn}
92-
nickname={nickname}
93-
/>
54+
<>
55+
{!isSignupPage && (
56+
<Header
57+
isDark={isDark}
58+
setIsDark={setIsDark}
59+
isLoggedIn={isLoggedIn}
60+
nickname={nickname}
61+
onLoginModalOpen={() => setIsLoginModalOpen(true)}
62+
/>
63+
)}
64+
9465
<ScrollToTop />
66+
9567
<Routes>
9668
<Route path="/" element={<Main />} />
97-
<Route path="/login" element={<Login />} />
9869
<Route path="/signup" element={<SignUp />} />
99-
100-
{/* IDE 라우팅 설정 */}
10170
<Route path="/ide" element={<IDE />} />
10271
<Route path="/ide/:param" element={<IDE />} />
10372
<Route path="/ide/:language/:filename" element={<IDE />} />
104-
10573
<Route path="/community" element={<Community />} />
74+
<Route path="/community/write" element={<CommunityWrite />} />
10675
<Route path="/broadcast" element={<Codecast />} />
10776
<Route path="/startbroadcast" element={<StartCodecast />} />
108-
109-
{/* MyPage 라우팅 설정 */}
11077
<Route path="/mypage" element={<MyPageLayout nickname={nickname} />}>
11178
<Route index element={<Mypage nickname={nickname} />} />
11279
<Route path="project" element={<MyProject />} />
@@ -115,9 +82,26 @@ function App() {
11582
<Route path="shared" element={<Shared />} />
11683
</Route>
11784
</Routes>
118-
<Footer />
119-
</HashRouter>
85+
86+
{!isSignupPage && <Footer />}
87+
88+
{isLoginModalOpen && (
89+
<Login
90+
onClose={() => setIsLoginModalOpen(false)}
91+
onLoginSuccess={() => {
92+
setIsLoggedIn(true);
93+
setNickname(localStorage.getItem('username') || '');
94+
}}
95+
/>
96+
)}
97+
</>
12098
);
12199
}
122100

123-
export default App;
101+
export default function App() {
102+
return (
103+
<HashRouter>
104+
<AppContent />
105+
</HashRouter>
106+
);
107+
}

src/components/community/Community.css

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ body {
66
}
77

88
.community-container {
9-
max-width: 900px;
9+
max-width: 1400px; /* 또는 100%, 1000px 등 */
1010
margin: 0 auto;
1111
padding: 80px 20px;
1212
}
@@ -33,6 +33,7 @@ body {
3333
font-size: 1.25rem; /* 글씨 키움 */
3434
cursor: pointer;
3535
transition: background-color 0.3s;
36+
3637
}
3738

3839

@@ -59,7 +60,7 @@ body {
5960
padding: 1rem 2rem 3rem 2rem; /* 위 여백을 1.5rem으로 줄임 */
6061
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
6162
margin-bottom: 2rem;
62-
width: 97.5%;
63+
width: 100%;
6364
min-height: 600px;
6465
}
6566

@@ -90,7 +91,7 @@ body {
9091
}
9192

9293
.popular-post-card h3 {
93-
font-size: 1.5rem;
94+
font-size: 1.25rem;
9495
font-weight: bold;
9596
margin: 0 0 0.5rem 0;
9697
}

src/components/community/Community.jsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import React from "react";
2+
import { useNavigate } from "react-router-dom"; // ✅ navigate import 추가
23
import "./Community.css";
34

45
export default function Community() {
6+
const navigate = useNavigate(); // ✅ navigate 선언
7+
58
const posts = [
69
{
710
title: "버블 정렬 시각화 프로젝트 공유합니다",
@@ -11,7 +14,7 @@ export default function Community() {
1114
date: "2023. 5. 15",
1215
likes: 24,
1316
comments: 8,
14-
thumbnail: "https://via.placeholder.com/300x180"
17+
thumbnail: "https://unsplash.com/photos/KrYbarbAx5s/download?ixid=M3wxMjA3fDB8MXxzZWFyY2h8MTZ8fCVFQiU5NCU5NCVFQiVCMiU4NCVFQSVCOSU4NXxrb3wwfHx8fDE3NDgyNDc1NDh8MA&force=true"
1518
},
1619
{
1720
title: "그래프 탐색 알고리즘 비교: BFS vs DFS",
@@ -21,7 +24,7 @@ export default function Community() {
2124
date: "2023. 5. 17",
2225
likes: 32,
2326
comments: 12,
24-
thumbnail: "https://via.placeholder.com/300x180"
27+
thumbnail: "https://images.unsplash.com/photo-1526374965328-7f61d4dc18c5?auto=format&fit=crop&w=300&h=180"
2528
},
2629
{
2730
title: "동적 프로그래밍 문제 해결 가이드",
@@ -31,15 +34,21 @@ export default function Community() {
3134
date: "2023. 5. 18",
3235
likes: 40,
3336
comments: 15,
34-
thumbnail: "https://via.placeholder.com/300x180"
37+
thumbnail: "https://unsplash.com/photos/ZS67i1HLllo/download?ixid=M3wxMjA3fDB8MXxzZWFyY2h8MTV8fCVFQiU4RiU5OSVFQyVBMCU4MSUyMCVFRCU5NCU4NCVFQiVBMSU5QyVFQSVCNyVCOCVFQiU5RSU5OCVFQiVCMCU4RCUyMCVFRCU5NSVCNCVFQSVCMiVCMCUyMCVFQSVCMCU4MCVFQyU5RCVCNCVFQiU5MyU5Q3xrb3wwfHx8fDE3NDgyNDc3NjB8MA&force=true"
3538
}
3639
];
3740

41+
3842
return (
3943
<div className="community-container">
4044
<div className="community-header">
4145
<h1>커뮤니티</h1>
42-
<button className="new-post-button">+ 새 게시물</button>
46+
<button
47+
className="new-post-button"
48+
onClick={() => navigate("/community/write")}
49+
>
50+
+ 새 게시물
51+
</button>
4352
</div>
4453

4554
<div className="popular-posts-wrapper">
@@ -86,7 +95,7 @@ export default function Community() {
8695
<p>{post.summary}</p>
8796
<div className="post-footer">
8897
<div className="author-info">
89-
<img src="https://via.placeholder.com/32" alt="작성자" />
98+
<img src="https://cdn-icons-png.flaticon.com/512/847/847969.png" alt="작성자" width="32" height="32" />
9099
<div>
91100
<p>{post.author}</p>
92101
<p className="date">{post.date}</p>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
.write-container {
2+
max-width: 1000px;
3+
width: 100%;
4+
margin: 100px auto 120px auto; /* ✅ 위아래 여백 + 가운데 정렬 */
5+
padding: 2rem;
6+
background: white;
7+
border-radius: 8px;
8+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
9+
font-family: 'Noto Sans KR', sans-serif;
10+
}
11+
12+
13+
.write-form label {
14+
display: block;
15+
margin-bottom: 1.5rem;
16+
font-weight: bold;
17+
}
18+
19+
.write-form input,
20+
.write-form textarea {
21+
width: 100%;
22+
padding: 0.75rem;
23+
margin-top: 0.5rem;
24+
border: 1px solid #ccc;
25+
border-radius: 6px;
26+
font-size: 1rem;
27+
font-family: inherit;
28+
}
29+
30+
.submit-button {
31+
background-color: #845ef7;
32+
color: white;
33+
padding: 0.75rem 2rem;
34+
border: none;
35+
border-radius: 6px;
36+
font-size: 1.1rem;
37+
cursor: pointer;
38+
}
39+
40+
.submit-button:hover {
41+
background-color: #6f4fd5;
42+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import React, { useState } from "react";
2+
import "./CommunityWrite.css";
3+
import { useNavigate } from "react-router-dom";
4+
5+
const CommunityWrite = () => {
6+
const navigate = useNavigate();
7+
const [title, setTitle] = useState("");
8+
const [content, setContent] = useState("");
9+
const [tags, setTags] = useState("");
10+
11+
const handleSubmit = (e) => {
12+
e.preventDefault();
13+
14+
// 임시 처리: 콘솔에 출력
15+
console.log("제목:", title);
16+
console.log("내용:", content);
17+
console.log("태그:", tags.split(',').map(tag => tag.trim()));
18+
19+
// 추후 API로 전송하거나, 목록에 추가
20+
alert("작성 완료!");
21+
navigate("/community");
22+
};
23+
24+
return (
25+
<div className="write-container">
26+
<h2>📌 새 게시물 작성</h2>
27+
<form className="write-form" onSubmit={handleSubmit}>
28+
<label>
29+
제목
30+
<input
31+
type="text"
32+
value={title}
33+
onChange={(e) => setTitle(e.target.value)}
34+
required
35+
/>
36+
</label>
37+
<label>
38+
내용
39+
<textarea
40+
value={content}
41+
onChange={(e) => setContent(e.target.value)}
42+
rows="10"
43+
required
44+
/>
45+
</label>
46+
<label>
47+
태그 (쉼표로 구분)
48+
<input
49+
type="text"
50+
value={tags}
51+
onChange={(e) => setTags(e.target.value)}
52+
/>
53+
</label>
54+
<button type="submit" className="submit-button">작성하기</button>
55+
</form>
56+
</div>
57+
);
58+
};
59+
60+
export default CommunityWrite;

0 commit comments

Comments
 (0)