릴리스: v1.3.48 관리자 미리보기와 새로고침 로딩 보정

This commit is contained in:
2026-04-01 18:37:01 +09:00
parent 6828b868bc
commit d5b4de1629
4 changed files with 83 additions and 33 deletions

View File

@@ -1,5 +1,8 @@
# 의사결정 이력
## 2026-04-01 v1.3.48
- 관리자 탭 데이터는 첫 진입 로딩만 믿기보다, 인증 완료와 탭 전환 시점에 필요한 목록을 다시 채워 넣는 편이 실제 운영 화면에서 더 안정적이라고 정리했다.
- 템플릿 요청 미리보기는 일반 티어표 보기와 완전히 같은 구현을 억지로 분기하기보다, 같은 내부 프레임 문법과 정보 밀도를 먼저 맞춰 체감 차이를 줄이는 쪽이 현실적이라고 판단했다.
## 2026-04-01 v1.3.47
- 관리자 `사용자 템플릿 요청`도 결국 검수용 카드이므로, 요청 전용 카드 문법을 따로 두기보다 `전체 티어표 관리`와 같은 카드 구조를 재사용하는 편이 더 직관적이라고 정리했다.
- 새 템플릿 생성 요청의 기본 게임 ID는 사람이 읽기 어려운 난수보다 요청 단위에서 유일한 임시값을 먼저 채워두고, 승인 전에 관리자가 수정하는 흐름이 더 현실적이라고 판단했다.

View File

@@ -1,6 +1,7 @@
# 할 일 및 이슈
## 중기 개선
- 관리자 템플릿 요청 미리보기는 실제 완성본 iframe 방식과의 체감 차이를 마지막으로 한 번 더 QA한다.
- 라이트모드/다크모드 2차 보정까지 반영했으므로, 남은 작업은 전체 화면을 실제 사용 흐름으로 돌려 보며 대비·명도·아이콘 가독성을 미세하게 QA하는 최종 테마 점검 단계로 가져간다.
- 관리자용 티어표 승인/숨김 처리, 아이템 정렬 UI를 추가한다.
- 회원 일괄 작업(다중 선택, 일괄 비밀번호 초기화, 활동 저조 계정 정리) 같은 관리 보조 기능을 추가한다.

View File

@@ -1,5 +1,9 @@
# 업데이트 로그
## 2026-04-01 v1.3.48
- 관리자 화면은 새로고침 직후에도 `티어표 관리 / 회원 관리` 목록이 비지 않도록, 관리자 인증이 확정되거나 탭이 바뀔 때 해당 목록을 다시 불러오는 흐름으로 보강함.
- 관리자 아이템 모달은 내부 스크롤바를 숨기고 스크롤 체인을 끊어 배경이 함께 움직이지 않게 했고, 게임 선택 패널과 본문 패널의 상단 정렬도 다시 맞춤.
- 템플릿 요청 미리보기는 누락돼 있던 `requestPreview__frame / __header` 스타일을 보강해 일반 티어표 완성본과 더 비슷한 내부 프레임 구조와 보드 밀도로 다시 정리함.
## 2026-04-01 v1.3.47
- 관리자 `사용자 템플릿 요청` 카드는 별도 요청 전용 레이아웃 대신 `전체 티어표 관리`와 같은 카드 문법으로 맞추고, 왼쪽 썸네일 클릭으로 같은 미리보기 모달이 열리도록 정리함.
- 새 템플릿 요청에는 썸네일 아래에 `게임 이름 / 게임 ID` 입력을 두고, 초기 `게임 ID``new-template` 대신 요청 ID 기반의 임시 고유값으로 채워 나중에 수정하기 쉽게 바꿈.

View File

