- 페이지네이션 로직을 별도 JS 파일로 분리 (public/js/pagination.js)
* 쿠키 기반 per_page 값 저장 및 유지
* 페이지네이션 이벤트 핸들러 통합
* 중복 코드 제거
- 페이지네이션 UI 개선
* 처음으로/끝으로 이동 버튼 추가
* selectbox 너비 조정 (90px)
* 서버사이드 selected 속성으로 옵션 매칭 개선
- 초기 페이지당 항목 수를 10개로 변경
* TenantController, UserController, DepartmentController, RoleController 기본값 수정
- layouts/app.blade.php
* pagination.js 로드 추가
* 기존 인라인 스크립트 제거
변경 파일:
- public/js/pagination.js (신규)
- resources/views/layouts/app.blade.php
- resources/views/partials/pagination.blade.php
- app/Http/Controllers/Api/Admin/{Tenant,User,Department,Role}Controller.php
159 lines
9.3 KiB
PHP
159 lines
9.3 KiB
PHP
{{--
|
|
공통 페이지네이션 컴포넌트 (HTMX 호환)
|
|
|
|
사용법:
|
|
@include('partials.pagination', [
|
|
'paginator' => $tenants,
|
|
'target' => '#tenant-table',
|
|
'includeForm' => '#filterForm'
|
|
])
|
|
--}}
|
|
|
|
<div class="bg-white px-4 py-3 border-t border-gray-200 sm:px-6">
|
|
<div class="flex items-center justify-between">
|
|
<!-- 모바일 네비게이션 -->
|
|
<div class="flex-1 flex justify-between sm:hidden">
|
|
@if($paginator->onFirstPage())
|
|
<span class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-400 bg-gray-100 cursor-not-allowed">
|
|
이전
|
|
</span>
|
|
@else
|
|
<button type="button"
|
|
onclick="handlePageChange({{ $paginator->currentPage() - 1 }})"
|
|
class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
|
|
이전
|
|
</button>
|
|
@endif
|
|
|
|
@if($paginator->hasMorePages())
|
|
<button type="button"
|
|
onclick="handlePageChange({{ $paginator->currentPage() + 1 }})"
|
|
class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
|
|
다음
|
|
</button>
|
|
@else
|
|
<span class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-400 bg-gray-100 cursor-not-allowed">
|
|
다음
|
|
</span>
|
|
@endif
|
|
</div>
|
|
|
|
<!-- 데스크톱 네비게이션 -->
|
|
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
|
|
<div class="flex items-center gap-4">
|
|
<p class="text-sm text-gray-700">
|
|
전체 <span class="font-medium">{{ $paginator->total() }}</span>개 중
|
|
<span class="font-medium">{{ $paginator->firstItem() }}</span>
|
|
~
|
|
<span class="font-medium">{{ $paginator->lastItem() }}</span>
|
|
</p>
|
|
<!-- 페이지당 항목 수 선택 -->
|
|
<select name="per_page" id="perPageSelect"
|
|
style="min-width: 90px;"
|
|
class="px-3 py-1 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
onchange="handlePerPageChange(this.value)">
|
|
<option value="10" {{ $paginator->perPage() == 10 ? 'selected' : '' }}>10개씩</option>
|
|
<option value="20" {{ $paginator->perPage() == 20 ? 'selected' : '' }}>20개씩</option>
|
|
<option value="30" {{ $paginator->perPage() == 30 ? 'selected' : '' }}>30개씩</option>
|
|
<option value="50" {{ $paginator->perPage() == 50 ? 'selected' : '' }}>50개씩</option>
|
|
<option value="100" {{ $paginator->perPage() == 100 ? 'selected' : '' }}>100개씩</option>
|
|
<option value="200" {{ $paginator->perPage() == 200 ? 'selected' : '' }}>200개씩</option>
|
|
<option value="500" {{ $paginator->perPage() == 500 ? 'selected' : '' }}>500개씩</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px" aria-label="Pagination">
|
|
<!-- 처음으로 버튼 -->
|
|
@if ($paginator->onFirstPage())
|
|
<span class="relative inline-flex items-center px-3 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-300 cursor-not-allowed">
|
|
처음
|
|
</span>
|
|
@else
|
|
<button type="button"
|
|
onclick="handlePageChange(1)"
|
|
class="relative inline-flex items-center px-3 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50">
|
|
처음
|
|
</button>
|
|
@endif
|
|
|
|
<!-- 이전 버튼 -->
|
|
@if ($paginator->onFirstPage())
|
|
<span class="relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-300 cursor-not-allowed">
|
|
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
|
</svg>
|
|
</span>
|
|
@else
|
|
<button type="button"
|
|
onclick="handlePageChange({{ $paginator->currentPage() - 1 }})"
|
|
class="relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50">
|
|
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/>
|
|
</svg>
|
|
</button>
|
|
@endif
|
|
|
|
<!-- 페이지 번호 -->
|
|
@php
|
|
$currentPage = $paginator->currentPage();
|
|
$lastPage = $paginator->lastPage();
|
|
$maxPages = 10;
|
|
|
|
// 시작 페이지 계산
|
|
$startPage = max(1, $currentPage - floor($maxPages / 2));
|
|
$endPage = min($lastPage, $startPage + $maxPages - 1);
|
|
|
|
// 끝에서 10개를 채우지 못하면 시작 페이지 조정
|
|
if ($endPage - $startPage + 1 < $maxPages) {
|
|
$startPage = max(1, $endPage - $maxPages + 1);
|
|
}
|
|
@endphp
|
|
|
|
@foreach ($paginator->getUrlRange($startPage, $endPage) as $page => $url)
|
|
@if ($page == $paginator->currentPage())
|
|
<span class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-blue-50 text-sm font-medium text-blue-600">
|
|
{{ $page }}
|
|
</span>
|
|
@else
|
|
<button type="button"
|
|
onclick="handlePageChange({{ $page }})"
|
|
class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50">
|
|
{{ $page }}
|
|
</button>
|
|
@endif
|
|
@endforeach
|
|
|
|
<!-- 다음 버튼 -->
|
|
@if ($paginator->hasMorePages())
|
|
<button type="button"
|
|
onclick="handlePageChange({{ $paginator->currentPage() + 1 }})"
|
|
class="relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50">
|
|
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
|
|
</svg>
|
|
</button>
|
|
@else
|
|
<span class="relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-300 cursor-not-allowed">
|
|
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/>
|
|
</svg>
|
|
</span>
|
|
@endif
|
|
|
|
<!-- 끝으로 버튼 -->
|
|
@if ($paginator->hasMorePages())
|
|
<button type="button"
|
|
onclick="handlePageChange({{ $paginator->lastPage() }})"
|
|
class="relative inline-flex items-center px-3 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50">
|
|
끝
|
|
</button>
|
|
@else
|
|
<span class="relative inline-flex items-center px-3 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-300 cursor-not-allowed">
|
|
끝
|
|
</span>
|
|
@endif
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div> |