게시물과 페이지 공개 상태 확장 v1.5.4

This commit is contained in:
2026-05-26 16:07:10 +09:00
parent b989193dab
commit 6333c4254f
20 changed files with 252 additions and 38 deletions

View File

@@ -47,8 +47,8 @@ const slugTouched = ref((() => {
if (!post?.id) {
return false
}
const status = post.status === 'private' ? 'draft' : post.status
if (status === 'published') {
const status = post.status || 'draft'
if (status !== 'draft') {
return true
}
return Boolean(post.slug) && !isAdminPostDraftPlaceholderSlug(post.slug)
@@ -160,7 +160,7 @@ const form = reactive({
featuredImage: props.initialPost.featuredImage || '',
isFeatured: Boolean(props.initialPost.isFeatured),
noindex: props.initialPost.noindex === true,
status: props.initialPost.status === 'private' ? 'draft' : (props.initialPost.status || 'draft'),
status: props.initialPost.status || 'draft',
publishedAt: toDateTimeLocalValue(props.initialPost.publishedAt),
tagsText: props.initialPost.tags?.join(', ') || ''
})
@@ -168,13 +168,16 @@ const form = reactive({
/**
* 서버에 반영된 게시 형태(툴바·자동 저장·슬러그 자동 연동 분기)
* @param {Object} post - 게시물
* @returns {'draft' | 'publishedLive' | 'scheduled'}
* @returns {'draft' | 'publishedLive' | 'scheduled' | 'members' | 'private'}
*/
const getPersistedPublishKind = (post) => {
if (!post?.id) {
return 'draft'
}
const st = post.status === 'private' ? 'draft' : post.status
const st = post.status || 'draft'
if (st === 'members' || st === 'private') {
return st
}
if (st !== 'published') {
return 'draft'
}
@@ -425,6 +428,16 @@ const displayScheduled = computed(() =>
persistedPublishKind.value === 'scheduled'
|| (persistedPublishKind.value === 'draft' && isScheduledPost()))
/** 툴바·상태줄에 멤버십 글로 표시할지 */
const displayMembersOnly = computed(() =>
persistedPublishKind.value === 'members'
|| (persistedPublishKind.value === 'draft' && form.status === 'members'))
/** 툴바·상태줄에 비공개 글로 표시할지 */
const displayPrivatePost = computed(() =>
persistedPublishKind.value === 'private'
|| (persistedPublishKind.value === 'draft' && form.status === 'private'))
/**
* 발행 모달에 표시할 게시 상태 요약 문구
* @returns {string} 요약 문구
@@ -556,7 +569,7 @@ const isRouteLeaveDirty = computed(() => {
if (!hasUnsavedPostChanges.value) {
return false
}
if (persistedPublishKind.value === 'publishedLive' || persistedPublishKind.value === 'scheduled') {
if (['publishedLive', 'scheduled', 'members', 'private'].includes(persistedPublishKind.value)) {
return true
}
return false
@@ -570,7 +583,7 @@ const headerDraftStatusText = computed(() => {
if (persistedPublishKind.value !== 'draft') {
return null
}
if (displayPublishedLive.value || displayScheduled.value) {
if (displayPublishedLive.value || displayScheduled.value || displayMembersOnly.value || displayPrivatePost.value) {
return null
}
const persisting = props.saving || props.autoSaving
@@ -1416,6 +1429,18 @@ defineExpose({
>
Scheduled
</span>
<span
v-else-if="displayMembersOnly"
class="admin-post-form__toolbar-status-members truncate rounded px-2 py-1.5 text-sm font-medium text-[#5a63d8]"
>
Members
</span>
<span
v-else-if="displayPrivatePost"
class="admin-post-form__toolbar-status-private truncate rounded px-2 py-1.5 text-sm font-medium text-[#fb2d8d]"
>
Private
</span>
<span
v-else-if="headerDraftStatusText"
class="admin-post-form__toolbar-status-draft truncate rounded px-2 py-1.5 text-sm text-[#8E9CAC]"
@@ -1488,6 +1513,17 @@ defineExpose({
</button>
</template>
<template v-else-if="persistedPublishKind === 'members' || persistedPublishKind === 'private'">
<button
class="admin-post-form__toolbar-update rounded px-3 py-1.5 text-sm font-bold transition-colors disabled:cursor-default disabled:text-[#8E9CAC] disabled:hover:bg-transparent enabled:text-[#394047] enabled:hover:bg-[#f1f3f4]"
type="button"
:disabled="!hasUnsavedPostChanges || saving || autoSaving"
@click="requestToolbarUpdate"
>
Update
</button>
</template>
<button
class="admin-post-form__settings-toggle grid size-[34px] place-items-center rounded text-[#394047] transition-colors hover:bg-[#f1f3f4] hover:text-black"
type="button"
@@ -1614,12 +1650,20 @@ defineExpose({
<select v-model="form.status" class="admin-post-form__select h-[38px] w-full appearance-none rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2 pr-10 transition-colors hover:border-[#c8ced3] focus:border-[#8e9cac] focus:outline-none">
<option value="draft">초안</option>
<option value="published">발행</option>
<option value="members">멤버십</option>
<option value="private">비공개</option>
</select>
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-chevron-down pointer-events-none absolute right-3 top-1/2 size-5 -translate-y-1/2 text-[#15171a]" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<polyline points="6 9 12 15 18 9" />
</svg>
</span>
<span v-if="form.status === 'members'" class="admin-post-form__hint text-xs text-muted">
로그인한 회원에게만 공개됩니다. 등급별 제한은 이후 멤버십 등급 기능에서 확장합니다.
</span>
<span v-else-if="form.status === 'private'" class="admin-post-form__hint text-xs text-muted">
공개 사용자 화면에서는 보이지 않습니다.
</span>
</label>
<div v-if="form.status === 'published'" class="admin-post-form__field grid gap-2 text-sm">