설정 화면 메인 커버 UI 정리 v1.5.29
This commit is contained in:
@@ -47,7 +47,7 @@ const activeSectionId = ref('admin-settings-section-title')
|
||||
const scrollSpySuspended = ref(false)
|
||||
/** 블로그 제목·설명 카드 편집 모드 여부 */
|
||||
const editTitleDesc = ref(false)
|
||||
/** 기타 설정 카드 편집 모드 여부 */
|
||||
/** 사이트 정보 카드 편집 모드 여부 */
|
||||
const editMisc = ref(false)
|
||||
/** POST 설정 카드 편집 모드 여부 */
|
||||
const editPost = ref(false)
|
||||
@@ -62,7 +62,7 @@ const titleDescSnapshot = reactive({
|
||||
title: '',
|
||||
description: ''
|
||||
})
|
||||
/** 편집 시작 시점의 기타 설정(취소 시 복원용) */
|
||||
/** 편집 시작 시점의 사이트 정보(취소 시 복원용) */
|
||||
const miscSnapshot = reactive({
|
||||
siteUrl: '',
|
||||
logoText: '',
|
||||
@@ -134,7 +134,7 @@ const hasTitleDescChanges = computed(() => editTitleDesc.value && (
|
||||
))
|
||||
|
||||
/**
|
||||
* 기타 설정 변경 여부
|
||||
* 사이트 정보 변경 여부
|
||||
* @returns {boolean} 변경 여부
|
||||
*/
|
||||
const hasMiscChanges = computed(() => editMisc.value && (
|
||||
@@ -434,8 +434,7 @@ const settingsNavGroups = [
|
||||
heading: '일반',
|
||||
items: [
|
||||
{ id: 'admin-settings-section-title', label: '블로그 제목·설명', keywords: 'title description site name', iconId: 'title-desc' },
|
||||
{ id: 'admin-settings-section-timezone', label: '타임존', keywords: 'timezone seoul gmt', iconId: 'timezone' },
|
||||
{ id: 'admin-settings-section-misc', label: '기타 설정', keywords: 'logo url copyright favicon' }
|
||||
{ id: 'admin-settings-section-misc', label: '사이트 정보', keywords: 'logo url copyright favicon site info' }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -927,7 +926,7 @@ const saveTitleDescSection = async () => {
|
||||
}
|
||||
|
||||
/**
|
||||
* 기타 설정 편집 모드 진입
|
||||
* 사이트 정보 편집 모드 진입
|
||||
* @returns {void}
|
||||
*/
|
||||
const beginEditMisc = () => {
|
||||
@@ -940,7 +939,7 @@ const beginEditMisc = () => {
|
||||
}
|
||||
|
||||
/**
|
||||
* 기타 설정 편집 취소
|
||||
* 사이트 정보 편집 취소
|
||||
* @returns {void}
|
||||
*/
|
||||
const cancelEditMisc = () => {
|
||||
@@ -953,7 +952,7 @@ const cancelEditMisc = () => {
|
||||
}
|
||||
|
||||
/**
|
||||
* 기타 설정 저장
|
||||
* 사이트 정보 저장
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const saveMiscSection = async () => {
|
||||
@@ -962,7 +961,7 @@ const saveMiscSection = async () => {
|
||||
}
|
||||
|
||||
const ok = await persistSiteSettings({
|
||||
successToast: '기타 설정이 저장되었습니다.',
|
||||
successToast: '사이트 정보가 저장되었습니다.',
|
||||
savingFlag: savingMisc
|
||||
})
|
||||
|
||||
@@ -1039,14 +1038,12 @@ const openHomeCoverDarkFilePicker = () => {
|
||||
}
|
||||
|
||||
/**
|
||||
* 메인 화면 커버 이미지를 업로드한다.
|
||||
* @param {Event} event - 파일 선택 이벤트
|
||||
* 메인 화면 커버 이미지 파일을 업로드한다.
|
||||
* @param {File} file - 업로드 파일
|
||||
* @param {'light'|'dark'} variant - 커버 이미지 종류
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const uploadHomeCover = async (event, variant = 'light') => {
|
||||
const target = /** @type {HTMLInputElement | null} */ (event.target instanceof HTMLInputElement ? event.target : null)
|
||||
const file = target?.files?.[0]
|
||||
const uploadHomeCoverFile = async (file, variant = 'light') => {
|
||||
const uploadingFlag = variant === 'dark' ? uploadingHomeCoverDark : uploadingHomeCover
|
||||
|
||||
if (!file || uploadingFlag.value) {
|
||||
@@ -1075,12 +1072,48 @@ const uploadHomeCover = async (event, variant = 'light') => {
|
||||
showToast('error', errorMessage.value)
|
||||
} finally {
|
||||
uploadingFlag.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 메인 화면 커버 이미지를 업로드한다.
|
||||
* @param {Event} event - 파일 선택 이벤트
|
||||
* @param {'light'|'dark'} variant - 커버 이미지 종류
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const uploadHomeCover = async (event, variant = 'light') => {
|
||||
const target = /** @type {HTMLInputElement | null} */ (event.target instanceof HTMLInputElement ? event.target : null)
|
||||
const file = target?.files?.[0]
|
||||
|
||||
if (!file) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await uploadHomeCoverFile(file, variant)
|
||||
} finally {
|
||||
if (target) {
|
||||
target.value = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 드롭된 메인 화면 커버 이미지를 업로드한다.
|
||||
* @param {DragEvent} event - 드롭 이벤트
|
||||
* @param {'light'|'dark'} variant - 커버 이미지 종류
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const dropHomeCover = async (event, variant = 'light') => {
|
||||
const file = event.dataTransfer?.files?.[0]
|
||||
|
||||
if (!file) {
|
||||
return
|
||||
}
|
||||
|
||||
await uploadHomeCoverFile(file, variant)
|
||||
}
|
||||
|
||||
/**
|
||||
* 메인 화면 커버 이미지를 제거한다.
|
||||
* @param {'light'|'dark'} variant - 커버 이미지 종류
|
||||
@@ -1514,23 +1547,6 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
id="admin-settings-section-timezone"
|
||||
class="admin-settings-screen__card rounded-xl border border-[#e6e8eb] bg-white p-6 shadow-[0_1px_2px_rgba(15,23,42,0.04)]"
|
||||
>
|
||||
<div class="admin-settings-screen__card-head mb-2">
|
||||
<h2 class="text-lg font-semibold text-[#15171a]">
|
||||
타임존
|
||||
</h2>
|
||||
<p class="mt-1 text-sm leading-relaxed text-[#657080]">
|
||||
게시 시각·예약 발행 등에 사용할 표준 시간대입니다. (준비 중)
|
||||
</p>
|
||||
</div>
|
||||
<div class="admin-settings-screen__placeholder mt-4 rounded-lg border border-dashed border-[#dce0e5] bg-[#f7f8fa] px-4 py-8 text-center text-sm text-[#657080]">
|
||||
이후 버전에서 타임존 선택과 현지 시각 미리보기를 제공합니다.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
id="admin-settings-section-misc"
|
||||
class="admin-settings-screen__card rounded-xl border border-[#e6e8eb] bg-white p-6 shadow-[0_1px_2px_rgba(15,23,42,0.04)]"
|
||||
@@ -1538,7 +1554,7 @@ onBeforeUnmount(() => {
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div class="min-w-0 flex-1">
|
||||
<h2 class="text-base font-semibold text-[#15171a] md:text-lg">
|
||||
기타 설정
|
||||
사이트 정보
|
||||
</h2>
|
||||
<p
|
||||
v-if="!editMisc"
|
||||
@@ -1829,29 +1845,69 @@ onBeforeUnmount(() => {
|
||||
v-if="!editHomeCover"
|
||||
class="admin-settings-screen__home-cover-readonly grid gap-4 border-t border-[#eceff2] pt-5 text-sm"
|
||||
>
|
||||
<div v-if="form.homeCoverImageUrl || form.homeCoverDarkImageUrl" class="admin-settings-screen__home-cover-preview w-full max-w-[720px] overflow-hidden rounded-lg border border-[#e6e8eb]">
|
||||
<HomeHero
|
||||
:image-url="form.homeCoverImageUrl"
|
||||
:dark-image-url="form.homeCoverDarkImageUrl"
|
||||
:title="form.homeCoverTitle"
|
||||
:text="form.homeCoverText"
|
||||
/>
|
||||
<div class="grid gap-6">
|
||||
<div class="admin-settings-screen__home-cover-mode grid gap-2">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<h3 class="text-sm font-bold text-[#15171a]">
|
||||
라이트모드
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
v-if="form.homeCoverImageUrl"
|
||||
class="admin-settings-screen__home-cover-preview w-full max-w-[720px] overflow-hidden rounded-lg border border-[#e6e8eb]"
|
||||
>
|
||||
<HomeHero
|
||||
:image-url="form.homeCoverImageUrl"
|
||||
:dark-image-url="''"
|
||||
:title="form.homeCoverTitle"
|
||||
:text="form.homeCoverText"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="admin-settings-screen__home-cover-empty grid aspect-[720/215] w-full max-w-[720px] place-items-center rounded-lg border border-dashed border-[#cfd6de] bg-[#f7f8fa] px-4 text-center text-sm text-[#657080]"
|
||||
>
|
||||
라이트모드 이미지가 없습니다.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-settings-screen__home-cover-mode grid gap-2">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<h3 class="text-sm font-bold text-[#15171a]">
|
||||
다크모드
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
v-if="form.homeCoverDarkImageUrl"
|
||||
class="admin-settings-screen__home-cover-preview w-full max-w-[720px] overflow-hidden rounded-lg border border-[#e6e8eb]"
|
||||
>
|
||||
<HomeHero
|
||||
:image-url="form.homeCoverDarkImageUrl"
|
||||
:dark-image-url="''"
|
||||
:title="form.homeCoverTitle"
|
||||
:text="form.homeCoverText"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="admin-settings-screen__home-cover-empty grid aspect-[720/215] w-full max-w-[720px] place-items-center rounded-lg border border-dashed border-[#cfd6de] bg-[#f7f8fa] px-4 text-center text-sm text-[#657080]"
|
||||
>
|
||||
다크모드 전용 이미지가 없습니다. 공개 화면에서는 라이트모드 이미지를 대신 사용합니다.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p v-else class="text-[#657080]">
|
||||
등록된 커버 이미지가 없습니다. 홈 상단 배너는 표시되지 않습니다.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-else class="admin-settings-screen__home-cover-edit grid gap-6 border-t border-[#eceff2] pt-5">
|
||||
<div class="grid gap-4 md:grid-cols-2">
|
||||
<div class="admin-settings-screen__home-cover-upload rounded-lg border border-[#e6e8eb] bg-[#fbfbfc] p-4">
|
||||
<div class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div class="min-w-0 flex-1">
|
||||
<h3 class="text-sm font-medium text-[#3f4650]">
|
||||
라이트모드 이미지
|
||||
<div class="grid gap-6">
|
||||
<div class="admin-settings-screen__home-cover-mode grid gap-2">
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div class="min-w-0">
|
||||
<h3 class="text-sm font-bold text-[#15171a]">
|
||||
라이트모드
|
||||
</h3>
|
||||
<p class="mt-1 text-sm leading-relaxed text-[#657080]">
|
||||
기본 헤더 이미지입니다. 다크 이미지가 없으면 다크모드에서도 이 이미지를 사용합니다.
|
||||
기본 헤더 이미지입니다.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex shrink-0 flex-wrap gap-2">
|
||||
@@ -1861,7 +1917,7 @@ onBeforeUnmount(() => {
|
||||
:disabled="uploadingHomeCover"
|
||||
@click="openHomeCoverFilePicker"
|
||||
>
|
||||
{{ uploadingHomeCover ? '업로드 중' : form.homeCoverImageUrl ? '이미지 변경' : '이미지 등록' }}
|
||||
{{ uploadingHomeCover ? '업로드 중' : '이미지 변경' }}
|
||||
</button>
|
||||
<button
|
||||
v-if="form.homeCoverImageUrl"
|
||||
@@ -1870,10 +1926,39 @@ onBeforeUnmount(() => {
|
||||
:disabled="uploadingHomeCover"
|
||||
@click="clearHomeCoverImage('light')"
|
||||
>
|
||||
제거
|
||||
삭제
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="form.homeCoverImageUrl"
|
||||
class="admin-settings-screen__home-cover-preview w-full max-w-[720px] overflow-hidden rounded-lg border border-[#e6e8eb]"
|
||||
>
|
||||
<HomeHero
|
||||
:image-url="form.homeCoverImageUrl"
|
||||
:dark-image-url="''"
|
||||
:title="form.homeCoverTitle"
|
||||
:text="form.homeCoverText"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
v-else
|
||||
class="admin-settings-screen__home-cover-dropzone grid aspect-[720/215] w-full max-w-[720px] cursor-pointer place-items-center rounded-lg border border-dashed border-[#b8c1cc] bg-[#f7f8fa] px-4 text-center transition hover:border-[#15171a] hover:bg-white disabled:cursor-not-allowed disabled:opacity-60"
|
||||
type="button"
|
||||
:disabled="uploadingHomeCover"
|
||||
@click="openHomeCoverFilePicker"
|
||||
@dragover.prevent
|
||||
@drop.prevent="dropHomeCover($event, 'light')"
|
||||
>
|
||||
<span class="grid place-items-center gap-2 text-sm font-semibold text-[#657080]">
|
||||
<svg class="size-6 text-[#8a94a3]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M12 16V4" />
|
||||
<path d="m7 9 5-5 5 5" />
|
||||
<path d="M4 16v3a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-3" />
|
||||
</svg>
|
||||
<span>라이트모드 이미지를 드롭하거나 선택하세요.</span>
|
||||
</span>
|
||||
</button>
|
||||
<input
|
||||
ref="homeCoverInputRef"
|
||||
class="hidden"
|
||||
@@ -1884,14 +1969,14 @@ onBeforeUnmount(() => {
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="admin-settings-screen__home-cover-upload rounded-lg border border-[#e6e8eb] bg-[#fbfbfc] p-4">
|
||||
<div class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div class="min-w-0 flex-1">
|
||||
<h3 class="text-sm font-medium text-[#3f4650]">
|
||||
다크모드 이미지
|
||||
<div class="admin-settings-screen__home-cover-mode grid gap-2">
|
||||
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div class="min-w-0">
|
||||
<h3 class="text-sm font-bold text-[#15171a]">
|
||||
다크모드
|
||||
</h3>
|
||||
<p class="mt-1 text-sm leading-relaxed text-[#657080]">
|
||||
다크모드에서만 교체되는 이미지입니다. 선택하지 않으면 라이트 이미지를 그대로 씁니다.
|
||||
다크모드에서 교체되는 이미지입니다.
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex shrink-0 flex-wrap gap-2">
|
||||
@@ -1901,7 +1986,7 @@ onBeforeUnmount(() => {
|
||||
:disabled="uploadingHomeCoverDark"
|
||||
@click="openHomeCoverDarkFilePicker"
|
||||
>
|
||||
{{ uploadingHomeCoverDark ? '업로드 중' : form.homeCoverDarkImageUrl ? '이미지 변경' : '이미지 등록' }}
|
||||
{{ uploadingHomeCoverDark ? '업로드 중' : '이미지 변경' }}
|
||||
</button>
|
||||
<button
|
||||
v-if="form.homeCoverDarkImageUrl"
|
||||
@@ -1910,10 +1995,39 @@ onBeforeUnmount(() => {
|
||||
:disabled="uploadingHomeCoverDark"
|
||||
@click="clearHomeCoverImage('dark')"
|
||||
>
|
||||
제거
|
||||
삭제
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="form.homeCoverDarkImageUrl"
|
||||
class="admin-settings-screen__home-cover-preview w-full max-w-[720px] overflow-hidden rounded-lg border border-[#e6e8eb]"
|
||||
>
|
||||
<HomeHero
|
||||
:image-url="form.homeCoverDarkImageUrl"
|
||||
:dark-image-url="''"
|
||||
:title="form.homeCoverTitle"
|
||||
:text="form.homeCoverText"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
v-else
|
||||
class="admin-settings-screen__home-cover-dropzone grid aspect-[720/215] w-full max-w-[720px] cursor-pointer place-items-center rounded-lg border border-dashed border-[#b8c1cc] bg-[#f7f8fa] px-4 text-center transition hover:border-[#15171a] hover:bg-white disabled:cursor-not-allowed disabled:opacity-60"
|
||||
type="button"
|
||||
:disabled="uploadingHomeCoverDark"
|
||||
@click="openHomeCoverDarkFilePicker"
|
||||
@dragover.prevent
|
||||
@drop.prevent="dropHomeCover($event, 'dark')"
|
||||
>
|
||||
<span class="grid place-items-center gap-2 text-sm font-semibold text-[#657080]">
|
||||
<svg class="size-6 text-[#8a94a3]" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||
<path d="M12 16V4" />
|
||||
<path d="m7 9 5-5 5 5" />
|
||||
<path d="M4 16v3a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-3" />
|
||||
</svg>
|
||||
<span>다크모드 이미지를 드롭하거나 선택하세요.</span>
|
||||
</span>
|
||||
</button>
|
||||
<input
|
||||
ref="homeCoverDarkInputRef"
|
||||
class="hidden"
|
||||
@@ -1925,18 +2039,6 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="form.homeCoverImageUrl || form.homeCoverDarkImageUrl"
|
||||
class="admin-settings-screen__home-cover-preview w-full max-w-[720px] overflow-hidden rounded-lg border border-[#e6e8eb]"
|
||||
>
|
||||
<HomeHero
|
||||
:image-url="form.homeCoverImageUrl"
|
||||
:dark-image-url="form.homeCoverDarkImageUrl"
|
||||
:title="form.homeCoverTitle"
|
||||
:text="form.homeCoverText"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label class="admin-settings-screen__field grid gap-2 text-sm">
|
||||
<span class="font-medium text-[#3f4650]">오버레이 제목</span>
|
||||
<input
|
||||
|
||||
Reference in New Issue
Block a user