관리자 백링크 모달 검색 개선

This commit is contained in:
2026-07-10 17:08:14 +09:00
parent 04c03ad604
commit cf7d6ca0de
7 changed files with 83 additions and 23 deletions

View File

@@ -30,6 +30,7 @@ const referenceModalPost = ref(null)
const referenceModalData = ref(createDefaultPostReferences())
const referenceModalLoading = ref(false)
const referenceModalError = ref('')
const referenceModalSearchQuery = ref('')
const postMenuTriggerRefs = new Map()
const tagFilterRef = ref(null)
const postSearchInputRef = ref(null)
@@ -470,6 +471,25 @@ const isReferenceModalOpen = computed(() => Boolean(referenceModalPost.value))
/** 게시물 참조 목록 */
const referenceModalPosts = computed(() => referenceModalData.value?.posts || [])
/** 게시물 참조 모달 검색어 */
const normalizedReferenceModalSearchQuery = computed(() => referenceModalSearchQuery.value.trim().toLowerCase())
/** 검색어가 적용된 게시물 참조 목록 */
const filteredReferenceModalPosts = computed(() => {
const keyword = normalizedReferenceModalSearchQuery.value
if (!keyword) {
return referenceModalPosts.value
}
return referenceModalPosts.value.filter((post) => {
return [
post.title,
post.slug
].some((value) => String(value || '').toLowerCase().includes(keyword))
})
})
/** 통계 모달 검색 유입 조회수 */
const analyticsModalSearchViews = computed(() => getAnalyticsSourceGroupViews(['search']))
@@ -611,6 +631,7 @@ const openReferenceModal = async (post) => {
referenceModalPost.value = post
referenceModalData.value = createDefaultPostReferences()
referenceModalError.value = ''
referenceModalSearchQuery.value = ''
referenceModalLoading.value = true
try {
@@ -630,6 +651,7 @@ const closeReferenceModal = () => {
referenceModalPost.value = null
referenceModalData.value = createDefaultPostReferences()
referenceModalError.value = ''
referenceModalSearchQuery.value = ''
referenceModalLoading.value = false
}
@@ -908,7 +930,7 @@ const onDocumentKeydown = (event) => {
}
if (
event.key.toLowerCase() === 'f'
['f', 'ㄹ'].includes(event.key.toLowerCase())
&& !event.metaKey
&& !event.ctrlKey
&& !event.altKey
@@ -1318,7 +1340,7 @@ watch(postPageCount, (pageCount) => {
<td class="admin-posts__cell admin-posts__cell-backlinks px-4 py-4">
<button
v-if="Number(post.backlinkCount || 0) > 0"
class="admin-posts__backlink-count inline-flex min-w-8 justify-center rounded border border-[#d7dce0] bg-white px-2 py-1 text-xs font-semibold text-[#394047] transition-colors hover:border-[#8e9cac] hover:bg-paper"
class="admin-posts__backlink-count text-sm font-semibold text-[#394047] underline-offset-4 transition-colors hover:text-[#15171a] hover:underline"
type="button"
@click="openReferenceModal(post)"
>
@@ -1478,7 +1500,7 @@ watch(postPageCount, (pageCount) => {
aria-labelledby="admin-posts-reference-modal-title"
@pointerdown.self="closeReferenceModal"
>
<article class="admin-posts__reference-modal-panel max-h-[86vh] w-full max-w-2xl overflow-y-auto rounded-lg border border-line bg-white shadow-xl">
<article class="admin-posts__reference-modal-panel flex h-[min(720px,86vh)] w-full max-w-2xl flex-col overflow-hidden rounded-lg border border-line bg-white shadow-xl">
<header class="admin-posts__reference-modal-header flex items-start justify-between gap-4 border-b border-line px-5 py-4">
<div class="min-w-0">
<p class="text-xs font-semibold uppercase text-muted">
@@ -1492,15 +1514,20 @@ watch(postPageCount, (pageCount) => {
</p>
</div>
<button
class="admin-posts__reference-modal-close border border-line px-3 py-1 text-xs font-medium text-muted hover:bg-paper hover:text-ink"
class="admin-posts__reference-modal-close inline-flex cursor-pointer items-center justify-center rounded text-sm font-semibold whitespace-nowrap text-[#5d6673] transition hover:text-[#15171a]"
type="button"
title="닫기 (ESC)"
aria-label="백링크 모달 닫기"
@click="closeReferenceModal"
>
닫기
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="pointer-events-none size-5" fill="none" aria-hidden="true">
<line x1="0.75" y1="23.249" x2="23.25" y2="0.749" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />
<line x1="23.25" y1="23.249" x2="0.75" y2="0.749" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />
</svg>
</button>
</header>
<div class="admin-posts__reference-modal-body p-5">
<div class="admin-posts__reference-modal-body flex min-h-0 flex-1 flex-col p-5">
<p v-if="referenceModalLoading" class="text-sm text-muted">
이 글을 링크한 게시물을 확인하는 중입니다.
</p>
@@ -1508,12 +1535,27 @@ watch(postPageCount, (pageCount) => {
{{ referenceModalError }}
</p>
<template v-else>
<p class="text-sm text-muted">
이 글을 링크한 게시물 {{ referenceModalPosts.length }}개
</p>
<ul v-if="referenceModalPosts.length" class="mt-4 divide-y divide-line border border-line">
<div class="flex flex-wrap items-center justify-between gap-3">
<p class="text-sm text-muted">
이 글을 링크한 게시물 {{ referenceModalPosts.length }}개
</p>
<label class="admin-posts__reference-search relative w-full sm:w-60">
<span class="sr-only">백링크 검색</span>
<svg class="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-[#8e9cac]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="m21 21-4.34-4.34" />
<circle cx="11" cy="11" r="8" />
</svg>
<input
v-model="referenceModalSearchQuery"
class="admin-posts__reference-search-input h-9 w-full rounded border border-line bg-white pl-9 pr-3 text-sm text-[#394047] outline-none transition-colors placeholder:text-[#8e9cac] hover:border-[#c8ced3] focus:border-[#8e9cac]"
type="search"
placeholder="게시물 검색"
>
</label>
</div>
<ul v-if="filteredReferenceModalPosts.length" class="mt-4 min-h-0 flex-1 divide-y divide-line overflow-y-auto border border-line">
<li
v-for="item in referenceModalPosts"
v-for="item in filteredReferenceModalPosts"
:key="item.id"
class="admin-posts__reference-item bg-white px-4 py-3"
>
@@ -1521,16 +1563,18 @@ watch(postPageCount, (pageCount) => {
<span class="min-w-0 font-semibold text-ink">
{{ item.title || '(제목 없음)' }}
</span>
<div class="flex shrink-0 items-center gap-3">
<span class="text-xs text-muted">
{{ item.referenceCount }}회 링크
</span>
<div class="flex shrink-0 items-center gap-2">
<NuxtLink
class="admin-posts__reference-move inline-flex h-8 items-center border border-line px-3 text-xs font-semibold text-[#394047] transition-colors hover:bg-paper"
class="admin-posts__reference-move inline-flex size-7 items-center justify-center rounded text-[#8e9cac] transition-colors hover:bg-paper hover:text-[#394047]"
:to="`/admin/posts/${item.id}`"
aria-label="게시물로 이동"
title="게시물로 이동"
@click="closeReferenceModal"
>
이동
<svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M17 7 7 17" />
<path d="M8 7h9v9" />
</svg>
</NuxtLink>
</div>
</div>
@@ -1543,6 +1587,9 @@ watch(postPageCount, (pageCount) => {
</div>
</li>
</ul>
<p v-else-if="referenceModalPosts.length" class="mt-4 border border-line bg-paper px-4 py-5 text-sm text-muted">
검색 결과가 없습니다.
</p>
<p v-else class="mt-4 border border-line bg-paper px-4 py-5 text-sm text-muted">
이 게시물을 링크한 다른 게시물이 없습니다.
</p>