Skip to content

Commit 15b8994

Browse files
committed
알림기능ui수정/마이페이지 알림센터추가/커뮤니티 쪽이동수정
1 parent bf26909 commit 15b8994

8 files changed

Lines changed: 965 additions & 187 deletions

File tree

src/App.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import Settings from "./components/mypage/Settings";
1717
import Shared from "./components/mypage/Shared";
1818
import MyProject from "./components/mypage/MyProject";
1919
import MyCommunity from "./components/mypage/MyCommunity";
20+
import Notifications from "./components/mypage/Notifications";
2021
import ScrollToTop from "./components/common/ScrollToTop";
2122
import CommunityWrite from "./components/community/CommunityWrite";
2223
import PostDetail from "./components/community/PostDetail";
@@ -129,6 +130,7 @@ function AppContent() {
129130
<Route path="community" element={<MyCommunity nickname={nickname} />} />
130131
<Route path="setting" element={<Settings nickname={nickname} />} />
131132
<Route path="shared" element={<Shared />} />
133+
<Route path="notifications" element={<Notifications />} />
132134
</Route>
133135
<Route path="*" element={<Navigate to="/" replace />} />
134136
</Routes>

src/components/community/Community.jsx

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export default function Community() {
5151
const [searchOperator, setSearchOperator] = useState(DEFAULT_OPERATOR);
5252

5353
const PAGE_SIZE = 10;
54+
const PAGE_BUTTON_LIMIT = 5;
5455

5556
useEffect(() => {
5657
let ignore = false;
@@ -332,9 +333,16 @@ export default function Community() {
332333
setLastKnownPage(currentPage);
333334
}, [currentPage, totalPages]);
334335

335-
const pageNumbers = useMemo(() => (
336-
Array.from({ length: totalPages }, (_, index) => index + 1)
337-
), [totalPages]);
336+
const pageNumbers = useMemo(() => {
337+
if (totalPages <= 0) return [];
338+
if (totalPages <= PAGE_BUTTON_LIMIT) {
339+
return Array.from({ length: totalPages }, (_, index) => index + 1);
340+
}
341+
const chunkIndex = Math.floor((currentPage - 1) / PAGE_BUTTON_LIMIT);
342+
const start = chunkIndex * PAGE_BUTTON_LIMIT + 1;
343+
const end = Math.min(start + PAGE_BUTTON_LIMIT - 1, totalPages);
344+
return Array.from({ length: end - start + 1 }, (_, index) => start + index);
345+
}, [currentPage, totalPages]);
338346

339347
const paginatedPosts = useMemo(() => {
340348
const start = (currentPage - 1) * PAGE_SIZE;
@@ -421,21 +429,22 @@ export default function Community() {
421429
.slice(0, 5);
422430
}, [posts]);
423431

424-
const jumpBy = 5;
425432
const goToPage = (page) => {
426433
if (page < 1 || page > totalPages) return;
427434
setCurrentPage(page);
428435
};
429436

430-
const handleChunkMove = (direction) => {
431-
const target = currentPage + direction * jumpBy;
432-
if (target < 1) {
433-
setCurrentPage(1);
434-
} else if (target > totalPages) {
435-
setCurrentPage(totalPages);
436-
} else {
437-
setCurrentPage(target);
438-
}
437+
const canGoPrev = currentPage > 1;
438+
const canGoNext = currentPage < totalPages;
439+
440+
const handlePrevPage = () => {
441+
if (!canGoPrev) return;
442+
goToPage(currentPage - 1);
443+
};
444+
445+
const handleNextPage = () => {
446+
if (!canGoNext) return;
447+
goToPage(currentPage + 1);
439448
};
440449

441450
return (
@@ -649,17 +658,17 @@ export default function Community() {
649658
type="button"
650659
className="page-button"
651660
onClick={() => goToPage(1)}
652-
disabled={currentPage === 1}
661+
disabled={!canGoPrev}
653662
>
654-
처음
663+
&lt;&lt;
655664
</button>
656665
<button
657666
type="button"
658667
className="page-button"
659-
onClick={() => handleChunkMove(-1)}
660-
disabled={currentPage === 1}
668+
onClick={handlePrevPage}
669+
disabled={!canGoPrev}
661670
>
662-
-5쪽
671+
&lt;
663672
</button>
664673
{pageNumbers.map((page) => (
665674
<button
@@ -674,18 +683,18 @@ export default function Community() {
674683
<button
675684
type="button"
676685
className="page-button"
677-
onClick={() => handleChunkMove(1)}
678-
disabled={currentPage === totalPages}
686+
onClick={handleNextPage}
687+
disabled={!canGoNext}
679688
>
680-
+5쪽
689+
&gt;
681690
</button>
682691
<button
683692
type="button"
684693
className="page-button"
685694
onClick={() => goToPage(totalPages)}
686-
disabled={currentPage === totalPages}
695+
disabled={!canGoNext}
687696
>
688-
마지막
697+
&gt;&gt;
689698
</button>
690699
</div>
691700
</div>

src/components/header/Header.css

Lines changed: 107 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -282,81 +282,85 @@
282282
margin-top: 8px;
283283
background-color: var(--surface-popover);
284284
border: 1px solid var(--border-subtle);
285-
border-radius: 6px;
286-
min-width: 250px;
287-
max-height: 300px;
288-
overflow-y: auto;
289-
box-shadow: 0 14px 28px rgba(24, 20, 56, 0.14);
285+
border-radius: 12px;
286+
min-width: 320px;
287+
box-shadow: 0 16px 32px rgba(24, 20, 56, 0.16);
290288
z-index: 100;
291289
display: flex;
292290
flex-direction: column;
293-
transition: all 0.3s ease;
291+
gap: 14px;
292+
padding: 16px;
293+
transition: transform 0.2s ease, opacity 0.2s ease;
294294
color: var(--text-primary);
295295
}
296296

297-
.notification-dropdown.expanded-dropdown {
298-
width: 600px;
299-
max-height: 80vh;
300-
position: fixed;
301-
top: 50%;
302-
left: 50%;
303-
transform: translate(-50%, -50%);
304-
box-shadow: 0 24px 48px rgba(24, 20, 56, 0.18);
305-
padding-top: 30px;
297+
.notification-dropdown__header {
298+
display: flex;
299+
align-items: center;
300+
justify-content: space-between;
301+
gap: 12px;
306302
}
307303

308-
.close-btn {
309-
position: absolute;
310-
top: 5px;
311-
right: 10px;
312-
background: none;
313-
border: none;
314-
color: #888;
315-
font-size: 1.5rem;
316-
cursor: pointer;
317-
z-index: 101;
318-
padding: 0;
319-
line-height: 1;
304+
.notification-dropdown__title {
305+
font-weight: 700;
306+
font-size: 15px;
320307
}
321308

322-
.close-btn:hover {
323-
color: #333;
309+
.notification-dropdown__badge {
310+
display: inline-flex;
311+
align-items: center;
312+
gap: 4px;
313+
padding: 4px 10px;
314+
border-radius: 999px;
315+
background: rgba(139, 112, 255, 0.15);
316+
color: var(--accent-primary);
317+
font-size: 12px;
318+
font-weight: 600;
324319
}
325320

326-
.notification-item {
327-
padding: 10px 15px;
328-
border-bottom: 1px solid var(--border-subtle);
329-
transition: background-color 0.2s;
330-
font-size: 14px;
331-
line-height: 1.4;
332-
color: var(--text-primary);
321+
.notification-dropdown__list {
333322
display: flex;
334-
align-items: center;
335-
gap: 10px;
336-
font-weight: bold;
323+
flex-direction: column;
324+
gap: 8px;
325+
max-height: 360px;
326+
overflow-y: auto;
327+
overscroll-behavior: contain;
328+
scrollbar-gutter: stable;
329+
padding-right: 4px;
337330
}
338331

339-
.notification-item:last-child {
340-
border-bottom: none;
332+
.notification-item {
333+
width: 100%;
334+
display: flex;
335+
align-items: flex-start;
336+
gap: 12px;
337+
padding: 12px 14px;
338+
border-radius: 10px;
339+
border: 1px solid transparent;
340+
background-color: transparent;
341+
transition: background-color 0.2s ease, border-color 0.2s ease;
342+
color: var(--text-primary);
341343
}
342344

343345
.notification-item:hover {
344346
background-color: var(--surface-hover);
347+
border-color: var(--border-subtle);
345348
}
346349

347350
.notification-item.unread {
348-
color: var(--text-primary);
349-
font-weight: bold;
351+
border-color: rgba(139, 112, 255, 0.45);
352+
background-color: rgba(139, 112, 255, 0.12);
350353
}
351354

352355
.notification-item.read {
353356
color: var(--text-muted);
354-
font-weight: normal;
355357
}
356358

357359
.notification-message {
358-
flex-grow: 1;
359-
margin-right: 10px;
360+
flex: 1;
361+
display: flex;
362+
flex-direction: column;
363+
gap: 6px;
360364
background: none;
361365
border: none;
362366
text-align: left;
@@ -366,15 +370,45 @@
366370
padding: 0;
367371
}
368372

373+
.notification-text {
374+
font-size: 14px;
375+
line-height: 1.4;
376+
font-weight: 600;
377+
}
378+
379+
.notification-item.read .notification-text {
380+
font-weight: 500;
381+
color: var(--text-muted);
382+
}
383+
384+
.notification-meta {
385+
display: inline-flex;
386+
align-items: center;
387+
gap: 6px;
388+
font-size: 12px;
389+
color: var(--text-muted);
390+
}
391+
392+
.notification-meta__dot {
393+
font-size: 10px;
394+
line-height: 1;
395+
}
396+
397+
.notification-meta time {
398+
color: inherit;
399+
}
400+
369401
.notification-read-btn {
370402
background: none;
371403
border: 1px solid var(--border-subtle);
372-
border-radius: 4px;
373-
padding: 4px 8px;
404+
border-radius: 8px;
405+
padding: 6px 12px;
374406
font-size: 12px;
407+
font-weight: 600;
375408
cursor: pointer;
376409
color: var(--text-muted);
377410
transition: background-color 0.2s, color 0.2s, border-color 0.2s;
411+
align-self: flex-start;
378412
}
379413

380414
.notification-read-btn:hover {
@@ -392,44 +426,39 @@
392426
}
393427

394428
.no-notifications {
395-
padding: 20px 15px;
429+
padding: 28px 18px;
396430
text-align: center;
397431
color: var(--text-muted);
432+
border: 1px dashed var(--border-subtle);
433+
border-radius: 12px;
398434
}
399435

400436
.notification-footer {
401-
padding: 10px;
402-
text-align: center;
437+
padding: 12px;
403438
border-top: 1px solid var(--border-subtle);
404439
}
405440

406-
.pagination {
407-
display: flex;
441+
.notification-view-all {
442+
width: 100%;
443+
display: inline-flex;
444+
align-items: center;
408445
justify-content: center;
409-
padding: 10px 0;
410-
border-top: 1px solid var(--border-subtle);
411-
}
412-
413-
.pagination button {
414-
background: none;
415-
border: 1px solid var(--border-subtle);
416-
padding: 5px 10px;
417-
margin: 0 4px;
418-
cursor: pointer;
419-
border-radius: 4px;
420-
transition: background-color 0.2s, color 0.2s, border-color 0.2s;
421-
color: var(--text-muted);
422-
}
423-
424-
.pagination button.active {
425-
background-color: var(--accent-secondary);
446+
gap: 10px;
447+
padding: 10px 16px;
448+
border-radius: 8px;
449+
border: none;
450+
background: linear-gradient(135deg, var(--accent-secondary), var(--accent-primary));
426451
color: #ffffff;
427-
border-color: var(--accent-secondary);
452+
font-size: 14px;
453+
font-weight: 600;
454+
cursor: pointer;
455+
transition: transform 0.18s ease, box-shadow 0.18s ease;
456+
box-shadow: 0 12px 24px -16px rgba(139, 112, 255, 0.7);
428457
}
429458

430-
.pagination button:hover:not(.active) {
431-
background-color: var(--surface-hover);
432-
color: var(--text-primary);
459+
.notification-view-all:hover {
460+
transform: translateY(-1px);
461+
box-shadow: 0 18px 30px -18px rgba(139, 112, 255, 0.8);
433462
}
434463

435464
.notification-item.unread {
@@ -441,10 +470,6 @@
441470
color: var(--accent-primary);
442471
}
443472

444-
.dark-mode .pagination button:hover:not(.active) {
445-
background-color: var(--surface-hover);
446-
color: var(--text-primary);
447-
}
448473
.dark-mode .user-nickname {
449474
color: var(--accent-primary);
450475
}
@@ -453,4 +478,8 @@
453478
.dark-mode .user-nickname:hover {
454479
color: #ffffff; /* hover 시 흰색 */
455480
text-decoration: underline; /* 밑줄 유지 */
481+
}
482+
483+
.dark-mode .notification-view-all {
484+
box-shadow: 0 18px 32px -18px rgba(24, 20, 56, 0.6);
456485
}

0 commit comments

Comments
 (0)