feat(admin): 활동 로그 페이지에 페이지 번호 직접 입력 기능 추가
- 페이지네이션을 3-column grid로 배치해 버튼 그룹은 중앙 정렬, 오른쪽 구석에 입력 박스 추가 - 숫자만 입력, Enter 또는 blur 시 페이지 이동 (1~totalPages로 clamp) - Enter 시 blur() 호출로 포커스 자동 해제 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8ece4b1850
commit
39bb6f77f9
1 changed files with 83 additions and 46 deletions
|
|
@ -27,6 +27,7 @@ function Logs() {
|
||||||
const [dateFrom, setDateFrom] = useState('');
|
const [dateFrom, setDateFrom] = useState('');
|
||||||
const [dateTo, setDateTo] = useState('');
|
const [dateTo, setDateTo] = useState('');
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
const [pageInput, setPageInput] = useState('1');
|
||||||
const [actorDropdownOpen, setActorDropdownOpen] = useState(false);
|
const [actorDropdownOpen, setActorDropdownOpen] = useState(false);
|
||||||
const [categoryDropdownOpen, setCategoryDropdownOpen] = useState(false);
|
const [categoryDropdownOpen, setCategoryDropdownOpen] = useState(false);
|
||||||
const [selectedLog, setSelectedLog] = useState(null);
|
const [selectedLog, setSelectedLog] = useState(null);
|
||||||
|
|
@ -65,6 +66,20 @@ function Logs() {
|
||||||
const total = data?.total || 0;
|
const total = data?.total || 0;
|
||||||
const totalPages = data?.totalPages || 0;
|
const totalPages = data?.totalPages || 0;
|
||||||
|
|
||||||
|
// 페이지 변경 시 입력 필드 동기화
|
||||||
|
useEffect(() => { setPageInput(String(currentPage)); }, [currentPage]);
|
||||||
|
|
||||||
|
const goToPageFromInput = () => {
|
||||||
|
const n = parseInt(pageInput, 10);
|
||||||
|
if (!Number.isFinite(n) || n < 1) {
|
||||||
|
setPageInput(String(currentPage));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const clamped = Math.min(totalPages, n);
|
||||||
|
setCurrentPage(clamped);
|
||||||
|
setPageInput(String(clamped));
|
||||||
|
};
|
||||||
|
|
||||||
// 카테고리 토글
|
// 카테고리 토글
|
||||||
const toggleCategory = (cat) => {
|
const toggleCategory = (cat) => {
|
||||||
setSelectedCategories((prev) =>
|
setSelectedCategories((prev) =>
|
||||||
|
|
@ -343,52 +358,74 @@ function Logs() {
|
||||||
|
|
||||||
{/* 페이지네이션 */}
|
{/* 페이지네이션 */}
|
||||||
{totalPages > 1 && (
|
{totalPages > 1 && (
|
||||||
<div className="flex items-center justify-center gap-2 mt-6">
|
<div className="grid grid-cols-3 items-center mt-6">
|
||||||
<button
|
<div />
|
||||||
onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
|
<div className="flex items-center justify-center gap-2">
|
||||||
disabled={currentPage === 1}
|
<button
|
||||||
className="p-2 rounded-lg hover:bg-gray-100 disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
|
onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
|
||||||
>
|
disabled={currentPage === 1}
|
||||||
<ChevronLeft size={18} />
|
className="p-2 rounded-lg hover:bg-gray-100 disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
|
||||||
</button>
|
>
|
||||||
{Array.from({ length: totalPages }, (_, i) => i + 1)
|
<ChevronLeft size={18} />
|
||||||
.filter((page) => {
|
</button>
|
||||||
if (totalPages <= 7) return true;
|
{Array.from({ length: totalPages }, (_, i) => i + 1)
|
||||||
if (page === 1 || page === totalPages) return true;
|
.filter((page) => {
|
||||||
if (Math.abs(page - currentPage) <= 2) return true;
|
if (totalPages <= 7) return true;
|
||||||
return false;
|
if (page === 1 || page === totalPages) return true;
|
||||||
})
|
if (Math.abs(page - currentPage) <= 2) return true;
|
||||||
.reduce((acc, page, i, arr) => {
|
return false;
|
||||||
if (i > 0 && page - arr[i - 1] > 1) {
|
})
|
||||||
acc.push({ type: 'ellipsis', key: `e-${page}` });
|
.reduce((acc, page, i, arr) => {
|
||||||
}
|
if (i > 0 && page - arr[i - 1] > 1) {
|
||||||
acc.push({ type: 'page', value: page, key: page });
|
acc.push({ type: 'ellipsis', key: `e-${page}` });
|
||||||
return acc;
|
}
|
||||||
}, [])
|
acc.push({ type: 'page', value: page, key: page });
|
||||||
.map((item) =>
|
return acc;
|
||||||
item.type === 'ellipsis' ? (
|
}, [])
|
||||||
<span key={item.key} className="w-9 h-9 flex items-center justify-center text-sm text-gray-400">...</span>
|
.map((item) =>
|
||||||
) : (
|
item.type === 'ellipsis' ? (
|
||||||
<button
|
<span key={item.key} className="w-9 h-9 flex items-center justify-center text-sm text-gray-400">...</span>
|
||||||
key={item.key}
|
) : (
|
||||||
onClick={() => setCurrentPage(item.value)}
|
<button
|
||||||
className={`w-9 h-9 rounded-lg text-sm font-medium transition-colors ${
|
key={item.key}
|
||||||
currentPage === item.value
|
onClick={() => setCurrentPage(item.value)}
|
||||||
? 'bg-primary text-white'
|
className={`w-9 h-9 rounded-lg text-sm font-medium transition-colors ${
|
||||||
: 'text-gray-600 hover:bg-gray-100'
|
currentPage === item.value
|
||||||
}`}
|
? 'bg-primary text-white'
|
||||||
>
|
: 'text-gray-600 hover:bg-gray-100'
|
||||||
{item.value}
|
}`}
|
||||||
</button>
|
>
|
||||||
)
|
{item.value}
|
||||||
)}
|
</button>
|
||||||
<button
|
)
|
||||||
onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}
|
)}
|
||||||
disabled={currentPage === totalPages}
|
<button
|
||||||
className="p-2 rounded-lg hover:bg-gray-100 disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
|
onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}
|
||||||
>
|
disabled={currentPage === totalPages}
|
||||||
<ChevronRight size={18} />
|
className="p-2 rounded-lg hover:bg-gray-100 disabled:opacity-30 disabled:cursor-not-allowed transition-colors"
|
||||||
</button>
|
>
|
||||||
|
<ChevronRight size={18} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-end gap-1.5">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
inputMode="numeric"
|
||||||
|
value={pageInput}
|
||||||
|
onChange={(e) => setPageInput(e.target.value.replace(/\D/g, ''))}
|
||||||
|
onBlur={goToPageFromInput}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
e.preventDefault();
|
||||||
|
goToPageFromInput();
|
||||||
|
e.currentTarget.blur();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className="w-12 h-9 text-center tabular-nums border border-gray-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent"
|
||||||
|
aria-label="페이지 번호 입력"
|
||||||
|
/>
|
||||||
|
<span className="text-sm text-gray-400 tabular-nums">/ {totalPages}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue