diff --git a/docs/history.md b/docs/history.md index 083d7c2..113f911 100644 --- a/docs/history.md +++ b/docs/history.md @@ -1,5 +1,9 @@ # 의사결정 이력 +## 2026-04-02 v1.3.73 +- 게임 선택이 여러 관리자 화면에 퍼지기 시작한 시점에서는 일부 화면만 셀렉트나 내부 리스트를 유지하기보다, 공용 검색 모달 하나로 통일하는 편이 장기적으로 더 일관되고 확장에 강하다고 정리했다. +- 검색 입력과 실행 버튼은 세로로 같은 문법으로 쌓기보다, 입력은 입력끼리 실행은 액션으로 읽히게 한 줄 배치로 적당히 구분해주는 편이 운영 화면에서 덜 답답하다고 판단했다. + ## 2026-04-02 v1.3.72 - 라우트 복원용 watcher가 composable 반환값 초기화보다 먼저 돌 수 있는 구간에서는 직접 함수를 즉시 호출하기보다, 초기화 완료 뒤 실행되도록 한 템포 미루는 편이 안전하다고 정리했다. diff --git a/docs/todo.md b/docs/todo.md index d9ab5c5..f300496 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -1,6 +1,7 @@ # 할 일 및 이슈 ## 단기 확인 +- 공용 게임 선택 모달을 아이템 관리 모달에도 붙였으므로, 관리자 `게임 관리 / 전체 티어표 관리 / 아이템 관리` 세 흐름에서 같은 검색/선택 UX가 자연스럽게 느껴지는지 한 번 더 QA한다. - 관리자 `/admin/games?gameId=...` 직접 진입과 새로고침에서 선택 게임이 정상 복원되고 콘솔 오류가 없는지 한 번 더 QA한다. - 공용 `게임 선택` 검색 모달은 새로 붙였으므로, 게임 관리 선택/전체 티어표 관리 필터 양쪽에서 검색어 입력, 선택, 해제, 뒤로가기 흐름을 한 번 더 QA한다. - 관리자 `전체 티어표 관리`의 게임 필터와 관리 모달은 새로 붙였으므로, 실제 운영 데이터에서 필터 전환 후 공개/비공개 집계, 제목 수정, 비공개 전환, 삭제 흐름이 자연스럽게 이어지는지 한 번 더 QA한다. diff --git a/docs/update.md b/docs/update.md index 2a79972..ea5ce08 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,5 +1,10 @@ # 업데이트 로그 +## 2026-04-02 v1.3.73 +- 전체 티어표 관리 카드 썸네일은 `draggable="false"`로 바꿔, 미리보기 진입 시 브라우저 기본 이미지 드래그가 클릭을 방해하지 않도록 정리함. +- 관리자 사이드바의 검색 입력과 검색 버튼은 한 줄로 묶어, 입력/선택/실행 버튼이 모두 같은 크기의 세로 스택처럼 보이던 답답함을 조금 줄이고 역할 구분을 더 분명하게 함. +- 아이템 관리 상세 모달의 템플릿 추가 대상 선택도 내부 전용 게임 리스트 대신 공용 `게임 선택` 검색 모달을 쓰도록 바꿔, 향후 게임 수가 많아져도 같은 선택 문법으로 이어지게 정리함. + ## 2026-04-02 v1.3.72 - 관리자 화면 초기화 중 `/admin/games?gameId=...` 경로를 즉시 처리하는 watcher가 `loadGame` 초기화보다 먼저 실행되어 브라우저 콘솔에 `Cannot access 'loadGame' before initialization` 오류가 나던 문제를 수정함. - 게임 라우트 진입 시 실제 게임 로딩 호출은 컴포넌트 초기화가 끝난 뒤 microtask로 미뤄 실행하도록 바꿔, 첫 진입/새로고침에서도 게임 선택 복원 흐름이 안전하게 이어지게 정리함. diff --git a/frontend/src/components/admin/AdminTierlistsSection.vue b/frontend/src/components/admin/AdminTierlistsSection.vue index f618c5e..499abc6 100644 --- a/frontend/src/components/admin/AdminTierlistsSection.vue +++ b/frontend/src/components/admin/AdminTierlistsSection.vue @@ -40,7 +40,7 @@ const props = defineProps({
@@ -142,7 +142,7 @@ const props = defineProps({
diff --git a/frontend/src/composables/useAdminCustomItems.js b/frontend/src/composables/useAdminCustomItems.js index c305da7..403f3bf 100644 --- a/frontend/src/composables/useAdminCustomItems.js +++ b/frontend/src/composables/useAdminCustomItems.js @@ -16,8 +16,6 @@ export function useAdminCustomItems({ customItemModalDraftLabel, customItemModalLabelSaving, customItemModalTargetGameId, - customItemModalGameQuery, - customItemModalGameSort, games, selectedGameId, refreshCustomItems, @@ -62,8 +60,6 @@ export function useAdminCustomItems({ modalTargetCustomItem.value = item || null customItemModalDraftLabel.value = item?.label || '' customItemModalTargetGameId.value = '' - customItemModalGameQuery.value = '' - customItemModalGameSort.value = 'recent' customItemModalOpen.value = true pushCustomItemModalHistoryState() } @@ -75,8 +71,6 @@ export function useAdminCustomItems({ customItemModalDraftLabel.value = '' customItemModalLabelSaving.value = false customItemModalTargetGameId.value = '' - customItemModalGameQuery.value = '' - customItemModalGameSort.value = 'recent' if (fromPopState) { customItemModalHistoryActive.value = false diff --git a/frontend/src/views/AdminView.vue b/frontend/src/views/AdminView.vue index 814f6c2..dd5091a 100644 --- a/frontend/src/views/AdminView.vue +++ b/frontend/src/views/AdminView.vue @@ -46,8 +46,6 @@ const customItemLimit = ref(50) const customItemTotal = ref(0) const customItemFilter = ref('all') const customItemModalTargetGameId = ref('') -const customItemModalGameQuery = ref('') -const customItemModalGameSort = ref('recent') const adminTierLists = ref([]) const adminTierListQuery = ref('') @@ -212,6 +210,7 @@ const filteredGamePickerGames = computed(() => { return Number(b.createdAt || 0) - Number(a.createdAt || 0) }) }) +const customItemTargetGame = computed(() => games.value.find((game) => game.id === customItemModalTargetGameId.value) || null) const importModalItemCount = computed(() => importModalItems.value.length) const activeTabTitle = computed(() => { if (activeTab.value === 'featured') return '목록 관리' @@ -490,7 +489,6 @@ watch( customItemQuery.value = '' customItemFilter.value = 'all' customItemPage.value = 1 - customItemModalGameQuery.value = '' await refreshCustomItems() return } @@ -622,21 +620,6 @@ const imageDiagnosticsCards = computed(() => { const visibleLinkedGames = computed(() => (modalTargetCustomItem.value?.linkedGames || []).filter((game) => game?.id && game.id !== 'freeform') ) -const filteredCustomItemModalGames = computed(() => { - const query = customItemModalGameQuery.value.trim().toLowerCase() - const linkedIds = new Set(visibleLinkedGames.value.map((game) => game.id)) - const list = games.value.filter((game) => { - if (!query) return true - return `${game.name || ''} ${game.id || ''}`.toLowerCase().includes(query) - }) - - return list.slice().sort((a, b) => { - const linkedDelta = Number(linkedIds.has(a.id)) - Number(linkedIds.has(b.id)) - if (linkedDelta !== 0) return linkedDelta - if (customItemModalGameSort.value === 'oldest') return Number(a.createdAt || 0) - Number(b.createdAt || 0) - return Number(b.createdAt || 0) - Number(a.createdAt || 0) - }) -}) const imageStatsPeriodLabel = computed(() => (imageStatsMonth.value ? `${imageStatsMonth.value} 기준` : '전체 기간')) const imageStatsYearOptions = computed(() => { @@ -1040,8 +1023,6 @@ const { customItemModalDraftLabel, customItemModalLabelSaving, customItemModalTargetGameId, - customItemModalGameQuery, - customItemModalGameSort, games, selectedGameId, refreshCustomItems, @@ -1327,6 +1308,11 @@ async function chooseGameFromPicker(gameId) { closeGamePickerModal() return } + if (gamePickerMode.value === 'custom-item-target') { + customItemModalTargetGameId.value = gameId + closeGamePickerModal() + return + } await selectAdminGame(gameId) closeGamePickerModal() @@ -1963,32 +1949,16 @@ function userAvatarFallback(user) {
GAME PICKER
템플릿으로 추가할 게임
+
+
+
선택한 게임
+
{{ customItemTargetGame?.name || '아직 선택하지 않음' }}
+
{{ customItemTargetGame?.id || '게임을 골라 주세요.' }}
+
+
+
-
- - -
-
- -
@@ -2244,8 +2214,10 @@ function userAvatarFallback(user) {
Filters
- - +
+ + +