diff --git a/src/app/mydashboard/layout.tsx b/src/app/mydashboard/layout.tsx
new file mode 100644
index 0000000..371f2f8
--- /dev/null
+++ b/src/app/mydashboard/layout.tsx
@@ -0,0 +1,12 @@
+import Sidebar from '@/components/Sidebar/Sidebar';
+import { ReactNode } from 'react';
+
+export default function Layout({ children }: { children: ReactNode }) {
+ return (
+
+
+
+ {children}
+
+ );
+}
diff --git a/src/app/mydashboard/page.tsx b/src/app/mydashboard/page.tsx
new file mode 100644
index 0000000..4dfdfab
--- /dev/null
+++ b/src/app/mydashboard/page.tsx
@@ -0,0 +1,3 @@
+export default function Page() {
+ return ;
+}
diff --git a/src/assets/images/sidebar_logo.png b/src/assets/images/sidebar_logo.png
new file mode 100644
index 0000000..8d8b4f2
Binary files /dev/null and b/src/assets/images/sidebar_logo.png differ
diff --git a/src/components/Sidebar/ArrowLeft.tsx b/src/components/Sidebar/ArrowLeft.tsx
new file mode 100644
index 0000000..cfef1ac
--- /dev/null
+++ b/src/components/Sidebar/ArrowLeft.tsx
@@ -0,0 +1,21 @@
+interface ArrowProps {
+ disabled?: boolean;
+}
+
+export default function ArrowLeft({ disabled = false }: ArrowProps) {
+ const baseStyle = 'w-4 h-4 fill-current';
+
+ // disabled 여부에 따른 색상 및 hover
+ // - 비활성화(disabled=true)일 땐 text-gray-30, 클릭 불가(cursor-default)
+ // - 활성화(disabled=false)일 땐 text-gray-80, hover:text-gray-60, cursor-pointer
+ const colorStyle = disabled ? 'text-gray-30 cursor-default' : 'text-gray-50 hover:text-gray-60 cursor-pointer';
+
+ return (
+
+ );
+}
diff --git a/src/components/Sidebar/ArrowRight.tsx b/src/components/Sidebar/ArrowRight.tsx
new file mode 100644
index 0000000..cdc7589
--- /dev/null
+++ b/src/components/Sidebar/ArrowRight.tsx
@@ -0,0 +1,17 @@
+interface ArrowProps {
+ disabled?: boolean;
+}
+
+export default function ArrowRight({ disabled = false }: ArrowProps) {
+ const baseStyle = 'w-4 h-4 fill-current';
+ const colorStyle = disabled ? 'text-gray-30 cursor-default' : 'text-gray-50 hover:text-gray-70 cursor-pointer';
+
+ return (
+
+ );
+}
diff --git a/src/components/Sidebar/Dot.tsx b/src/components/Sidebar/Dot.tsx
new file mode 100644
index 0000000..86d8cb1
--- /dev/null
+++ b/src/components/Sidebar/Dot.tsx
@@ -0,0 +1,32 @@
+interface DotProps {
+ colorClass: 'green-30' | 'blue-20' | 'orange-20' | 'purple' | 'pink-20';
+}
+
+export default function Dot({ colorClass }: DotProps) {
+ let className = '';
+ switch (colorClass) {
+ case 'green-30':
+ className = 'text-green-30';
+ break;
+ case 'blue-20':
+ className = 'text-blue-20';
+ break;
+ case 'orange-20':
+ className = 'text-orange-20';
+ break;
+ case 'pink-20':
+ className = 'text-pink-20';
+ break;
+ case 'purple':
+ className = 'text-purple';
+ break;
+ default:
+ className = 'text-gray-50';
+ }
+
+ return (
+
+ );
+}
diff --git a/src/components/Sidebar/Sidebar.tsx b/src/components/Sidebar/Sidebar.tsx
new file mode 100644
index 0000000..058bece
--- /dev/null
+++ b/src/components/Sidebar/Sidebar.tsx
@@ -0,0 +1,79 @@
+'use client';
+
+import { useState } from 'react';
+import Image from 'next/image';
+
+import { chunkArray } from '@/utils/chunkArray';
+import SidebarLogo from './SidebarLogo';
+import SidebarItemList from './SidebarItemList';
+import SidebarPaginationControls from './SidebarPaginationControls';
+
+import add_box from '@/assets/icons/add_box.svg';
+
+interface ItemList {
+ id: number;
+ name: string;
+ colorClass: 'green-30' | 'blue-20' | 'orange-20' | 'purple' | 'pink-20';
+ hasCrown?: boolean;
+}
+
+const mockBoardData: ItemList[] = [
+ { id: 1, name: '비브리지', colorClass: 'green-30', hasCrown: true },
+ { id: 2, name: '코드잇', colorClass: 'blue-20', hasCrown: true },
+ { id: 3, name: '3분기 계획', colorClass: 'green-30' },
+ { id: 4, name: '회의록', colorClass: 'blue-20' },
+ { id: 5, name: '중요 문서함', colorClass: 'pink-20' },
+ { id: 6, name: '비브리지', colorClass: 'blue-20', hasCrown: true },
+ { id: 7, name: '코드잇', colorClass: 'purple', hasCrown: true },
+ { id: 8, name: '3분기 계획', colorClass: 'blue-20' },
+ { id: 9, name: '회의록', colorClass: 'purple' },
+ { id: 10, name: '중요 문서함', colorClass: 'blue-20' },
+ { id: 11, name: '비브리지', colorClass: 'blue-20', hasCrown: true },
+ { id: 12, name: '코드잇', colorClass: 'pink-20', hasCrown: true },
+ { id: 13, name: '3분기 계획', colorClass: 'orange-20' },
+ { id: 14, name: '회의록', colorClass: 'blue-20' },
+ { id: 15, name: '중요 문서함', colorClass: 'blue-20' },
+ { id: 16, name: '중요 테스트', colorClass: 'blue-20' },
+];
+
+export default function Sidebar() {
+ const MAX_GROUPS_PER_PAGE = 3;
+ const [page, setPage] = useState(1);
+ const chunkedData = chunkArray(mockBoardData, 5);
+
+ const totalPages = Math.ceil(chunkedData.length / MAX_GROUPS_PER_PAGE);
+
+ const startIndex = (page - 1) * MAX_GROUPS_PER_PAGE;
+ const endIndex = page * MAX_GROUPS_PER_PAGE;
+ const currentGroups = chunkedData.slice(startIndex, endIndex);
+
+ const canGoPrev = page > 1;
+ const canGoNext = page < totalPages;
+
+ const handlePrev = () => {
+ if (canGoPrev) setPage((prev) => prev - 1);
+ };
+ const handleNext = () => {
+ if (canGoNext) setPage((prev) => prev + 1);
+ };
+
+ return (
+
+ );
+}
diff --git a/src/components/Sidebar/SidebarItemList.tsx b/src/components/Sidebar/SidebarItemList.tsx
new file mode 100644
index 0000000..ace406b
--- /dev/null
+++ b/src/components/Sidebar/SidebarItemList.tsx
@@ -0,0 +1,37 @@
+import Image from 'next/image';
+import Dot from './Dot';
+import crown from '@/assets/icons/crown.svg';
+
+interface ItemList {
+ id: number;
+ name: string;
+ colorClass: 'green-30' | 'blue-20' | 'orange-20' | 'purple' | 'pink-20';
+ hasCrown?: boolean;
+}
+
+interface SidebarItemListProps {
+ currentGroups: ItemList[][];
+}
+
+export default function SidebarItemList({ currentGroups }: SidebarItemListProps) {
+ return (
+
+ {currentGroups.map((group, groupIndex) => (
+
+ {group.map((item) => (
+
+
+
+
+
+ {item.name}
+ {item.hasCrown && }
+
+
+
+ ))}
+
+ ))}
+
+ );
+}
diff --git a/src/components/Sidebar/SidebarLogo.tsx b/src/components/Sidebar/SidebarLogo.tsx
new file mode 100644
index 0000000..1b1e4b4
--- /dev/null
+++ b/src/components/Sidebar/SidebarLogo.tsx
@@ -0,0 +1,13 @@
+import Image from 'next/image';
+import logo from '@/assets/images/sidebar_logo.png';
+import logo_ci from '@/assets/images/logo_ci.png';
+
+export default function SidebarLogo() {
+ return (
+ <>
+
+
+
+ >
+ );
+}
diff --git a/src/components/Sidebar/SidebarPaginationControls.tsx b/src/components/Sidebar/SidebarPaginationControls.tsx
new file mode 100644
index 0000000..4f1cacd
--- /dev/null
+++ b/src/components/Sidebar/SidebarPaginationControls.tsx
@@ -0,0 +1,22 @@
+import ArrowLeft from './ArrowLeft';
+import ArrowRight from './ArrowRight';
+
+interface PaginationControlsProps {
+ canGoPrev: boolean;
+ canGoNext: boolean;
+ handlePrev: () => void;
+ handleNext: () => void;
+}
+
+export default function SidebarPaginationControls({ canGoPrev, canGoNext, handlePrev, handleNext }: PaginationControlsProps) {
+ return (
+
+ );
+}
diff --git a/src/utils/chunkArray.ts b/src/utils/chunkArray.ts
new file mode 100644
index 0000000..c8e4ccc
--- /dev/null
+++ b/src/utils/chunkArray.ts
@@ -0,0 +1,7 @@
+export function chunkArray(array: T[], size: number): T[][] {
+ const result: T[][] = [];
+ for (let i = 0; i < array.length; i += size) {
+ result.push(array.slice(i, i + size));
+ }
+ return result;
+}