KIM-JINO5 2 miesięcy temu
rodzic
commit
413ad5405c
100 zmienionych plików z 290 dodań i 155 usunięć
  1. 0 29
      app/(account)/navTabs.tsx
  2. 0 46
      app/(account)/style.scss
  3. 7 7
      app/(auth)/register/page.tsx
  4. 4 2
      app/(auth)/register/style.scss
  5. 0 0
      app/(main)/(account)/change-approve/page.tsx
  6. 0 0
      app/(main)/(account)/change-approve/style.scss
  7. 0 0
      app/(main)/(account)/change-email/page.tsx
  8. 0 0
      app/(main)/(account)/change-email/style.scss
  9. 0 0
      app/(main)/(account)/change-intro/page.tsx
  10. 0 0
      app/(main)/(account)/change-intro/style.scss
  11. 0 0
      app/(main)/(account)/change-name/page.tsx
  12. 0 0
      app/(main)/(account)/change-name/style.scss
  13. 0 0
      app/(main)/(account)/change-password/page.tsx
  14. 0 0
      app/(main)/(account)/change-password/style.scss
  15. 0 0
      app/(main)/(account)/change-summary/page.tsx
  16. 0 0
      app/(main)/(account)/change-summary/style.scss
  17. 0 0
      app/(main)/(account)/change-thumb/page.tsx
  18. 0 0
      app/(main)/(account)/change-thumb/style.scss
  19. 0 0
      app/(main)/(account)/exp-logs/page.tsx
  20. 0 0
      app/(main)/(account)/exp-logs/style.scss
  21. 1 4
      app/(main)/(account)/layout.tsx
  22. 0 0
      app/(main)/(account)/loading.tsx
  23. 0 0
      app/(main)/(account)/login-log/page.tsx
  24. 0 0
      app/(main)/(account)/login-log/style.scss
  25. 0 0
      app/(main)/(account)/my-comments/page.tsx
  26. 0 0
      app/(main)/(account)/my-comments/style.scss
  27. 0 0
      app/(main)/(account)/my-posts/page.tsx
  28. 0 0
      app/(main)/(account)/my-posts/style.scss
  29. 46 0
      app/(main)/(account)/navTabs.tsx
  30. 0 0
      app/(main)/(account)/profile/page.tsx
  31. 0 0
      app/(main)/(account)/profile/style.scss
  32. 90 0
      app/(main)/(account)/style.scss
  33. 0 0
      app/(main)/(account)/verify-email/page.tsx
  34. 0 0
      app/(main)/(account)/verify-email/style.scss
  35. 0 0
      app/(main)/(account)/withdraw/page.tsx
  36. 0 0
      app/(main)/(account)/withdraw/style.scss
  37. 0 0
      app/(main)/(forum)/board/[code]/page.tsx
  38. 1 0
      app/(main)/(forum)/board/[code]/style.scss
  39. 1 1
      app/(main)/(forum)/board/[code]/view.tsx
  40. 0 0
      app/(main)/(forum)/board/_component/AlbumListLayout.tsx
  41. 0 0
      app/(main)/(forum)/board/_component/DefaultListLayout.tsx
  42. 0 0
      app/(main)/(forum)/board/_component/FooterContent.tsx
  43. 0 0
      app/(main)/(forum)/board/_component/HeaderContent.tsx
  44. 0 0
      app/(main)/(forum)/board/_component/NoticeListLayout.tsx
  45. 0 0
      app/(main)/(forum)/board/_component/PermissionDenied.tsx
  46. 0 0
      app/(main)/(forum)/board/_component/PostWriteButton.tsx
  47. 0 0
      app/(main)/(forum)/board/_component/QnAListLayout.tsx
  48. 0 0
      app/(main)/(forum)/board/_component/style.scss
  49. 1 1
      app/(main)/(forum)/comment/_component/EditForm.tsx
  50. 1 1
      app/(main)/(forum)/comment/_component/Item.tsx
  51. 0 0
      app/(main)/(forum)/comment/_component/List.tsx
  52. 0 0
      app/(main)/(forum)/comment/_component/MentionSuggestion.tsx
  53. 1 1
      app/(main)/(forum)/comment/_component/WriteForm.tsx
  54. 0 0
      app/(main)/(forum)/comment/style.scss
  55. 0 0
      app/(main)/(forum)/comment/view.tsx
  56. 0 0
      app/(main)/(forum)/error.tsx
  57. 1 4
      app/(main)/(forum)/layout.tsx
  58. 1 1
      app/(main)/(forum)/post/[id]/page.tsx
  59. 0 0
      app/(main)/(forum)/post/[id]/style.scss
  60. 2 2
      app/(main)/(forum)/post/[id]/view.tsx
  61. 0 0
      app/(main)/(forum)/post/_component/Content.tsx
  62. 0 0
      app/(main)/(forum)/post/_component/Copied.tsx
  63. 0 0
      app/(main)/(forum)/post/_component/Editor.tsx
  64. 0 0
      app/(main)/(forum)/post/_component/FooterContent.tsx
  65. 0 0
      app/(main)/(forum)/post/_component/HeaderContent.tsx
  66. 3 3
      app/(main)/(forum)/post/_component/LatestPosts.tsx
  67. 0 0
      app/(main)/(forum)/post/_component/PostTagInput.tsx
  68. 0 0
      app/(main)/(forum)/post/_component/QRCode.tsx
  69. 0 0
      app/(main)/(forum)/post/_component/Report.tsx
  70. 0 0
      app/(main)/(forum)/post/_component/SnsShare.tsx
  71. 0 0
      app/(main)/(forum)/post/_component/style.scss
  72. 1 1
      app/(main)/(forum)/post/edit/[id]/page.tsx
  73. 0 0
      app/(main)/(forum)/post/edit/[id]/style.scss
  74. 0 0
      app/(main)/(forum)/post/edit/[id]/view.tsx
  75. 1 1
      app/(main)/(forum)/post/write/page.tsx
  76. 0 0
      app/(main)/(forum)/post/write/style.scss
  77. 0 0
      app/(main)/(forum)/post/write/view.tsx
  78. 0 0
      app/(main)/(forum)/style.scss
  79. 0 0
      app/(main)/docs/[code]/page.tsx
  80. 0 0
      app/(main)/docs/[code]/style.scss
  81. 1 5
      app/(main)/docs/layout.tsx
  82. 0 0
      app/(main)/docs/page.tsx
  83. 11 0
      app/(main)/layout.tsx
  84. 1 5
      app/(main)/news/layout.tsx
  85. 0 0
      app/(main)/news/page.tsx
  86. 0 0
      app/(main)/news/style.scss
  87. 0 0
      app/(main)/news/view.tsx
  88. 0 0
      app/(main)/page.tsx
  89. 1 1
      app/(main)/support/contact/page.tsx
  90. 0 0
      app/(main)/support/contact/style.scss
  91. 0 0
      app/(main)/support/faq/page.tsx
  92. 0 0
      app/(main)/support/faq/style.scss
  93. 1 1
      app/(main)/support/faq/view.tsx
  94. 1 1
      app/(main)/support/guide/page.tsx
  95. 0 0
      app/(main)/support/guide/style.scss
  96. 1 5
      app/(main)/support/layout.tsx
  97. 0 0
      app/(main)/support/navTab.tsx
  98. 4 1
      app/(main)/support/style.scss
  99. 14 0
      app/api/document/[...path]/route.ts
  100. 93 32
      app/component/Layout.tsx

