From 611abb5a76094072a1084e26e23653ce5fcf67d4 Mon Sep 17 00:00:00 2001
From: zenn
Date: Thu, 23 Jul 2026 16:50:01 +0900
Subject: [PATCH] =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20=ED=8E=98?=
=?UTF-8?q?=EC=9D=B4=EC=A7=80=EB=84=A4=EC=9D=B4=EC=85=98=20=EA=B3=B5?=
=?UTF-8?q?=ED=86=B5=ED=99=94?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
components/admin/AdminPagination.vue | 120 +++++++++++++++++++++++++++
docs/map.md | 1 +
docs/todo.md | 2 +-
docs/update.md | 5 ++
package-lock.json | 4 +-
package.json | 2 +-
pages/admin/media/index.vue | 88 ++------------------
pages/admin/posts/index.vue | 87 ++-----------------
8 files changed, 143 insertions(+), 166 deletions(-)
create mode 100644 components/admin/AdminPagination.vue
diff --git a/components/admin/AdminPagination.vue b/components/admin/AdminPagination.vue
new file mode 100644
index 0000000..7cde4d5
--- /dev/null
+++ b/components/admin/AdminPagination.vue
@@ -0,0 +1,120 @@
+
+
+
+
+
diff --git a/docs/map.md b/docs/map.md
index 378e56c..b4bb85a 100644
--- a/docs/map.md
+++ b/docs/map.md
@@ -188,6 +188,7 @@
| components/admin/AdminUnsavedChangesModal.vue | 관리자 편집 화면 공통 미저장 변경사항 이탈 확인 모달(상단 40px 위치) |
| components/admin/AdminConfirmModal.vue | 관리자 공통 확인 모달(제목·본문 슬롯·확인/취소 버튼, primary/danger 톤) |
| components/admin/AdminToast.vue | 관리자 공통 우측 상단 토스트 표시(성공·오류·안내 톤, 화면별 상단 위치 조정) |
+| components/admin/AdminPagination.vue | 관리자 공통 번호형 페이지네이션(이전·다음 화살표, 첫/끝/현재 주변 페이지, ellipsis 접기) |
| components/admin/AdminAnalyticsTrendChart.vue | 관리자 통계 추이 막대 차트(축 라벨·증감 툴팁·기간 페이지 이동) |
| lib/analytics-chart-ui.js | 통계 차트 라벨·페이지네이션·증감 계산 유틸 |
diff --git a/docs/todo.md b/docs/todo.md
index b4b2374..30fa058 100644
--- a/docs/todo.md
+++ b/docs/todo.md
@@ -9,7 +9,7 @@
- `components/admin/AdminPostForm.vue`: 태그 입력, 대표 이미지 선택, 발행/초안 저장 상태, 우측 설정 패널 책임을 분리.
- `pages/admin/media/index.vue`: 미디어 목록, 폴더 트리, 상세 모달, 재생성 액션을 작은 단위로 분리.
- 관리자 UI 공통 컴포넌트 정리.
- - 모달 패널, 필터 팝오버, 페이지네이션 툴바의 radius·shadow·z-index·색상 규칙을 공통화.
+ - 모달 패널, 필터 팝오버의 radius·shadow·z-index·색상 규칙을 공통화.
- 게시글/페이지/미디어 목록의 검색·필터·정렬 레이아웃을 같은 패턴으로 유지.
- 최근 브라우저 회귀 테스트 추가.
- 태그 추천 선택 후 다음 태그 후보가 포커스 해제 없이 유지되는지 확인.
diff --git a/docs/update.md b/docs/update.md
index 44098e8..7fc2dee 100644
--- a/docs/update.md
+++ b/docs/update.md
@@ -1,5 +1,10 @@
# 업데이트 이력
+## v1.11.6
+
+- 관리자 번호형 페이지네이션을 공용 `AdminPagination` 컴포넌트로 분리.
+- 게시글 목록과 미디어 목록의 페이지 버튼 계산·렌더링 중복 제거.
+
## v1.11.5
- 관리자 토스트 표시 마크업을 공용 `AdminToast` 컴포넌트로 분리.
diff --git a/package-lock.json b/package-lock.json
index 6e5ac43..99544ca 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "sori.studio",
- "version": "1.11.5",
+ "version": "1.11.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sori.studio",
- "version": "1.11.5",
+ "version": "1.11.6",
"hasInstallScript": true,
"dependencies": {
"@nuxtjs/tailwindcss": "^6.14.0",
diff --git a/package.json b/package.json
index 8283534..0e28c2d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "sori.studio",
- "version": "1.11.5",
+ "version": "1.11.6",
"private": true,
"type": "module",
"imports": {
diff --git a/pages/admin/media/index.vue b/pages/admin/media/index.vue
index 0f5739c..799de40 100644
--- a/pages/admin/media/index.vue
+++ b/pages/admin/media/index.vue
@@ -663,43 +663,6 @@ const isAllFilteredMediaSelected = computed(() => {
return filteredSelectableMediaUrls.value.every((url) => selectedMediaUrls.value.includes(url))
})
-const mediaPaginationItems = computed(() => {
- const total = mediaPageCount.value
- const current = mediaPage.value
-
- if (total <= 7) {
- return Array.from({ length: total }, (_, index) => index + 1)
- }
-
- const pages = new Set([1, total, current - 1, current, current + 1])
-
- if (current <= 4) {
- pages.add(2)
- pages.add(3)
- pages.add(4)
- pages.add(5)
- }
-
- if (current >= total - 3) {
- pages.add(total - 4)
- pages.add(total - 3)
- pages.add(total - 2)
- pages.add(total - 1)
- }
-
- const orderedPages = [...pages].filter((page) => page >= 1 && page <= total).sort((left, right) => left - right)
- return orderedPages.reduce((items, page, index) => {
- const previousPage = orderedPages[index - 1]
-
- if (previousPage && page - previousPage > 1) {
- items.push(`ellipsis-${previousPage}-${page}`)
- }
-
- items.push(page)
- return items
- }, [])
-})
-
/**
* 관리자 미디어 페이지를 변경한다.
* @param {number} page - 이동할 페이지
@@ -1706,53 +1669,16 @@ watch(() => mediaPagination.value.page, (page) => {
-
-
표시할 미디어가 없습니다.
+
+
diff --git a/pages/admin/posts/index.vue b/pages/admin/posts/index.vue
index 018f615..cbb1814 100644
--- a/pages/admin/posts/index.vue
+++ b/pages/admin/posts/index.vue
@@ -416,44 +416,6 @@ const hasActiveListFilters = computed(() => statusFilter.value !== 'all'
/** 글 목록 전체 페이지 수 */
const postPageCount = computed(() => Math.max(1, Number(postPagination.value.pageCount || 1)))
-/** 글 목록 페이지 버튼 항목 */
-const postPaginationItems = computed(() => {
- const total = postPageCount.value
- const current = postPage.value
-
- if (total <= 7) {
- return Array.from({ length: total }, (_, index) => index + 1)
- }
-
- const pages = new Set([1, total, current - 1, current, current + 1])
-
- if (current <= 4) {
- pages.add(2)
- pages.add(3)
- pages.add(4)
- pages.add(5)
- }
-
- if (current >= total - 3) {
- pages.add(total - 4)
- pages.add(total - 3)
- pages.add(total - 2)
- pages.add(total - 1)
- }
-
- const orderedPages = [...pages].filter((page) => page >= 1 && page <= total).sort((left, right) => left - right)
- return orderedPages.reduce((items, page, index) => {
- const previousPage = orderedPages[index - 1]
-
- if (previousPage && page - previousPage > 1) {
- items.push(`ellipsis-${previousPage}-${page}`)
- }
-
- items.push(page)
- return items
- }, [])
-})
-
/**
* 게시물 목록 썸네일 URL을 반환한다.
* @param {Object} post - 게시물
@@ -1341,49 +1303,12 @@ watch(postPageCount, (pageCount) => {
{{ totalPostCount === 0 ? '아직 작성된 글이 없습니다.' : '조건에 맞는 글이 없습니다.' }}
-
+