@@ -302,7 +302,44 @@ watch(
async (tab) => {
if (tab === 'game-admin' && selectedGameId.value && !selectedGame.value?.game?.id) {
await loadGame()
return
}
if (tab === 'items') {
customItemQuery.value = ''
customItemOrphanOnly.value = false
customItemPage.value = 1
customItemModalGameQuery.value = ''
await refreshCustomItems()
return
}
if (tab === 'tierlists') {
if (tierlistsMode.value === 'requests') await refreshTemplateRequests()
else await refreshAdminTierLists()
return
}
if (tab === 'users') {
await refreshUsers()
}
}
)
watch(
() => tierlistsMode.value,
async (mode) => {
if (activeTab.value !== 'tierlists') return
if (mode === 'requests') await refreshTemplateRequests()
else await refreshAdminTierLists()
}
)
watch(
() => auth.user?.id,
async (userId) => {
if (!userId || !auth.user?.isAdmin) return
await Promise.all([refreshGames(), refreshCustomItems(), refreshAdminTierLists(), refreshUsers(), refreshTemplateRequests(), refreshImageDiagnostics()])
}
)
@@ -2243,7 +2280,7 @@ async function saveFeaturedOrder() {
<div v-if="previewTierList?.requestPreview" class="requestPreview">
<div class="requestPreview__frame">
<div class="requestPreview__header">
<div class="requestPreview__title">{{ previewTierList.title || '티어표 미리보기' }}</div>
<div class="requestPreview__heroTitle">{{ previewTierList.title || '티어표 미리보기' }}</div>
<div v-if="previewTierList.description" class="requestPreview__desc">{{ previewTierList.description }}</div>
<div class="requestPreview__meta">
{{ previewRequestHasColumns(previewTierList) ? (previewRequestColumns(previewTierList).length + '열 구성') : '단일 열 구성' }} ·
@@ -3457,7 +3494,8 @@ async function saveFeaturedOrder() {
align-content: start;
gap: 18px;
overflow: auto;
padding-right: 6px;
padding-right: 0;
overscroll-behavior: contain;
scrollbar-width: none;
-ms-overflow-style: none;
}
@@ -3880,23 +3918,23 @@ async function saveFeaturedOrder() {
display: grid;
gap: 18px;
}
.requestPreview__summary {
.requestPreview__frame {
display: grid;
grid-template-columns: minmax(0, 1fr) 220px;
gap: 16px;
align-items: start;
}
.requestPreview__summaryBody {
display: grid;
gap: 8px;
}
.requestPreview__summaryThumb {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
border-radius: 18px;
gap: 26px;
padding: 28px;
border-radius: 24px;
border: 1px solid var(--theme-border);
background: var(--theme-surface-soft);
background: color-mix(in srgb, var(--theme-main-bg) 92%, transparent);
}
.requestPreview__header {
display: grid;
gap: 10px;
}
.requestPreview__heroTitle {
font-size: clamp(30px, 3vw, 48px);
line-height: 1.08;
font-weight: 900;
letter-spacing: -0.04em;
}
.requestPreview__meta {
color: var(--theme-text-soft);
@@ -3904,27 +3942,28 @@ async function saveFeaturedOrder() {
}
.requestPreview__desc {
color: var(--theme-text-muted);
line-height: 1.6;
line-height: 1.7;
white-space: pre-line;
font-size: 15px;
}
.requestPreview__board,
.requestPreview__pool {
display: grid;
gap: 12px;
gap: 14px;
}
.requestPreview__boardHead,
.requestPreview__row {
display: grid;
grid-template-columns: 92px minmax(0, 1fr);
gap: 12px;
grid-template-columns: 120px minmax(0, 1fr);
gap: 16px;
align-items: start;
}
.requestPreview__rowLabel,
.requestPreview__poolLabel,
.requestPreview__columnLabel {
font-size: 13px;
font-weight: 800;
color: rgba(255, 255, 255, 0.86);
font-size: 15px;
font-weight: 900;
color: var(--theme-text-strong);
}
.requestPreview__rowLabel--head {
color: var(--theme-text-faint);
@@ -3932,25 +3971,27 @@ async function saveFeaturedOrder() {
.requestPreview__columnLabels,
.requestPreview__cells {
display: grid;
gap: 12px;
gap: 14px;
}
.requestPreview__columnLabel,
.requestPreview__cell {
min-width: 0;
}
.requestPreview__columnLabel {
padding: 8px 4px;
text-align: center;
}
.requestPreview__cell {
padding: 10px;
border-radius: 16px;
min-height: 134px;
padding: 14px;
border-radius: 18px;
border: 1px solid var(--theme-border);
background: var(--theme-surface-soft);
}
.requestPreview__rowItems {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
gap: 10px;
}
.requestPreview__rowItems--pool {
grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
gap: 12px;
}
.requestPreview__rowItems--pool {
grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
@@ -3958,10 +3999,10 @@ async function saveFeaturedOrder() {
.requestPreview__item {
position: relative;
overflow: hidden;
border-radius: 14px;
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.12);
background: var(--theme-surface-soft);
min-height: 72px;
min-height: 84px;
}
.requestPreview__item--muted {
opacity: 0.52;
@@ -4146,6 +4187,7 @@ async function saveFeaturedOrder() {
padding: 20px;
background: color-mix(in srgb, var(--theme-body-bg) 76%, transparent);
backdrop-filter: blur(6px);
overscroll-behavior: contain;
}
.modalCard {
width: min(560px, 100%);