+ 0 - 29
app/(account)/navTabs.tsx

@@ -1,29 +0,0 @@
-'use client';
-
-import './style.scss';
-import React from 'react';
-import Link from 'next/link';
-import { usePathname } from 'next/navigation';
-
-export default function NavTabs() {
-	const pathname = usePathname();
-
-    return (
-		<div id="tabs">
-			{[
-				{ href: "/profile", label: "내 정보" },
-				{ href: "/change-password", label: "비밀번호 변경" },
-				{ href: "/my-posts", label: "작성 게시글" },
-				{ href: "/my-comments", label: "작성 댓글" },
-				{ href: "/exp-logs", label: "경험치 내역" },
-				{ href: "/login-log", label: "로그인 기록" },
-				{ href: "/withdraw", label: "회원탈퇴" }
-			].map(({ href, label }, index, array) => (
-				<React.Fragment key={href}>
-					<Link href={href} className={pathname === href ? 'active' : ''}>{label}</Link>
-					{index !== array.length - 1 && <span>&nbsp;</span>}
-				</React.Fragment>
-			))}
-		</div>
-	);
-}

+ 0 - 46
app/(account)/style.scss

@@ -1,46 +0,0 @@
-#tabs {
-	position: relative;
-	padding: 5px 32px 0 32px;
-	margin-bottom: 24px;
-	display: flex;
-	flex-wrap: wrap;
-	align-items: center;
-	justify-content: start;
-
-	a {
-		color: #0D6295;
-		padding: 10px 15px;
-		transition: color 0.3s;
-
-		&:first-child {
-			padding-left: 0;
-		}
-
-		&:hover {
-			color: #e47911;
-			text-decoration: underline;
-		}
-
-		&.active {
-			color: #e47911;
-			font-weight: bold;
-			text-decoration: underline;
-		}
-	}
-
-	span {
-		width: 1px;
-		height: 11px;
-		background-color: #ccc;
-	}
-}
-
-@media (max-width: 576px) {
-	main {
-		#changeApprove, #changeEmail, #changeIntro, #changeName, #changePassword,
-		#changeSummary, #changeThumb, #profile, #verifyEmail, #withdraw, #loginLog,
-		#myPosts, #myComments, #expLogs {
-			padding: 15px 10px 22px 10px;
-		}
-	}
-}

+ 7 - 7
app/(auth)/register/page.tsx

@@ -108,7 +108,7 @@ export default function Page()
 					<legend>회원가입</legend>
 					<legend>회원가입</legend>
 					<form method="post" acceptCharset="utf-8" autoComplete="off" onSubmit={handleSubmit}>
 					<form method="post" acceptCharset="utf-8" autoComplete="off" onSubmit={handleSubmit}>
 						<div className="flex flex-row flex-wrap">
 						<div className="flex flex-row flex-wrap">
-							<section className="grow sm:pt-4 sm:pb-4">
+							<section className="sm:pt-4 sm:pb-4">
 								<dl>
 								<dl>
 									<dt hidden>&nbsp;</dt>
 									<dt hidden>&nbsp;</dt>
 									<dd>{ process.env.NEXT_PUBLIC_SITE_NAME } 에 오신 것을 환영합니다.</dd>
 									<dd>{ process.env.NEXT_PUBLIC_SITE_NAME } 에 오신 것을 환영합니다.</dd>
@@ -121,7 +121,7 @@ export default function Page()
 									<dd>비밀번호는 최소 8자 이상 입력해주세요.</dd>
 									<dd>비밀번호는 최소 8자 이상 입력해주세요.</dd>
 								</dl>
 								</dl>
 							</section>
 							</section>
-							<section className="grow sm:pt-4">
+							<section className="sm:pt-4">
 								<article className="grid">
 								<article className="grid">
 									<label htmlFor="email">이메일</label>
 									<label htmlFor="email">이메일</label>
 									<input type="email" name="email" id="email" ref={emailRef} maxLength={30} onChange={e => setEmail(e.target.value)} autoComplete="off" />
 									<input type="email" name="email" id="email" ref={emailRef} maxLength={30} onChange={e => setEmail(e.target.value)} autoComplete="off" />
@@ -138,20 +138,20 @@ export default function Page()
 						<hr />
 						<hr />
 
 
 						<div className="flex flex-row flex-wrap">
 						<div className="flex flex-row flex-wrap">
-							<section className="grow">
+							<section>
 								<dl>
 								<dl>
 									<dt>회원가입 약관</dt>
 									<dt>회원가입 약관</dt>
 									<dd>원활한 서비스 이용을 위해 약관 동의가 필요합니다.</dd>
 									<dd>원활한 서비스 이용을 위해 약관 동의가 필요합니다.</dd>
 									<dd>약관 내용을 자세히 확인하신 후 동의해주세요.</dd>
 									<dd>약관 내용을 자세히 확인하신 후 동의해주세요.</dd>
 								</dl>
 								</dl>
 							</section>
 							</section>
-							<section className="grow pt-4 sm:pt-0">
+							<section className="pt-4 sm:pt-0">
 								<p>
 								<p>
 									<Checkbox name="agree_1" id="agree_1" onCheckedChange={(checked) => setAgree1(Boolean(checked))} />
 									<Checkbox name="agree_1" id="agree_1" onCheckedChange={(checked) => setAgree1(Boolean(checked))} />
 									<label htmlFor="agree_1">
 									<label htmlFor="agree_1">
 										<Dialog>
 										<Dialog>
 											<DialogTrigger>이용약관</DialogTrigger>
 											<DialogTrigger>이용약관</DialogTrigger>
-											<TermsDialog subject="이용약관" description="" />
+											<TermsDialog subject="이용약관" code="terms" />
 										</Dialog>
 										</Dialog>
 										에 동의합니다.
 										에 동의합니다.
 									</label>
 									</label>
@@ -161,7 +161,7 @@ export default function Page()
 									<label htmlFor="agree_2">
 									<label htmlFor="agree_2">
 										<Dialog>
 										<Dialog>
 											<DialogTrigger>개인정보처리방침</DialogTrigger>
 											<DialogTrigger>개인정보처리방침</DialogTrigger>
