Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 0 additions & 21 deletions src/components/Sidebar/ArrowLeft.tsx

This file was deleted.

17 changes: 0 additions & 17 deletions src/components/Sidebar/ArrowRight.tsx

This file was deleted.

31 changes: 8 additions & 23 deletions src/components/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
'use client';

import { useState } from 'react';
import Image from 'next/image';

import { chunkArray } from '@/utils/chunkArray';
import { UseChunkPagination } from '@/hooks/useChunkPagination';
import PaginationControls from '../pagination/PaginationControls';
import SidebarLogo from './SidebarLogo';
import SidebarItemList from './SidebarItemList';
import SidebarPaginationControls from './SidebarPaginationControls';

import add_box from '@/assets/icons/add_box.svg';

Expand Down Expand Up @@ -37,25 +36,11 @@ const mockBoardData: ItemList[] = [
];

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);
};
const { currentGroups, totalPages, canGoPrev, canGoNext, handlePrev, handleNext } = UseChunkPagination({
items: mockBoardData,
chunkSize: 5,
maxGroupsPerPage: 3,
});

return (
<aside className='h-screen w-[67px] px-2 py-5 md:w-[160px] lg:w-[300px]'>
Expand All @@ -71,7 +56,7 @@ export default function Sidebar() {
<SidebarItemList currentGroups={currentGroups} />
</div>

{totalPages > 1 && <SidebarPaginationControls canGoPrev={canGoPrev} canGoNext={canGoNext} handlePrev={handlePrev} handleNext={handleNext} />}
<PaginationControls canGoPrev={canGoPrev} canGoNext={canGoNext} handlePrev={handlePrev} handleNext={handleNext} totalPages={totalPages} alwaysShow={false} className='hidden md:flex' />
</div>
</div>
</aside>
Expand Down
22 changes: 0 additions & 22 deletions src/components/Sidebar/SidebarPaginationControls.tsx

This file was deleted.

24 changes: 24 additions & 0 deletions src/components/pagination/Arrow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ARROW_PATH_LEFT, ARROW_PATH_RIGHT } from '@/constants/paths';
import { cn } from '@/utils/helper';

/*
* direction: 'left' | 'right'
* disabled일 경우 색상/커서 상태 변경
*/
interface ArrowProps {
direction: 'left' | 'right';
disabled?: boolean;
}

export default function Arrow({ direction, 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-60 cursor-pointer';

const dValue = direction === 'left' ? ARROW_PATH_LEFT : ARROW_PATH_RIGHT;

return (
<svg className={cn(baseStyle, colorStyle)} width='10' height='16' viewBox='0 0 10 16' fill='none' xmlns='http://www.w3.org/2000/svg'>
<path d={dValue} fill='currentColor' />
</svg>
);
}
50 changes: 50 additions & 0 deletions src/components/pagination/PaginationControls.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import Arrow from './Arrow';

/*
* "PaginationControls" 컴포넌트 사용 가이드
* ------------------------------------------------------------
* // 예시
* <PaginationControls
* canGoPrev={canGoPrev}
* canGoNext={canGoNext}
* handlePrev={handlePrev}
* handleNext={handleNext}
* totalPages={totalPages}
* alwaysShow={false} // 1페이지 이하일 때 버튼을 숨길지 (기본값 false)
* className='hidden md:flex' // 모바일 숨기고 md부터 보이도록 (선택)
* />
*
* - canGoPrev, canGoNext: "이전/다음 버튼" 활성/비활성 제어
* - handlePrev, handleNext: 클릭 시 실제 페이지 이동 처리 함수
* - totalPages: 총 페이지 수
* - alwaysShow: true면 totalPages<=1이어도 버튼을 무조건 렌더(비활성).
* - className: display나 여백, 반응형 등을 제어하기 위해 부모가 원하는 클래스를 덧붙일 수 있음.
* ------------------------------------------------------------
*/
interface PaginationControlsProps {
canGoPrev: boolean;
canGoNext: boolean;
handlePrev: () => void;
handleNext: () => void;
totalPages: number;
alwaysShow?: boolean;
className?: string;
}

export default function PaginationControls({ canGoPrev, canGoNext, handlePrev, handleNext, totalPages, alwaysShow = false, className }: PaginationControlsProps) {
if (!alwaysShow && totalPages <= 1) {
return null;
}

return (
<div className={`flex ${className} `}>
<button className='flex h-10 w-10 items-center justify-center rounded-bl-[4px] rounded-tl-[4px] border border-gray-30' onClick={handlePrev}>
<Arrow direction='left' disabled={!canGoPrev} />
</button>

<button className='flex h-10 w-10 items-center justify-center rounded-br-[4px] rounded-tr-[4px] border border-gray-30' onClick={handleNext}>
<Arrow direction='right' disabled={!canGoNext} />
</button>
</div>
);
}
3 changes: 3 additions & 0 deletions src/constants/paths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const ARROW_PATH_LEFT = `M2.641 7.99933L8.91824 1.72208C9.08384 1.55648 9.16451 1.35937 9.16024 1.13074C9.15596 0.902106 9.07103 0.704996 8.90543 0.539412C8.73983 0.373815 8.54272 0.291016 8.31409 0.291016C8.08547 0.291016 7.88836 0.373815 7.72276 0.539412L1.34295 6.93204C1.19231 7.08268 1.08066 7.25147 1.00801 7.43843C0.93537 7.62541 0.899048 7.81237 0.899048 7.99933C0.899048 8.18629 0.93537 8.37325 1.00801 8.56022C1.08066 8.74718 1.19231 8.91598 1.34295 9.06662L7.73557 15.4592C7.90117 15.6248 8.09615 15.7055 8.32051 15.7012C8.54486 15.697 8.73983 15.612 8.90543 15.4464C9.07103 15.2808 9.15383 15.0837 9.15383 14.8551C9.15383 14.6265 9.07103 14.4294 8.90543 14.2638L2.641 7.99933Z`;

export const ARROW_PATH_RIGHT = `M7.35901 7.99933L1.08176 1.72208C0.916163 1.55648 0.835496 1.35937 0.83976 1.13074C0.844038 0.902106 0.928975 0.704996 1.09457 0.539412C1.26017 0.373815 1.45728 0.291016 1.68591 0.291016C1.91453 0.291016 2.11164 0.373815 2.27724 0.539412L8.65705 6.93204C8.80769 7.08268 8.91934 7.25147 8.99199 7.43843C9.06463 7.62541 9.10095 7.81237 9.10095 7.99933C9.10095 8.18629 9.06463 8.37325 8.99199 8.56022C8.91934 8.74718 8.80769 8.91598 8.65705 9.06662L2.26443 15.4592C2.09883 15.6248 1.90385 15.7055 1.67949 15.7012C1.45514 15.697 1.26017 15.612 1.09457 15.4464C0.928975 15.2808 0.846176 15.0837 0.846176 14.8551C0.846176 14.6265 0.928975 14.4294 1.09457 14.2638L7.35901 7.99933Z`;
66 changes: 66 additions & 0 deletions src/hooks/useChunkPagination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { useState } from 'react';
import { chunkArray } from '@/utils/chunkArray';

/*
* "UseChunkPagination" 커스텀 훅 사용 가이드
* ------------------------------------------------------------
* // 예시
* const {
* currentGroups,
* page,
* canGoPrev,
* canGoNext,
* handlePrev,
* handleNext,
* totalPages,
* } = UseChunkPagination({
* items: myDataArray, // 전체 아이템 배열
* chunkSize: 5, // 한 묶음에 몇 개씩 자를지
* maxGroupsPerPage: 3, // 한 페이지에 묶음을 몇 개까지 보여줄지
* });
*
* // 이후, currentGroups로 화면을 렌더하고,
* // canGoPrev/canGoNext로 이전/다음 버튼 활성화 여부를 결정하며,
* // handlePrev/handleNext로 페이지 이동을 제어
*
* // 만약 "한 페이지에 1묶음씩" 보이길 원하면 maxGroupsPerPage를 1로 바꾸면 됨.
* // => 데이터가 2묶음 이상이면 다음 페이지가 생김
* ------------------------------------------------------------
*/
interface UseChunkPaginationProps<T> {
items: T[];
chunkSize: number;
maxGroupsPerPage: number;
}

export function UseChunkPagination<T>({ items, chunkSize, maxGroupsPerPage }: UseChunkPaginationProps<T>) {
const [page, setPage] = useState(1);

const chunkedData = chunkArray(items, chunkSize);
const totalPages = Math.ceil(chunkedData.length / maxGroupsPerPage);

const startIndex = (page - 1) * maxGroupsPerPage;
const endIndex = page * maxGroupsPerPage;
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 {
currentGroups,
page,
setPage,
totalPages,
canGoPrev,
canGoNext,
handlePrev,
handleNext,
};
}