navigate(`/sessions/${sessionId}/questions/${question.questionId}`)}>
{/* 질문 헤더 */}
@@ -902,7 +885,7 @@ function QnAListPage() {
placeholder="댓글을 입력해주세요..."
value={commentInputs[question.questionId] || ''}
onChange={e => handleCommentChange(question.questionId, e.target.value)}
- onKeyDown={e => { if (e.key === 'Enter') handleCommentSubmit(e, question.questionId); }}
+ onKeyDown={e => { if (e.key === 'Enter' && !e.nativeEvent.isComposing) handleCommentSubmit(e, question.questionId); }}
onPaste={e => handleCommentPaste(e, question.questionId)}
autoFocus
/>
@@ -960,7 +943,7 @@ function QnAListPage() {
value={newQuestion}
onChange={e => setNewQuestion(e.target.value)}
onKeyDown={e => {
- if (e.key === 'Enter') isStaff ? handleNewUnderstandCheck() : handleNewQuestion();
+ if (e.key === 'Enter' && !e.nativeEvent.isComposing) isStaff ? handleNewUnderstandCheck() : handleNewQuestion();
}}
onPaste={handleNewQuestionPaste}
disabled={isSubmitting}
diff --git a/frontend/src/pages/qna/QnAListPage.module.css b/frontend/src/pages/qna/QnAListPage.module.css
index 95ffedf..10ea886 100644
--- a/frontend/src/pages/qna/QnAListPage.module.css
+++ b/frontend/src/pages/qna/QnAListPage.module.css
@@ -1,5 +1,11 @@
/* ── 페이지 레이아웃 ── */
+/* .pageWrapper {
+ background: var(--gray50);
+ min-height: 100vh;
+} */
+
.page {
+ /* background: var(--gray50); */
display: flex;
flex-direction: column;
min-height: 100vh;
@@ -19,6 +25,7 @@
margin: 10px;
color: var(--black);
padding-top: 60px;
+ padding-bottom: 40px;
font-weight: 700;
line-height: normal;
}
@@ -108,17 +115,20 @@
/* ── 이해도 바 ── */
.understandBar {
+ padding: 8px 16px;
margin-top: 20px;
- margin-bottom: 20px;
+ margin-bottom: 30px;
display: flex;
align-items: center;
justify-content: space-between;
+ gap: 10px;
border-radius: 10px;
border: 1px solid var(--dark);
background: var(--white);
- box-shadow: 1px 2px 3px 0 rgba(0, 0, 0, 0.25);
+ box-shadow: none;
width: 100%;
- height: 56px;
+ min-height: 56px;
+ padding: 10px 16px;
box-sizing: border-box;
}
@@ -129,6 +139,8 @@
color: var(--gray600);
display: flex;
align-items: center;
+ align-self: center;
+ flex-shrink: 0;
padding: 0;
line-height: 1;
}
@@ -145,12 +157,18 @@
font-size: 24px;
font-weight: 500;
color: var(--black);
+ /* padding: 12px */
+}
+
+.longText {
+ font-size: 19px;
}
.understandCount {
font-weight: 300;
color: var(--black);
font-size: 18px;
+ white-space: nowrap;
}
/* ── O/X 버튼 ── */
@@ -207,18 +225,35 @@
}
.questionCard {
- padding: 14px 16px;
+ padding: 16px 18px;
cursor: pointer;
transition: box-shadow 0.2s;
- border-radius: 30px;
+ border-radius: 20px;
background: var(--white);
- box-shadow: 1px 2px 3px 0 rgba(0, 0, 0, 0.25);
+ box-shadow:
+ 0 1px 4px rgba(0,0,0,0.06),
+ 0 0 0 1px rgba(0,0,0,0.03);
width: 95%;
box-sizing: border-box;
min-height: 40px;
}
+/* 해결된 질문: 미해결 질문과 한눈에 구분되도록 배경을 연한 회색으로 + 카드 전체를 흐리게 처리 (초록 테두리는 미해결 질문 전용이므로 제외) */
+.questionCardResolved {
+ background: var(--gray50);
+ opacity: 0.6;
+ border-color: transparent;
+ box-shadow:
+ 0 1px 4px rgba(0,0,0,0.06),
+ 0 0 0 1px rgba(0,0,0,0.03);
+}
+
.questionCard:hover {
+ transform: translateY(-1px);
+ box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.15);
+}
+
+.questionCardResolved:hover {
box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.15);
}
@@ -620,7 +655,13 @@
}
.understandName {
- font-size: 20px;
+ font-size: 18px;
+ }
+
+ .longText {
+ font-size: 17px;
+ margin: 15px;
+
}
.understandCount {
@@ -637,6 +678,40 @@
}
}
+/* ════════════════════════════════════════
+ 반응형 — (600px 이하)
+════════════════════════════════════════ */
+@media (max-width: 600px) {
+ .understandBar {
+ padding: 10px 12px;
+ gap: 4px;
+ }
+
+ .understandName {
+ font-size: 18px;
+ margin: 6px
+ }
+
+ .longText {
+ font-size: 15px;
+ margin: 8px
+ }
+
+ .understandCount {
+ font-size: 15px;
+ }
+
+ .oxBtn {
+ width: 32px;
+ height: 32px;
+ }
+
+ .arrowBtn svg {
+ width: 24px;
+ height: 24px;
+ }
+}
+
/* ════════════════════════════════════════
반응형 — 모바일 (480px 이하)
@@ -661,14 +736,18 @@
/* ── 이해도 바 ── */
.understandBar {
- height: auto;
min-height: 48px;
padding: 8px 10px;
- flex-wrap: wrap;
}
.understandName {
- font-size: 17px;
+ font-size: 18px;
+ margin: 6px
+ }
+
+ .longText {
+ font-size: 15px;
+ margin: 8px
}
.understandCount {
@@ -676,8 +755,8 @@
}
.oxBtn {
- width: 30px;
- height: 30px;
+ width: 29px;
+ height: 29px;
font-size: 12px;
margin: 0 2px;
}
diff --git a/frontend/src/pages/qna/QnAMainPage.js b/frontend/src/pages/qna/QnAMainPage.js
index f799420..83b14db 100644
--- a/frontend/src/pages/qna/QnAMainPage.js
+++ b/frontend/src/pages/qna/QnAMainPage.js
@@ -44,69 +44,71 @@ function QNAMainPage() {
if (error) return
오류: {error}
;
return (
-
+
+
- {/* ── 진행 중인 세션 ── */}
- {activeSessions.length > 0 && (
- <>
-
- 현재 세션
- {activeSessions.map(session => (
- navigate(`/sessions/${session.sessionId}/questions`, { state: { status: 'IN_SESSION' } })}
- >
-
- {getIcon(session.dayPart)}
- {session.title}
-
-
- {session.week}주차 {DAY_OF_WEEK_KO[session.dayOfWeek]} {DAY_PART_KO[session.dayPart]}
-
-
{formatDate(session.sessionDate)}
-
{getTime(session.dayPart)}
-
- ))}
-
-
- >
- )}
+ {/* ── 진행 중인 세션 ── */}
+ {activeSessions.length > 0 && (
+ <>
+
+ 현재 세션
+ {activeSessions.map(session => (
+ navigate(`/sessions/${session.sessionId}/questions`, { state: { status: 'IN_SESSION' } })}
+ >
+
+ {getIcon(session.dayPart)}
+ {session.title}
+
+
+ {session.week}주차 {DAY_OF_WEEK_KO[session.dayOfWeek]} {DAY_PART_KO[session.dayPart]}
+
+
{formatDate(session.sessionDate)}
+
{getTime(session.dayPart)}
+
+ ))}
+
+
+ >
+ )}
- {/* ── 지난 세션 ── */}
- {pastSessions.length > 0 && (
-
- 지난 세션
-
- {pastSessions.map(session => (
-
navigate(`/sessions/${session.sessionId}/questions`, { state: { status: 'AFTER_SESSION' } })}
- >
-
- {getIcon(session.dayPart)}
- {session.title}
-
- • {session.week}주차 {DAY_OF_WEEK_KO[session.dayOfWeek]} {DAY_PART_KO[session.dayPart]}
+ {/* ── 지난 세션 ── */}
+ {pastSessions.length > 0 && (
+
+ 지난 세션
+
+ {pastSessions.map(session => (
+
navigate(`/sessions/${session.sessionId}/questions`, { state: { status: 'AFTER_SESSION' } })}
+ >
+
+ {getIcon(session.dayPart)}
+ {session.title}
+
+ • {session.week}주차 {DAY_OF_WEEK_KO[session.dayOfWeek]} {DAY_PART_KO[session.dayPart]}
+
-
-
-
- ))}
-
-
- )}
+
+
+ ))}
+
+
+ )}
- {/* ── 세션 없을 때 ── */}
- {activeSessions.length === 0 && pastSessions.length === 0 && (
-
- )}
+ {/* ── 세션 없을 때 ── */}
+ {activeSessions.length === 0 && pastSessions.length === 0 && (
+
+ )}
+
);
}
diff --git a/frontend/src/pages/qna/QnAMainPage.module.css b/frontend/src/pages/qna/QnAMainPage.module.css
index 38d5103..0d10f08 100644
--- a/frontend/src/pages/qna/QnAMainPage.module.css
+++ b/frontend/src/pages/qna/QnAMainPage.module.css
@@ -1,10 +1,17 @@
/* ── 페이지 레이아웃 ── */
+.pageWrapper {
+ min-height: 100vh;
+ background: #f2f2f0;
+ padding-top: 1px;
+}
+
.page {
min-height: 100vh;
max-width: 880px;
margin: 0 auto;
padding: 0 16px;
box-sizing: border-box;
+ background: #f2f2f0;
}
/* ── 섹션 공통 ── */
@@ -27,17 +34,32 @@
background: var(--white);
border-radius: 10px;
padding: 16px;
+ padding-bottom: 24px;
text-align: center;
width: 356px;
height: 148px;
- box-shadow: 2px 2px 5px 0 rgba(0, 0, 0, 0.25);
+
+ border: 1px solid rgba(0,0,0,0.06);
+
+ box-shadow:
+ 0 1px 0 rgba(255,255,255,0.8) inset,
+ 0 3px 8px rgba(0,0,0,0.10),
+ 0 1px 3px rgba(0,0,0,0.06);
+
+
cursor: pointer;
- transition: box-shadow 0.2s;
+ transition:
+ transform 0.2s ease,
+ box-shadow 0.2s ease;
margin: 0 auto;
+ margin-bottom: 40px;
}
.card:hover {
- box-shadow: 4px 4px 10px 0 rgba(0, 0, 0, 0.2);
+ box-shadow:
+ 0 1px 0 rgba(255,255,255,0.8) inset,
+ 0 6px 12px rgba(0,0,0,0.14),
+ 0 2px 5px rgba(0,0,0,0.08);
}
.card:hover .cardTitle {
@@ -77,7 +99,16 @@
/* ── 지난 세션 목록 ── */
.icon {
+ display: inline-block;
+ position: relative;
+ top: -2px;
+
margin-right: 20px;
+ transition: color 0.2s;
+}
+
+.enterIcon {
+ font-size: 20px;
}
.list {
@@ -93,27 +124,30 @@
display: flex;
align-items: center;
justify-content: space-between;
- box-shadow: 2px 2px 5px 0 rgba(0, 0, 0, 0.25);
+ box-shadow: 0 1px 4px rgba(0,0,0,0.06),
+ 0 0 0 1px rgba(0,0,0,0.03);
cursor: pointer;
transition: box-shadow 0.2s;
}
.listItem:hover {
- box-shadow: 4px 4px 10px 0 rgba(0, 0, 0, 0.2);
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.1);
}
.listTitle {
font-family: var(--font-main);
- font-size: 24px;
+ font-size: 23px;
font-weight: 500;
color: var(--black);
+ transition: color 0.2s;
}
.listWeek {
font-family: var(--font-main);
- font-size: 18px;
+ font-size: 15px;
font-weight: 500;
color: var(--gray600);
+ transition: color 0.2s;
}
.enterBtn {
@@ -128,6 +162,10 @@
color: var(--dark);
}
+.listItem:hover .icon {
+ color: var(--dark);
+}
+
/* ── 빈 상태 ── */
.empty {
text-align: center;
@@ -135,6 +173,12 @@
margin-top: 40px;
}
+.listItem:hover .enterBtn,
+.listItem:hover .listTitle,
+.listItem:hover .listWeek {
+ color: var(--dark);
+}
+
/* ════════════════════════════════════════
반응형 — 태블릿 (768px 이하)
@@ -202,6 +246,7 @@
.card {
width: min(356px, 80%);
+ min-height: 140px;
padding: 14px 12px;
}
@@ -221,6 +266,10 @@
}
.listItem {
+ width: 88%;
+ margin: 0 auto;
+ min-height: 40px;
+
padding: 12px;
gap: 8px;
}
@@ -230,14 +279,24 @@
}
.listWeek {
- font-size: 13px;
+ font-size: 12px;
}
- .icon {
- margin-right: 10px;
+ .cardTitle .icon {
+ margin-right: 6px;
+ }
+
+ .listItem .icon {
+ margin-left: 8px;
+ margin-right: 12px;
+ margin-top: 2px;
flex-shrink: 0;
}
+ .enterIcon {
+ font-size: 18px;
+ }
+
.enterBtn {
padding: 4px;
}
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..542d230
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,60 @@
+{
+ "name": "piroin",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "framer-motion": "^12.40.0"
+ }
+ },
+ "node_modules/framer-motion": {
+ "version": "12.40.0",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.40.0.tgz",
+ "integrity": "sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-dom": "^12.40.0",
+ "motion-utils": "^12.39.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/motion-dom": {
+ "version": "12.40.0",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.40.0.tgz",
+ "integrity": "sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-utils": "^12.39.0"
+ }
+ },
+ "node_modules/motion-utils": {
+ "version": "12.39.0",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.39.0.tgz",
+ "integrity": "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==",
+ "license": "MIT"
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..00f24cb
--- /dev/null
+++ b/package.json
@@ -0,0 +1,5 @@
+{
+ "dependencies": {
+ "framer-motion": "^12.40.0"
+ }
+}