-											<TermsDialog subject="개인정보처리방침" description="" />
+											<TermsDialog subject="개인정보처리방침" code="privacy" />
 										</Dialog>
 										</Dialog>
 										에 동의합니다.
 										에 동의합니다.
 									</label>
 									</label>
@@ -179,4 +179,4 @@ export default function Page()
 			</div>
 			</div>
 		</>
 		</>
     );
     );
-}
+}

+ 4 - 2
app/(auth)/register/style.scss

@@ -58,11 +58,13 @@
 
 
             section {
             section {
                 &:nth-of-type(2n+1) {
                 &:nth-of-type(2n+1) {
-                    flex-basis: 57%;
+                    flex: 0 0 57%;
+                    max-width: 57%;
                 }
                 }
 
 
                 &:nth-of-type(2n) {
                 &:nth-of-type(2n) {
-                    flex-basis: 43%;
+                    flex: 0 0 43%;
+                    max-width: 43%;
 
 
                     label {
                     label {
                         small {
                         small {

+ 0 - 0
app/(account)/change-approve/page.tsx → app/(main)/(account)/change-approve/page.tsx


+ 0 - 0
app/(account)/change-approve/style.scss → app/(main)/(account)/change-approve/style.scss


+ 0 - 0
app/(account)/change-email/page.tsx → app/(main)/(account)/change-email/page.tsx


+ 0 - 0
app/(account)/change-email/style.scss → app/(main)/(account)/change-email/style.scss


+ 0 - 0
app/(account)/change-intro/page.tsx → app/(main)/(account)/change-intro/page.tsx


+ 0 - 0
app/(account)/change-intro/style.scss → app/(main)/(account)/change-intro/style.scss


+ 0 - 0
app/(account)/change-name/page.tsx → app/(main)/(account)/change-name/page.tsx


+ 0 - 0
app/(account)/change-name/style.scss → app/(main)/(account)/change-name/style.scss


+ 0 - 0
app/(account)/change-password/page.tsx → app/(main)/(account)/change-password/page.tsx


+ 0 - 0
app/(account)/change-password/style.scss → app/(main)/(account)/change-password/style.scss


+ 0 - 0
app/(account)/change-summary/page.tsx → app/(main)/(account)/change-summary/page.tsx


+ 0 - 0
app/(account)/change-summary/style.scss → app/(main)/(account)/change-summary/style.scss


+ 0 - 0
app/(account)/change-thumb/page.tsx → app/(main)/(account)/change-thumb/page.tsx


+ 0 - 0
app/(account)/change-thumb/style.scss → app/(main)/(account)/change-thumb/style.scss


+ 0 - 0
app/(account)/exp-logs/page.tsx → app/(main)/(account)/exp-logs/page.tsx


+ 0 - 0
app/(account)/exp-logs/style.scss → app/(main)/(account)/exp-logs/style.scss


+ 1 - 4
app/(account)/layout.tsx → app/(main)/(account)/layout.tsx

@@ -3,7 +3,6 @@
 import './style.scss';
 import './style.scss';
 import { useRouter } from 'next/navigation';
 import { useRouter } from 'next/navigation';
 import { useEffect } from 'react';
 import { useEffect } from 'react';
-import Layout from "@/app/component/Layout";
 import useAuth from '@/hooks/useAuth';
 import useAuth from '@/hooks/useAuth';
 
 
 export default function AccountLayout({ children }: { children: React.ReactNode }) {
 export default function AccountLayout({ children }: { children: React.ReactNode }) {
@@ -21,7 +20,5 @@ export default function AccountLayout({ children }: { children: React.ReactNode
 		return null;
 		return null;
 	}
 	}
 
 
-    return (
-		<Layout>{children}</Layout>
-	);
+	return <>{children}</>;
 }
 }

+ 0 - 0
app/(account)/loading.tsx → app/(main)/(account)/loading.tsx


+ 0 - 0
app/(account)/login-log/page.tsx → app/(main)/(account)/login-log/page.tsx


+ 0 - 0
app/(account)/login-log/style.scss → app/(main)/(account)/login-log/style.scss


+ 0 - 0
app/(account)/my-comments/page.tsx → app/(main)/(account)/my-comments/page.tsx


+ 0 - 0
app/(account)/my-comments/style.scss → app/(main)/(account)/my-comments/style.scss


+ 0 - 0
app/(account)/my-posts/page.tsx → app/(main)/(account)/my-posts/page.tsx


+ 0 - 0
app/(account)/my-posts/style.scss → app/(main)/(account)/my-posts/style.scss


+ 46 - 0
app/(main)/(account)/navTabs.tsx

@@ -0,0 +1,46 @@
+'use client';
+
+import './style.scss';
+import { useCallback } from 'react';
+import Link from 'next/link';
+import { usePathname } from 'next/navigation';
+import useDragScroll from '@/hooks/useDragScroll';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';
+
+const SCROLL_AMOUNT = 120;
+
+export default function NavTabs() {
+	const pathname = usePathname();
+	const dragScroll = useDragScroll<HTMLDivElement>();
+
+	const scroll = useCallback((dir: 'left' | 'right') => {
+		const el = dragScroll.ref.current;
+		if (!el) return;
+		el.scrollBy({ left: dir === 'left' ? -SCROLL_AMOUNT : SCROLL_AMOUNT, behavior: 'smooth' });
+	}, [dragScroll.ref]);
+
+    return (
+		<div id="tabs-wrapper">
+			<button type='button' className='scroll-arrow left' onClick={() => scroll('left')} aria-label='왼쪽 스크롤'>
+				<FontAwesomeIcon icon={faChevronLeft} />
+			</button>
+			<div id="tabs" ref={dragScroll.ref} onMouseDown={dragScroll.onMouseDown} onMouseMove={dragScroll.onMouseMove} onMouseUp={dragScroll.onMouseUp} onMouseLeave={dragScroll.onMouseLeave}>
+				{[
+					{ href: "/profile", label: "내 정보" },
+					{ href: "/change-password", label: "비밀번호 변경" },
+					{ href: "/my-posts", label: "작성 게시글" },
+					{ href: "/my-comments", label: "작성 댓글" },
+					{ href: "/exp-logs", label: "경험치 내역" },
+					{ href: "/login-log", label: "로그인 기록" },
+					{ href: "/withdraw", label: "회원탈퇴" }
+				].map(({ href, label }) => (
+					<Link key={href} href={href} className={pathname === href ? 'active' : undefined}>{label}</Link>
+				))}
+			</div>
+			<button type='button' className='scroll-arrow right' onClick={() => scroll('right')} aria-label='오른쪽 스크롤'>
+				<FontAwesomeIcon icon={faChevronRight} />
+			</button>
+		</div>
+	);
+}

+ 0 - 0
app/(account)/profile/page.tsx → app/(main)/(account)/profile/page.tsx


+ 0 - 0
app/(account)/profile/style.scss → app/(main)/(account)/profile/style.scss


+ 90 - 0
app/(main)/(account)/style.scss

@@ -0,0 +1,90 @@
+#tabs-wrapper {
+	position: relative;
+	display: flex;
+	align-items: center;
+	padding: 25px 0 0 32px;
+	margin-bottom: 24px;
+
+	.scroll-arrow {
+		display: none;
+	}
+}
+
+#tabs {
+	display: flex;
+	flex-wrap: nowrap;
+	align-items: center;
+	justify-content: start;
+	overflow-x: scroll;
+	cursor: grab;
+	gap: 4px;
+	touch-action: pan-y;
+	scrollbar-width: none;
+	-ms-overflow-style: none;
+
+	&::-webkit-scrollbar {
+		display: none;
+	}
+
+	a {
+		color: #0D6295;
+		white-space: nowrap;
+		border-radius: 4px;
+		flex-shrink: 0;
+		padding: 0 12px 0 0;
+		-webkit-user-select: none;
+		user-select: none;
+		-webkit-user-drag: none;
+		-webkit-tap-highlight-color: transparent;
+		outline: none;
+
+		&:hover {
+			color: #e47911;
+			text-decoration: underline;
+		}
+
+		&.active {
+			color: #e47911;
+			font-weight: 600;
+		}
+	}
+}
+
+@media (max-width: 576px) {
+	#tabs-wrapper {
+		padding: 15px 0 0 0;
+		margin-bottom: 0;
+		gap: 0;
+
+		.scroll-arrow {
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			flex-shrink: 0;
+			width: 28px;
+			height: 28px;
+			border: none;
+			background: transparent;
+			color: #666;
+			font-size: 0.75rem;
+			cursor: pointer;
+
+			&:active {
+				color: #e47911;
+			}
+		}
+	}
+
+	#tabs {
+		flex: 1;
+		min-width: 0;
+	}
+
+	main {
+		#changeApprove, #changeEmail, #changeIntro, #changeName, #changePassword,
+		#changeSummary, #changeThumb, #profile, #verifyEmail, #withdraw, #loginLog,
+		#myPosts, #myComments, #expLogs {
+			padding: 15px 10px 22px 10px;
+		}
+	}
+}

+ 0 - 0
app/(account)/verify-email/page.tsx → app/(main)/(account)/verify-email/page.tsx


+ 0 - 0
app/(account)/verify-email/style.scss → app/(main)/(account)/verify-email/style.scss


+ 0 - 0
app/(account)/withdraw/page.tsx → app/(main)/(account)/withdraw/page.tsx


+ 0 - 0
app/(account)/withdraw/style.scss → app/(main)/(account)/withdraw/style.scss


+ 0 - 0
app/(forum)/board/[code]/page.tsx → app/(main)/(forum)/board/[code]/page.tsx


+ 1 - 0
app/(forum)/board/[code]/style.scss → app/(main)/(forum)/board/[code]/style.scss

@@ -46,6 +46,7 @@
 			-webkit-user-select: none;
 			-webkit-user-select: none;
 			user-select: none;
 			user-select: none;
 			cursor: grab;
 			cursor: grab;
+			touch-action: pan-y;
 
 
 			ul {
 			ul {
 				display: flex;
 				display: flex;

+ 1 - 1
app/(forum)/board/[code]/view.tsx → app/(main)/(forum)/board/[code]/view.tsx

@@ -14,7 +14,7 @@ import { BoardResponse, BoardPostsResponse } from '@/types/response/forum/board'
 import Post from '@/types/forum/post';
 import Post from '@/types/forum/post';
 import useDragScroll from '@/hooks/useDragScroll';
 import useDragScroll from '@/hooks/useDragScroll';
 import PostWriteButton from '../_component/PostWriteButton';
 import PostWriteButton from '../_component/PostWriteButton';
-import NavTab from '@/app/support/navTab';
+import NavTab from '@/app/(main)/support/navTab';
 import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
 import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
 import HeaderContent from '../_component/HeaderContent';
 import HeaderContent from '../_component/HeaderContent';
 import FooterContent from '../_component/FooterContent';
 import FooterContent from '../_component/FooterContent';

+ 0 - 0
app/(forum)/board/_component/AlbumListLayout.tsx → app/(main)/(forum)/board/_component/AlbumListLayout.tsx


+ 0 - 0
app/(forum)/board/_component/DefaultListLayout.tsx → app/(main)/(forum)/board/_component/DefaultListLayout.tsx


+ 0 - 0
app/(forum)/board/_component/FooterContent.tsx → app/(main)/(forum)/board/_component/FooterContent.tsx


+ 0 - 0
app/(forum)/board/_component/HeaderContent.tsx → app/(main)/(forum)/board/_component/HeaderContent.tsx


+ 0 - 0
app/(forum)/board/_component/NoticeListLayout.tsx → app/(main)/(forum)/board/_component/NoticeListLayout.tsx


+ 0 - 0
app/(forum)/board/_component/PermissionDenied.tsx → app/(main)/(forum)/board/_component/PermissionDenied.tsx


+ 0 - 0
app/(forum)/board/_component/PostWriteButton.tsx → app/(main)/(forum)/board/_component/PostWriteButton.tsx


+ 0 - 0
app/(forum)/board/_component/QnAListLayout.tsx → app/(main)/(forum)/board/_component/QnAListLayout.tsx


+ 0 - 0
app/(forum)/board/_component/style.scss → app/(main)/(forum)/board/_component/style.scss


+ 1 - 1
app/(forum)/comment/_component/EditForm.tsx → app/(main)/(forum)/comment/_component/EditForm.tsx

@@ -3,7 +3,7 @@
 import '../style.scss';
 import '../style.scss';
 import { useState, useRef, useEffect, useCallback } from 'react';
 import { useState, useRef, useEffect, useCallback } from 'react';
 import useErrorAlert from '@/hooks/useErrorAlert';
 import useErrorAlert from '@/hooks/useErrorAlert';
-import Editor, { type Handle as EditorHandle } from '@/app/(forum)/post/_component/Editor';
+import Editor, { type Handle as EditorHandle } from '@/app/(main)/(forum)/post/_component/Editor';
 import { BoardResponse } from '@/types/response/forum/board';
 import { BoardResponse } from '@/types/response/forum/board';
 import { PostResponse } from '@/types/response/forum/post';
 import { PostResponse } from '@/types/response/forum/post';
 import { CommentUpdateRequest } from '@/types/request/forum/comment';
 import { CommentUpdateRequest } from '@/types/request/forum/comment';

+ 1 - 1
app/(forum)/comment/_component/Item.tsx → app/(main)/(forum)/comment/_component/Item.tsx

@@ -16,7 +16,7 @@ import { type CommentItem } from '@/types/forum/comment';
 import { BoardResponse } from '@/types/response/forum/board';
 import { BoardResponse } from '@/types/response/forum/board';
 import { PostResponse } from '@/types/response/forum/post';
 import { PostResponse } from '@/types/response/forum/post';
 import EditForm from './EditForm';
 import EditForm from './EditForm';
-import Report from '@/app/(forum)/post/_component/Report';
+import Report from '@/app/(main)/(forum)/post/_component/Report';
 import { Reaction } from '@/constants/forum';
 import { Reaction } from '@/constants/forum';
 
 
 type Props = {
 type Props = {

+ 0 - 0
app/(forum)/comment/_component/List.tsx → app/(main)/(forum)/comment/_component/List.tsx


+ 0 - 0
app/(forum)/comment/_component/MentionSuggestion.tsx → app/(main)/(forum)/comment/_component/MentionSuggestion.tsx


+ 1 - 1
app/(forum)/comment/_component/WriteForm.tsx → app/(main)/(forum)/comment/_component/WriteForm.tsx

@@ -3,7 +3,7 @@
 import '../style.scss';
 import '../style.scss';
 import Image from 'next/image';
 import Image from 'next/image';
 import { useState, useRef, useEffect, useCallback } from 'react';
 import { useState, useRef, useEffect, useCallback } from 'react';
-import Editor, { type Handle as EditorHandle } from '@/app/(forum)/post/_component/Editor';
+import Editor, { type Handle as EditorHandle } from '@/app/(main)/(forum)/post/_component/Editor';
 import EmojiPicker from '@/app/component/EmojiPicker';
 import EmojiPicker from '@/app/component/EmojiPicker';
 import Loading from '@/app/component/Loading';
 import Loading from '@/app/component/Loading';
 import { useMemberContext } from '@/contexts/memberProvider';
 import { useMemberContext } from '@/contexts/memberProvider';

+ 0 - 0
app/(forum)/comment/style.scss → app/(main)/(forum)/comment/style.scss


+ 0 - 0
app/(forum)/comment/view.tsx → app/(main)/(forum)/comment/view.tsx


+ 0 - 0
app/(forum)/error.tsx → app/(main)/(forum)/error.tsx


+ 1 - 4
app/(forum)/layout.tsx → app/(main)/(forum)/layout.tsx

@@ -1,10 +1,7 @@
 'use client';
 'use client';
 
 
 import "./style.scss";
 import "./style.scss";
-import Layout from "@/app/component/Layout";
 
 
 export default function BoardLayout({ children }: { children: React.ReactNode }) {
 export default function BoardLayout({ children }: { children: React.ReactNode }) {
-    return (
-		<Layout>{children}</Layout>
-	);
+	return <>{children}</>;
 }
 }

+ 1 - 1
app/(forum)/post/[id]/page.tsx → app/(main)/(forum)/post/[id]/page.tsx

@@ -7,7 +7,7 @@ import { checkAuthServer } from '@/lib/api/auth';
 import { fetchBoard } from '@/lib/api/forum/board';
 import { fetchBoard } from '@/lib/api/forum/board';
 import { fetchPostData } from '@/lib/api/forum/post';
 import { fetchPostData } from '@/lib/api/forum/post';
 import { checkPermission } from '@/lib/utils/server';
 import { checkPermission } from '@/lib/utils/server';
-import PermissionDenied from '@/app/(forum)/board/_component/PermissionDenied';
+import PermissionDenied from '@/app/(main)/(forum)/board/_component/PermissionDenied';
 
 
 export default async function PostView({ params }: { params: Promise<{ id: string }> })
 export default async function PostView({ params }: { params: Promise<{ id: string }> })
 {
 {

+ 0 - 0
app/(forum)/post/[id]/style.scss → app/(main)/(forum)/post/[id]/style.scss


+ 2 - 2
app/(forum)/post/[id]/view.tsx → app/(main)/(forum)/post/[id]/view.tsx

@@ -12,8 +12,8 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { faBookmark as nBookmark, faThumbsUp as nThumbsUp, faThumbsDown as nThumbsDown, faFlag as nFlag, faPenToSquare, faTrashCan } from '@fortawesome/free-regular-svg-icons';
 import { faBookmark as nBookmark, faThumbsUp as nThumbsUp, faThumbsDown as nThumbsDown, faFlag as nFlag, faPenToSquare, faTrashCan } from '@fortawesome/free-regular-svg-icons';
 import { faQrcode, faPrint, faLink, faShareNodes, faBookmark as yBookmark, faThumbsUp as yThumbsUp, faThumbsDown as yThumbsDown, faFlag as yFlag } from '@fortawesome/free-solid-svg-icons';
 import { faQrcode, faPrint, faLink, faShareNodes, faBookmark as yBookmark, faThumbsUp as yThumbsUp, faThumbsDown as yThumbsDown, faFlag as yFlag } from '@fortawesome/free-solid-svg-icons';
 import Loading from '@/app/component/Loading';
 import Loading from '@/app/component/Loading';
-import Comment from '@/app/(forum)/comment/view';
-import LatestList from '@/app/(forum)/post/_component/LatestPosts';
+import Comment from '@/app/(main)/(forum)/comment/view';
+import LatestList from '@/app/(main)/(forum)/post/_component/LatestPosts';
 import { BoardResponse } from '@/types/response/forum/board';
 import { BoardResponse } from '@/types/response/forum/board';
 import { PostResponse } from '@/types/response/forum/post';
 import { PostResponse } from '@/types/response/forum/post';
 import Content from '../_component/Content';
 import Content from '../_component/Content';

+ 0 - 0
app/(forum)/post/_component/Content.tsx → app/(main)/(forum)/post/_component/Content.tsx


+ 0 - 0
app/(forum)/post/_component/Copied.tsx → app/(main)/(forum)/post/_component/Copied.tsx


+ 0 - 0
app/(forum)/post/_component/Editor.tsx → app/(main)/(forum)/post/_component/Editor.tsx


+ 0 - 0
app/(forum)/post/_component/FooterContent.tsx → app/(main)/(forum)/post/_component/FooterContent.tsx


+ 0 - 0
app/(forum)/post/_component/HeaderContent.tsx → app/(main)/(forum)/post/_component/HeaderContent.tsx


+ 3 - 3
app/(forum)/post/_component/LatestPosts.tsx → app/(main)/(forum)/post/_component/LatestPosts.tsx

@@ -12,9 +12,9 @@ import PostLatest from '@/types/forum/latestPost';
 import { LatestPostsResponse } from '@/types/response/forum/board'
 import { LatestPostsResponse } from '@/types/response/forum/board'
 import { fetchApi, throwError } from '@/lib/utils/client';
 import { fetchApi, throwError } from '@/lib/utils/client';
 import Loading from '@/app/component/Loading';
 import Loading from '@/app/component/Loading';
-import DefaultListLayout from '@/app/(forum)/board/_component/DefaultListLayout';
-import QnAListLayout from '@/app/(forum)/board/_component/QnAListLayout';
-import AlbumListLayout from '@/app/(forum)/board/_component/AlbumListLayout';
+import DefaultListLayout from '@/app/(main)/(forum)/board/_component/DefaultListLayout';
+import QnAListLayout from '@/app/(main)/(forum)/board/_component/QnAListLayout';
+import AlbumListLayout from '@/app/(main)/(forum)/board/_component/AlbumListLayout';
 import { BoardLayout } from '@/constants/forum';
 import { BoardLayout } from '@/constants/forum';
 
 
 type Props = {
 type Props = {

+ 0 - 0
app/(forum)/post/_component/PostTagInput.tsx → app/(main)/(forum)/post/_component/PostTagInput.tsx


+ 0 - 0
app/(forum)/post/_component/QRCode.tsx → app/(main)/(forum)/post/_component/QRCode.tsx


+ 0 - 0
app/(forum)/post/_component/Report.tsx → app/(main)/(forum)/post/_component/Report.tsx


+ 0 - 0
app/(forum)/post/_component/SnsShare.tsx → app/(main)/(forum)/post/_component/SnsShare.tsx


+ 0 - 0
app/(forum)/post/_component/style.scss → app/(main)/(forum)/post/_component/style.scss


+ 1 - 1
app/(forum)/post/edit/[id]/page.tsx → app/(main)/(forum)/post/edit/[id]/page.tsx

@@ -7,7 +7,7 @@ import { fetchBoard, fetchBoardList } from '@/lib/api/forum/board';
 import { fetchPostData } from '@/lib/api/forum/post';
 import { fetchPostData } from '@/lib/api/forum/post';
 import { getTokenData, checkPermission } from '@/lib/utils/server';
 import { getTokenData, checkPermission } from '@/lib/utils/server';
 import { TokenData } from '@/types/response/common';
 import { TokenData } from '@/types/response/common';
-import PermissionDenied from '@/app/(forum)/board/_component/PermissionDenied';
+import PermissionDenied from '@/app/(main)/(forum)/board/_component/PermissionDenied';
 
 
 export default async function PostEdit({ params }: { params: Promise<{ id: string }> })
 export default async function PostEdit({ params }: { params: Promise<{ id: string }> })
 {
 {

+ 0 - 0
app/(forum)/post/edit/[id]/style.scss → app/(main)/(forum)/post/edit/[id]/style.scss


+ 0 - 0
app/(forum)/post/edit/[id]/view.tsx → app/(main)/(forum)/post/edit/[id]/view.tsx


+ 1 - 1
app/(forum)/post/write/page.tsx → app/(main)/(forum)/post/write/page.tsx

@@ -5,7 +5,7 @@ import { notFound, forbidden, unauthorized } from 'next/navigation';
 import { checkAuthServer } from '@/lib/api/auth';
 import { checkAuthServer } from '@/lib/api/auth';
 import { fetchBoard, fetchBoardList } from '@/lib/api/forum/board';
 import { fetchBoard, fetchBoardList } from '@/lib/api/forum/board';
 import { checkPermission } from '@/lib/utils/server';
 import { checkPermission } from '@/lib/utils/server';
-import PermissionDenied from '@/app/(forum)/board/_component/PermissionDenied';
+import PermissionDenied from '@/app/(main)/(forum)/board/_component/PermissionDenied';
 
 
 export default async function PostWrite({ searchParams }: { searchParams : Promise<{ board: string }> })
 export default async function PostWrite({ searchParams }: { searchParams : Promise<{ board: string }> })
 {
 {

+ 0 - 0
app/(forum)/post/write/style.scss → app/(main)/(forum)/post/write/style.scss


+ 0 - 0
app/(forum)/post/write/view.tsx → app/(main)/(forum)/post/write/view.tsx


+ 0 - 0
app/(forum)/style.scss → app/(main)/(forum)/style.scss


+ 0 - 0
app/docs/[code]/page.tsx → app/(main)/docs/[code]/page.tsx


+ 0 - 0
app/docs/[code]/style.scss → app/(main)/docs/[code]/style.scss


+ 1 - 5
app/docs/layout.tsx → app/(main)/docs/layout.tsx

@@ -1,9 +1,5 @@
 'use client';
 'use client';
 
 
-import Layout from "@/app/component/Layout";
-
 export default function DocsLayout({ children }: { children: React.ReactNode }) {
 export default function DocsLayout({ children }: { children: React.ReactNode }) {
-    return (
-		<Layout>{children}</Layout>
-	);
+	return <>{children}</>;
 }
 }

+ 0 - 0
app/docs/page.tsx → app/(main)/docs/page.tsx


+ 11 - 0
app/(main)/layout.tsx

@@ -0,0 +1,11 @@
+'use client';
+
+import Layout from '@/app/component/Layout';
+
+export default function MainLayout({ children }: { children: React.ReactNode }) {
+	return (
+		<Layout>
+			{children}
+		</Layout>
+	);
+}

+ 1 - 5
app/news/layout.tsx → app/(main)/news/layout.tsx

@@ -1,9 +1,5 @@
 'use client';
 'use client';
 
 
-import Layout from "@/app/component/Layout";
-
 export default function NewsLayout({ children }: { children: React.ReactNode }) {
 export default function NewsLayout({ children }: { children: React.ReactNode }) {
-    return (
-		<Layout>{children}</Layout>
-	);
+	return <>{children}</>;
 }
 }

+ 0 - 0
app/news/page.tsx → app/(main)/news/page.tsx


+ 0 - 0
app/news/style.scss → app/(main)/news/style.scss


+ 0 - 0
app/news/view.tsx → app/(main)/news/view.tsx


+ 0 - 0
app/page.tsx → app/(main)/page.tsx


+ 1 - 1
app/support/contact/page.tsx → app/(main)/support/contact/page.tsx

@@ -1,7 +1,7 @@
 'use client';
 'use client';
 
 
 import './style.scss';
 import './style.scss';
-import NavTab from '@/app/support/navTab';
+import NavTab from '@/app/(main)/support/navTab';
 
 
 export default function View() {
 export default function View() {
 	return (
 	return (

+ 0 - 0
app/support/contact/style.scss → app/(main)/support/contact/style.scss


+ 0 - 0
app/support/faq/page.tsx → app/(main)/support/faq/page.tsx


+ 0 - 0
app/support/faq/style.scss → app/(main)/support/faq/style.scss


+ 1 - 1
app/support/faq/view.tsx → app/(main)/support/faq/view.tsx

@@ -5,7 +5,7 @@ import { useState, useEffect, useMemo, useCallback } from 'react';
 import { FaqCategory, FaqItem } from '@/types/response/page/faq';
 import { FaqCategory, FaqItem } from '@/types/response/page/faq';
 import { fetchApi } from '@/lib/utils/client';
 import { fetchApi } from '@/lib/utils/client';
 import { FaqCategoryResponse, FaqItemsResponse } from '@/types/response/page/faq';
 import { FaqCategoryResponse, FaqItemsResponse } from '@/types/response/page/faq';
-import NavTab from '@/app/support/navTab';
+import NavTab from '@/app/(main)/support/navTab';
 import Loading from '@/app/component/Loading';
 import Loading from '@/app/component/Loading';
 
 
 // 텍스트에서 키워드를 <mark>로 감싸서 highlight
 // 텍스트에서 키워드를 <mark>로 감싸서 highlight

+ 1 - 1
app/support/guide/page.tsx → app/(main)/support/guide/page.tsx

@@ -3,7 +3,7 @@
 import './style.scss';
 import './style.scss';
 import { notFound } from 'next/navigation';
 import { notFound } from 'next/navigation';
 import { fetchDocument } from '@/lib/api/page/document';
 import { fetchDocument } from '@/lib/api/page/document';
-import NavTab from '@/app/support/navTab';
+import NavTab from '@/app/(main)/support/navTab';
 
 
 export default async function Guide() {
 export default async function Guide() {
 	const result = await fetchDocument('guide');
 	const result = await fetchDocument('guide');

+ 0 - 0
app/support/guide/style.scss → app/(main)/support/guide/style.scss


+ 1 - 5
app/support/layout.tsx → app/(main)/support/layout.tsx

@@ -1,9 +1,5 @@
 'use client';
 'use client';
 
 
-import Layout from "@/app/component/Layout";
-
 export default function SupportLayout({ children }: { children: React.ReactNode }) {
 export default function SupportLayout({ children }: { children: React.ReactNode }) {
-    return (
-		<Layout>{children}</Layout>
-	);
+	return <>{children}</>;
 }
 }

+ 0 - 0
app/support/navTab.tsx → app/(main)/support/navTab.tsx


+ 4 - 1
app/support/style.scss → app/(main)/support/style.scss

@@ -7,6 +7,9 @@
 	row-gap: 10px;
 	row-gap: 10px;
 	column-gap: 15px;
 	column-gap: 15px;
 	padding: 25px 0 0 32px;
 	padding: 25px 0 0 32px;
+	min-width: 410px;
+  	max-width: 1920px;
+	margin: 0 auto;
 
 
 	> article {
 	> article {
 		> a {
 		> a {
@@ -28,7 +31,7 @@
 @media (max-width: 576px) {
 @media (max-width: 576px) {
 	main {
 	main {
 		#navTab {
 		#navTab {
-			padding: 15px 0 0 10px;
+			padding: 15px 0 10px 10px;
 		}
 		}
 
 
 		#board, #contact, #faq, #guide {
 		#board, #contact, #faq, #guide {

+ 14 - 0
app/api/document/[...path]/route.ts

@@ -0,0 +1,14 @@
+import { NextRequest, NextResponse } from 'next/server';
+import { ResultDto } from '@/types/response/common';
+import { fetchJson } from '@/lib/utils/server';
+
+export async function GET(request: NextRequest, { params }: { params: Promise<{ path: string[] }> }) {
+	const { path } = await params;
+	const endpoint = `/api/document/${path.join('/')}`;
+
+	const res: ResultDto = await fetchJson(endpoint, {
+		method: 'GET'
+	});
+
+	return NextResponse.json(res);
+}

+ 93 - 32
app/component/Layout.tsx

@@ -1,27 +1,49 @@
 'use client';
 'use client';
 
 
-import { useState, useCallback } from 'react';
+import { useState, useCallback, useEffect } from 'react';
 import Link from 'next/link';
 import Link from 'next/link';
+import { usePathname } from 'next/navigation';
 import Styles from '../styles/common.module.scss';
 import Styles from '../styles/common.module.scss';
 import useAuth from '@/hooks/useAuth';
 import useAuth from '@/hooks/useAuth';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faBars, faXmark } from '@fortawesome/free-solid-svg-icons';
+import { faBars, faXmark, faCoins, faComments, faNewspaper, faHeadset, faUser, faRightToBracket } from '@fortawesome/free-solid-svg-icons';
+import { faCommentDots, faClock } from '@fortawesome/free-regular-svg-icons';
+import ChatSidebar from '@/app/component/chat/ChatSidebar';
 
 
 type Props = {
 type Props = {
 	children: React.ReactNode;
 	children: React.ReactNode;
-	sidebarContent?: React.ReactNode;
 };
 };
 
 
-export default function Layout({ children, sidebarContent }: Props) {
+export default function Layout({ children }: Props) {
 	const { isAuthenticated, isLoading, logout } = useAuth();
 	const { isAuthenticated, isLoading, logout } = useAuth();
 	const [sidebarOpen, setSidebarOpen] = useState(false);
 	const [sidebarOpen, setSidebarOpen] = useState(false);
+	const [chatOpen, setChatOpen] = useState(false);
+	const pathname = usePathname();
 
 
 	const toggleSidebar = useCallback(() => {
 	const toggleSidebar = useCallback(() => {
 		setSidebarOpen((prev) => !prev);
 		setSidebarOpen((prev) => !prev);
 	}, []);
 	}, []);
 
 
-	const closeSidebar = useCallback(() => {
+	const toggleChat = useCallback(() => {
+		setChatOpen((prev) => !prev);
+	}, []);
+
+	const closeOverlay = useCallback(() => {
 		setSidebarOpen(false);
 		setSidebarOpen(false);
+		setChatOpen(false);
+	}, []);
+
+	const [currentTime, setCurrentTime] = useState('');
+	useEffect(() => {
+		const updateTime = () => {
+			const now = new Date();
+			setCurrentTime(
+				`${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`
+			);
+		};
+		updateTime();
+		const timer = setInterval(updateTime, 1000);
+		return () => clearInterval(timer);
 	}, []);
 	}, []);
 
 
 	if (isLoading) {
 	if (isLoading) {
@@ -30,33 +52,33 @@ export default function Layout({ children, sidebarContent }: Props) {
 
 
     return (
     return (
         <>
         <>
-            <div id='container' className={`${Styles.container}${sidebarOpen ? ` ${Styles.sidebarOpen}` : ''}`}>
+            <div id='container' className={`${Styles.container}${sidebarOpen ? ` ${Styles.sidebarOpen}` : ''}${chatOpen ? ` ${Styles.chatOpen}` : ''}`}>
 
 
                 {/* 상단 내용 */}
                 {/* 상단 내용 */}
-                <header id='header' className={`${Styles.header} flex items-center justify-between w-full px-4`}>
-					<div className='flex items-center gap-2'>
-						<button type='button' className={Styles.hamburger} onClick={toggleSidebar} aria-label='메뉴'>
-							<FontAwesomeIcon icon={sidebarOpen ? faXmark : faBars} />
-						</button>
-						<Link href='/' className='font-bold text-xl'>
-							<picture>
-								<source src="image.webp" type="image/webp" />
-								<img src="/resources/logo.svg" alt="bitforum logo" />
-							</picture>
-						</Link>
-					</div>
-                    <nav className='flex grow items-center justify-between'>
+                <header id='header' className={`${Styles.header} flex items-center w-full px-4`}>
+					<button type='button' className={Styles.hamburger} onClick={toggleSidebar} aria-label='메뉴'>
+						<FontAwesomeIcon icon={sidebarOpen ? faXmark : faBars} />
+					</button>
+					<Link href='/' className={Styles.logo}>
+						<picture>
+							<source src="image.webp" type="image/webp" />
+							<img src="/resources/logo.svg" alt="bitforum logo" />
+						</picture>
+					</Link>
+                    <nav className={Styles.pcNav}>
                         <ul className='flex gap-4'>
                         <ul className='flex gap-4'>
                             <li>
                             <li>
                                 <Link href='/'>
                                 <Link href='/'>
                                     코인
                                     코인
                                 </Link>
                                 </Link>
                             </li>
                             </li>
+							{/*
                             <li>
                             <li>
                                 <Link href='/latest'>
                                 <Link href='/latest'>
                                     토론
                                     토론
                                 </Link>
                                 </Link>
                             </li>
                             </li>
+							*/}
                             <li>
                             <li>
                                 <Link href='/news'>
                                 <Link href='/news'>
                                     뉴스
                                     뉴스
@@ -69,7 +91,10 @@ export default function Layout({ children, sidebarContent }: Props) {
                             </li>
                             </li>
                         </ul>
                         </ul>
 						{!isAuthenticated ? (
 						{!isAuthenticated ? (
-							<ul className='flex gap-4'>
+							<ul className='flex gap-4 items-center'>
+								<li className={`${Styles.clock} text-sm opacity-70`} style={{ fontVariantNumeric: 'tabular-nums' }}>
+									<FontAwesomeIcon icon={faClock} className='mr-1' />{currentTime}
+								</li>
 								<li>
 								<li>
 									<a href='/login'>
 									<a href='/login'>
 										로그인
 										로그인
@@ -82,7 +107,10 @@ export default function Layout({ children, sidebarContent }: Props) {
 								</li>
 								</li>
 							</ul>
 							</ul>
 						) : (
 						) : (
-							<ul className='flex gap-4'>
+							<ul className='flex gap-4 items-center'>
+								<li className={`${Styles.clock} text-sm opacity-70`} style={{ fontVariantNumeric: 'tabular-nums' }}>
+									<FontAwesomeIcon icon={faClock} className='mr-1' />{currentTime}
+								</li>
 								<li>
 								<li>
 									<Link href='/profile'>
 									<Link href='/profile'>
 										내 정보
 										내 정보
@@ -96,15 +124,13 @@ export default function Layout({ children, sidebarContent }: Props) {
 							</ul>
 							</ul>
 						)}
 						)}
                     </nav>
                     </nav>
+					<button type='button' className={Styles.chatToggle} onClick={toggleChat} aria-label='채팅'>
+						<FontAwesomeIcon icon={faCommentDots} />
+					</button>
                 </header>
                 </header>
 
 
-                {/* 좌측 사이드바 */}
-                <aside id='aside' className={Styles.aside}>
-					{sidebarContent}
-				</aside>
-
 				{/* 모바일 오버레이 */}
 				{/* 모바일 오버레이 */}
-				<div className={Styles.overlay} onClick={closeSidebar} />
+				<div className={Styles.overlay} onClick={closeOverlay} />
 
 
                 {/* 메인 내용 */}
                 {/* 메인 내용 */}
                 <main id='main' className={`${Styles.main} relative`}>
                 <main id='main' className={`${Styles.main} relative`}>
@@ -112,21 +138,56 @@ export default function Layout({ children, sidebarContent }: Props) {
                 </main>
                 </main>
 
 
 				{/* 우측 채팅 사이드바 */}
 				{/* 우측 채팅 사이드바 */}
-				<aside id='chatAside' className={Styles.chatAside}></aside>
+				<aside id='chatAside' className={Styles.chatAside}>
+					<ChatSidebar />
+				</aside>
 
 
                 {/* 하단 내용 */}
                 {/* 하단 내용 */}
                 <footer id='footer' className={`${Styles.footer} px-4`}>
                 <footer id='footer' className={`${Styles.footer} px-4`}>
                     <ol>
                     <ol>
-                        {/* 최신글 표시 ▼ */}
-                        <li>111111</li>
+                        <li>
+							<Link href='/docs/teams'>이용약관</Link>
+						</li>
 
 
-                        {/* 공지사항 표시 ▲ */}
-                        <li>222222</li>
+                        <li>
+							<Link href='/docs/privacy'>개인정보처리방침</Link>
+						</li>
 
 
                         {/* 저작권 표시 */}
                         {/* 저작권 표시 */}
                         <li>© 2025 PLAYR. All rights reserved.</li>
                         <li>© 2025 PLAYR. All rights reserved.</li>
                     </ol>
                     </ol>
                 </footer>
                 </footer>
+
+				{/* 모바일 하단 탭바 */}
+				<nav className={Styles.bottomTab}>
+					<Link href='/' className={pathname === '/' ? Styles.active : ''}>
+						<FontAwesomeIcon icon={faCoins} />
+						<span>코인</span>
+					</Link>
+					<Link href='/latest' className={pathname.startsWith('/latest') || (pathname.startsWith('/board') && !pathname.startsWith('/board/notice')) || pathname.startsWith('/post') ? Styles.active : ''}>
+						<FontAwesomeIcon icon={faComments} />
+						<span>토론</span>
+					</Link>
+					<Link href='/news' className={pathname.startsWith('/news') ? Styles.active : ''}>
+						<FontAwesomeIcon icon={faNewspaper} />
+						<span>뉴스</span>
+					</Link>
+					<Link href='/board/notice' className={pathname.startsWith('/board/notice') || pathname.startsWith('/support') ? Styles.active : ''}>
+						<FontAwesomeIcon icon={faHeadset} />
+						<span>고객지원</span>
+					</Link>
+					{isAuthenticated ? (
+						<Link href='/profile' className={pathname.startsWith('/profile') ? Styles.active : ''}>
+							<FontAwesomeIcon icon={faUser} />
+							<span>내 정보</span>
+						</Link>
+					) : (
+						<a href='/login'>
+							<FontAwesomeIcon icon={faRightToBracket} />
+							<span>로그인</span>
+						</a>
+					)}
+				</nav>
             </div>
             </div>
         </>
         </>
     );
     );

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików