사이트 광고 슬롯 설정 추가
This commit is contained in:
@@ -33,6 +33,7 @@ const savingBrand = ref(false)
|
||||
const savingAnnouncement = ref(false)
|
||||
const savingSpam = ref(false)
|
||||
const savingSiteCode = ref(false)
|
||||
const savingAds = ref(false)
|
||||
const uploadingLogo = ref(false)
|
||||
const uploadingHomeCover = ref(false)
|
||||
const uploadingHomeCoverDark = ref(false)
|
||||
@@ -81,6 +82,8 @@ const customizeAnnouncement = ref(false)
|
||||
const editSpam = ref(false)
|
||||
/** 사이트 코드 카드 편집 모드 여부 */
|
||||
const editSiteCode = ref(false)
|
||||
/** 광고 슬롯 카드 편집 모드 여부 */
|
||||
const editAds = ref(false)
|
||||
/** 편집 시작 시점의 제목·설명(취소 시 복원용) */
|
||||
const titleDescSnapshot = reactive({
|
||||
title: '',
|
||||
@@ -131,6 +134,13 @@ const siteCodeSnapshot = reactive({
|
||||
customHeadCode: '',
|
||||
customFooterCode: ''
|
||||
})
|
||||
/** 편집 시작 시점의 광고 슬롯(취소 시 복원용) */
|
||||
const adsSnapshot = reactive({
|
||||
adHomeFeedCode: '',
|
||||
adSidebarCode: '',
|
||||
adPostTopCode: '',
|
||||
adPostBottomCode: ''
|
||||
})
|
||||
let toastTimer = null
|
||||
let scrollSpyFrame = null
|
||||
let postExportRefreshTimer = null
|
||||
@@ -166,7 +176,11 @@ const form = reactive({
|
||||
signupBlockedUsernames: normalizeSignupBlockedUsernames(settings.value?.signupBlockedUsernames),
|
||||
adsTxt: settings.value?.adsTxt || '',
|
||||
customHeadCode: settings.value?.customHeadCode || '',
|
||||
customFooterCode: settings.value?.customFooterCode || ''
|
||||
customFooterCode: settings.value?.customFooterCode || '',
|
||||
adHomeFeedCode: settings.value?.adHomeFeedCode || '',
|
||||
adSidebarCode: settings.value?.adSidebarCode || '',
|
||||
adPostTopCode: settings.value?.adPostTopCode || '',
|
||||
adPostBottomCode: settings.value?.adPostBottomCode || ''
|
||||
})
|
||||
|
||||
/**
|
||||
@@ -251,6 +265,17 @@ const hasSiteCodeChanges = computed(() => editSiteCode.value && (
|
||||
|| form.customFooterCode !== siteCodeSnapshot.customFooterCode
|
||||
))
|
||||
|
||||
/**
|
||||
* 광고 슬롯 변경 여부
|
||||
* @returns {boolean} 변경 여부
|
||||
*/
|
||||
const hasAdsChanges = computed(() => editAds.value && (
|
||||
form.adHomeFeedCode !== adsSnapshot.adHomeFeedCode
|
||||
|| form.adSidebarCode !== adsSnapshot.adSidebarCode
|
||||
|| form.adPostTopCode !== adsSnapshot.adPostTopCode
|
||||
|| form.adPostBottomCode !== adsSnapshot.adPostBottomCode
|
||||
))
|
||||
|
||||
/**
|
||||
* 최신 게시물 export 작업 목록
|
||||
* @returns {Array} export 작업 목록
|
||||
@@ -520,7 +545,8 @@ const settingsNavGroups = [
|
||||
{ id: 'admin-settings-section-home-cover', label: '메인 화면', keywords: 'home cover hero banner image', iconId: 'home-cover' },
|
||||
{ id: 'admin-settings-section-brand', label: '브랜드', keywords: 'brand design accent color point 포인트 컬러', iconId: 'site-code' },
|
||||
{ id: 'admin-settings-section-announcement', label: '어나운스 바', keywords: 'announcement banner notice', iconId: 'announcement' },
|
||||
{ id: 'admin-settings-section-site-code', label: '사이트 코드', keywords: 'ads ads.txt head footer script code adsense', iconId: 'site-code' }
|
||||
{ id: 'admin-settings-section-site-code', label: '사이트 코드', keywords: 'ads ads.txt head footer script code adsense', iconId: 'site-code' },
|
||||
{ id: 'admin-settings-section-ads', label: 'Ads', keywords: 'ads ad slot advertisement adsense 광고 애드센스', iconId: 'site-code' }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1100,7 +1126,11 @@ const buildSiteSettingsPayload = () => ({
|
||||
signupBlockedUsernames: normalizeSignupBlockedUsernames(form.signupBlockedUsernames),
|
||||
adsTxt: form.adsTxt || '',
|
||||
customHeadCode: form.customHeadCode || '',
|
||||
customFooterCode: form.customFooterCode || ''
|
||||
customFooterCode: form.customFooterCode || '',
|
||||
adHomeFeedCode: form.adHomeFeedCode || '',
|
||||
adSidebarCode: form.adSidebarCode || '',
|
||||
adPostTopCode: form.adPostTopCode || '',
|
||||
adPostBottomCode: form.adPostBottomCode || ''
|
||||
})
|
||||
|
||||
/**
|
||||
@@ -1684,6 +1714,53 @@ const saveSiteCodeSection = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 광고 슬롯 편집 모드 진입
|
||||
* @returns {void}
|
||||
*/
|
||||
const beginEditAds = () => {
|
||||
adsSnapshot.adHomeFeedCode = form.adHomeFeedCode
|
||||
adsSnapshot.adSidebarCode = form.adSidebarCode
|
||||
adsSnapshot.adPostTopCode = form.adPostTopCode
|
||||
adsSnapshot.adPostBottomCode = form.adPostBottomCode
|
||||
editAds.value = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 광고 슬롯 편집 취소
|
||||
* @returns {void}
|
||||
*/
|
||||
const cancelEditAds = () => {
|
||||
form.adHomeFeedCode = adsSnapshot.adHomeFeedCode
|
||||
form.adSidebarCode = adsSnapshot.adSidebarCode
|
||||
form.adPostTopCode = adsSnapshot.adPostTopCode
|
||||
form.adPostBottomCode = adsSnapshot.adPostBottomCode
|
||||
editAds.value = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 광고 슬롯 설정 저장
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const saveAdsSection = async () => {
|
||||
if (!hasAdsChanges.value) {
|
||||
return
|
||||
}
|
||||
|
||||
const ok = await persistSiteSettings({
|
||||
successToast: '광고 슬롯 설정이 저장되었습니다.',
|
||||
savingFlag: savingAds
|
||||
})
|
||||
|
||||
if (ok) {
|
||||
adsSnapshot.adHomeFeedCode = form.adHomeFeedCode
|
||||
adsSnapshot.adSidebarCode = form.adSidebarCode
|
||||
adsSnapshot.adPostTopCode = form.adPostTopCode
|
||||
adsSnapshot.adPostBottomCode = form.adPostBottomCode
|
||||
editAds.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape 키: 제목·설명 편집 중이면 취소, 아니면 설정 화면 닫기
|
||||
* @param {KeyboardEvent} event - 키보드 이벤트
|
||||
@@ -1728,6 +1805,11 @@ const onGlobalKeydown = (event) => {
|
||||
cancelEditSiteCode()
|
||||
return
|
||||
}
|
||||
if (editAds.value) {
|
||||
event.preventDefault()
|
||||
cancelEditAds()
|
||||
return
|
||||
}
|
||||
closeSettings()
|
||||
}
|
||||
|
||||
@@ -2919,6 +3001,16 @@ onBeforeUnmount(() => {
|
||||
@save="saveSiteCodeSection"
|
||||
/>
|
||||
|
||||
<AdminAdsSettingsCard
|
||||
:form="form"
|
||||
:editing="editAds"
|
||||
:saving="savingAds"
|
||||
:has-changes="hasAdsChanges"
|
||||
@begin="beginEditAds"
|
||||
@cancel="cancelEditAds"
|
||||
@save="saveAdsSection"
|
||||
/>
|
||||
|
||||
<h2 class="admin-settings-screen__section-heading z-20 mb-px pt-10 text-2xl font-bold tracking-tight text-[#15171a]">
|
||||
콘텐츠·안전
|
||||
</h2>
|
||||
|
||||
@@ -348,6 +348,12 @@ const scrollFeatured = (direction) => {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<SiteAdSlot
|
||||
class="home-page__ad-slot px-6 py-4"
|
||||
:code="siteSettings?.adHomeFeedCode"
|
||||
location="home-feed"
|
||||
/>
|
||||
|
||||
<section class="latest-posts-section min-h-[360px] py-4 px-6">
|
||||
<div class="mx-auto max-w-[720px]">
|
||||
<div class="flex items-end justify-between gap-2 border-b border-[var(--site-line)] pb-2">
|
||||
|
||||
@@ -15,6 +15,9 @@ const { data: tags } = await useFetch('/api/tags', {
|
||||
const { data: posts } = await useFetch('/api/posts', {
|
||||
default: () => []
|
||||
})
|
||||
const { data: siteSettings } = await useFetch('/api/site-settings', {
|
||||
default: () => ({})
|
||||
})
|
||||
const postToc = useState('post-detail-toc', () => [])
|
||||
|
||||
if (!post.value) {
|
||||
@@ -338,9 +341,19 @@ useHead(() => ({
|
||||
|
||||
<section>
|
||||
<div class="mx-auto max-w-[720px] px-4 sm:px-5">
|
||||
<SiteAdSlot
|
||||
class="post-detail__ad-slot post-detail__ad-slot--top mb-8"
|
||||
:code="siteSettings?.adPostTopCode"
|
||||
location="post-top"
|
||||
/>
|
||||
<ContentRenderer>
|
||||
<ContentMarkdownRenderer class="post-detail__content" :content="post.content" />
|
||||
</ContentRenderer>
|
||||
<SiteAdSlot
|
||||
class="post-detail__ad-slot post-detail__ad-slot--bottom mt-8"
|
||||
:code="siteSettings?.adPostBottomCode"
|
||||
location="post-bottom"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user