관리자 글쓰기 전체 화면 레이아웃 보정

This commit is contained in:
2026-05-07 10:53:08 +09:00
parent 1ef50c111b
commit 9054c9625c
8 changed files with 124 additions and 87 deletions

View File

@@ -480,70 +480,69 @@ defineExpose({
</script>
<template>
<form class="admin-post-form flex min-h-[calc(100vh-2.5rem)] flex-col bg-white" @submit.prevent="submitPost">
<header class="admin-post-form__toolbar flex h-[82px] shrink-0 items-start border-b border-transparent bg-white p-6">
<div class="admin-post-form__toolbar-inner flex h-[34px] min-w-0 flex-1 items-center justify-between">
<div class="admin-post-form__toolbar-left flex h-full items-center gap-2">
<NuxtLink class="admin-post-form__toolbar-link inline-flex items-center gap-2 rounded px-3 py-1.5 text-base text-black" to="/admin/posts">
<span class="admin-post-form__toolbar-back text-lg leading-none" aria-hidden="true">&lt;</span>
<span>Posts</span>
</NuxtLink>
<span class="admin-post-form__toolbar-status rounded px-3 py-1.5 text-base text-[#8e9cac]">
{{ editorStatusLabel }}
</span>
<form class="admin-post-form flex h-screen min-h-screen overflow-hidden bg-white" @submit.prevent="submitPost">
<div class="admin-post-form__workspace flex min-w-0 flex-1 flex-col bg-white">
<header class="admin-post-form__toolbar flex h-[56px] shrink-0 items-center bg-white px-8">
<div class="admin-post-form__toolbar-inner flex h-[34px] min-w-0 flex-1 items-center justify-between">
<div class="admin-post-form__toolbar-left flex h-full min-w-0 items-center gap-3">
<NuxtLink class="admin-post-form__toolbar-link inline-flex items-center gap-2 rounded px-2 py-1.5 text-sm font-medium text-[#394047] transition-colors hover:bg-[#eff1f2] hover:text-black" to="/admin/posts">
<span class="admin-post-form__toolbar-back text-lg leading-none" aria-hidden="true">&lt;</span>
<span>Posts</span>
</NuxtLink>
<span class="admin-post-form__toolbar-status truncate rounded px-2 py-1.5 text-sm text-[#8e9cac]">
{{ editorStatusLabel }}
</span>
</div>
<div class="admin-post-form__toolbar-actions flex h-full shrink-0 items-center gap-2">
<button
class="admin-post-form__toolbar-preview rounded px-3 py-1.5 text-sm font-bold text-[#394047] transition-colors hover:bg-[#eff1f2] hover:text-black"
type="button"
@click="previewPost"
>
미리보기
</button>
<button
class="admin-post-form__toolbar-submit rounded px-3 py-1.5 text-sm font-bold text-[#2bba3c] transition-colors hover:bg-[#eaf8ec] hover:text-[#159624] disabled:opacity-50"
type="submit"
:disabled="saving"
>
{{ saving ? '저장 중' : submitLabel }}
</button>
<button
class="admin-post-form__settings-toggle grid size-[34px] place-items-center rounded text-[#394047] transition-colors hover:bg-[#eff1f2] hover:text-black"
type="button"
:aria-pressed="isSettingsOpen"
aria-label="게시물 설정 패널 전환"
@click="toggleSettingsPanel"
>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
<path d="M14 2.16699C14.3242 2.16699 14.4998 2.39365 14.5 2.57129V13.4287C14.5 13.606 14.3242 13.834 14 13.834H11.5V2.16699H14ZM2 2.16699H10.5V13.834H2C1.6756 13.834 1.5 13.6064 1.5 13.4287V2.57129C1.50024 2.39409 1.67607 2.16699 2 2.16699Z" stroke="currentColor" />
</svg>
</button>
</div>
</div>
<div class="admin-post-form__toolbar-actions flex h-full items-center gap-2">
<button
class="admin-post-form__toolbar-preview rounded px-3 py-1.5 text-base font-bold text-[#394047]"
type="button"
@click="previewPost"
>
미리보기
</button>
<button
class="admin-post-form__toolbar-submit rounded px-3 py-1.5 text-base font-bold text-[#2bba3c] disabled:opacity-50"
type="submit"
:disabled="saving"
>
{{ saving ? '저장 중' : submitLabel }}
</button>
<button
class="admin-post-form__settings-toggle grid size-[34px] place-items-center rounded text-[#394047] hover:bg-[#eff1f2]"
type="button"
:aria-pressed="isSettingsOpen"
aria-label="게시물 설정 패널 전환"
@click="toggleSettingsPanel"
>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 2.16699C14.3242 2.16699 14.4998 2.39365 14.5 2.57129V13.4287C14.5 13.606 14.3242 13.834 14 13.834H11.5V2.16699H14ZM2 2.16699H10.5V13.834H2C1.6756 13.834 1.5 13.6064 1.5 13.4287V2.57129C1.50024 2.39409 1.67607 2.16699 2 2.16699Z" stroke="#394047"/>
</svg>
</header>
<!-- <span class="admin-post-form__settings-toggle-icon block h-4 w-4 border-x-2 border-[#394047]" aria-hidden="true" /> -->
</button>
</div>
</div>
</header>
<div class="admin-post-form__main flex min-h-0 flex-1 flex-col bg-white lg:flex-row">
<section class="admin-post-form__content mx-auto w-full max-w-[804px] px-8 pb-16 pt-14">
<main class="admin-post-form__editor-scroll min-h-0 flex-1 overflow-y-auto">
<section class="admin-post-form__content mx-auto w-full max-w-[804px] px-8 pb-16 pt-32">
<div class="admin-post-form__feature-block mb-9">
<figure v-if="form.featuredImage" class="admin-post-form__featured-editor overflow-hidden rounded border border-line bg-white">
<img class="admin-post-form__featured-editor-image aspect-[16/9] w-full bg-surface object-cover" :src="form.featuredImage" alt="">
<figcaption class="admin-post-form__featured-editor-actions flex flex-wrap items-center gap-2 border-t border-line p-3">
<button class="admin-post-form__featured-change rounded border border-line px-3 py-1.5 text-xs font-semibold" type="button" @click="openMediaPicker('featuredImage')">
<button class="admin-post-form__featured-change rounded border border-line px-3 py-1.5 text-xs font-semibold transition-colors hover:border-[#c8ced3] hover:bg-[#eff1f2]" type="button" @click="openMediaPicker('featuredImage')">
변경
</button>
<label class="admin-post-form__featured-reupload cursor-pointer rounded border border-line px-3 py-1.5 text-xs font-semibold">
<label class="admin-post-form__featured-reupload cursor-pointer rounded border border-line px-3 py-1.5 text-xs font-semibold transition-colors hover:border-[#c8ced3] hover:bg-[#eff1f2]">
업로드
<input class="sr-only" type="file" accept="image/*" @change="uploadFeaturedImage">
</label>
<button class="admin-post-form__featured-remove rounded border border-red-200 px-3 py-1.5 text-xs font-semibold text-red-700" type="button" @click="removeFeaturedImage">
<button class="admin-post-form__featured-remove rounded border border-red-200 px-3 py-1.5 text-xs font-semibold text-red-700 transition-colors hover:bg-red-50" type="button" @click="removeFeaturedImage">
삭제
</button>
</figcaption>
</figure>
<div v-else class="admin-post-form__feature-empty flex h-6 items-start">
<button class="admin-post-form__feature-add inline-flex items-center gap-1.5 text-sm text-[#8e9cac]" type="button" @click="openMediaPicker('featuredImage')">
<button class="admin-post-form__feature-add inline-flex items-center gap-1.5 rounded px-2 py-1 text-sm text-[#8e9cac] transition-colors hover:bg-[#eff1f2] hover:text-[#394047]" type="button" @click="openMediaPicker('featuredImage')">
<span aria-hidden="true">+</span>
<span>대표 이미지 추가</span>
</button>
@@ -567,10 +566,10 @@ defineExpose({
{{ formatAutosaveTime(autosaveNotice.savedAt) }} 저장된 작성 내용이 있습니다.
</p>
<div class="admin-post-form__autosave-actions flex gap-2">
<button class="admin-post-form__autosave-restore rounded bg-[#15171a] px-3 py-1.5 text-xs font-semibold text-white" type="button" @click="restoreAutosave">
<button class="admin-post-form__autosave-restore rounded bg-[#15171a] px-3 py-1.5 text-xs font-semibold text-white transition-colors hover:bg-black" type="button" @click="restoreAutosave">
복원
</button>
<button class="admin-post-form__autosave-discard rounded border border-line bg-white px-3 py-1.5 text-xs font-semibold" type="button" @click="discardAutosave">
<button class="admin-post-form__autosave-discard rounded border border-line bg-white px-3 py-1.5 text-xs font-semibold transition-colors hover:bg-[#eff1f2]" type="button" @click="discardAutosave">
삭제
</button>
</div>
@@ -579,22 +578,29 @@ defineExpose({
<div class="admin-post-form__field admin-post-form__content-editor text-sm">
<AdminBlockEditor ref="blockEditor" v-model="form.content" />
</div>
</section>
</section>
</main>
</div>
<aside v-if="isSettingsOpen" class="admin-post-form__settings flex h-auto w-full shrink-0 flex-col border-t border-[#e3e6e8] bg-white lg:w-[420px] lg:border-l lg:border-t-0">
<div class="admin-post-form__settings-header flex h-[82px] shrink-0 items-center justify-between px-6">
<aside
class="admin-post-form__settings flex h-screen shrink-0 flex-col overflow-hidden border-[#e3e6e8] bg-white transition-[width,border-color] duration-300 ease-out"
:class="isSettingsOpen ? 'w-[420px] border-l' : 'w-0 border-l-0'"
:aria-hidden="!isSettingsOpen"
>
<div class="admin-post-form__settings-inner flex h-full w-[420px] flex-col">
<div class="admin-post-form__settings-header flex h-[56px] shrink-0 items-center justify-between px-6">
<h2 class="admin-post-form__settings-title text-xl font-bold text-black">
게시물 설정
</h2>
<button class="admin-post-form__settings-close grid size-6 place-items-center text-[#394047]" type="button" aria-label="게시물 설정 닫기" @click="toggleSettingsPanel">
<button class="admin-post-form__settings-close grid size-8 place-items-center rounded text-[#394047] transition-colors hover:bg-[#eff1f2] hover:text-black" type="button" aria-label="게시물 설정 닫기" @click="toggleSettingsPanel">
<span aria-hidden="true">x</span>
</button>
</div>
<div class="admin-post-form__settings-body grid content-start gap-4 overflow-y-auto px-6 pb-8">
<div class="admin-post-form__settings-body grid content-start gap-4 overflow-y-auto px-6 pb-8 pt-8">
<label class="admin-post-form__field grid gap-2 text-sm">
<span class="admin-post-form__label font-medium">상태</span>
<select v-model="form.status" class="admin-post-form__select h-[38px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2">
<select v-model="form.status" class="admin-post-form__select h-[38px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2 transition-colors hover:border-[#c8ced3] focus:border-[#8e9cac] focus:outline-none">
<option value="draft">초안</option>
<option value="published">발행</option>
<option value="private">비공개</option>
@@ -607,7 +613,7 @@ defineExpose({
</span>
<input
v-model="form.publishedAt"
class="admin-post-form__input h-[38px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2"
class="admin-post-form__input h-[38px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2 transition-colors hover:border-[#c8ced3] focus:border-[#8e9cac] focus:outline-none"
type="datetime-local"
>
<span class="admin-post-form__hint text-xs text-muted">
@@ -619,7 +625,7 @@ defineExpose({
<span class="admin-post-form__label font-medium">슬러그</span>
<input
v-model="form.slug"
class="admin-post-form__input h-[38px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2"
class="admin-post-form__input h-[38px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2 transition-colors hover:border-[#c8ced3] focus:border-[#8e9cac] focus:outline-none"
type="text"
pattern="[a-z0-9가-힣]+(-[a-z0-9가-힣]+)*"
required
@@ -631,7 +637,7 @@ defineExpose({
<span class="admin-post-form__label font-medium">요약</span>
<textarea
v-model="form.excerpt"
class="admin-post-form__textarea min-h-[108px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2"
class="admin-post-form__textarea min-h-[108px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2 transition-colors hover:border-[#c8ced3] focus:border-[#8e9cac] focus:outline-none"
/>
</label>
@@ -639,7 +645,7 @@ defineExpose({
<span class="admin-post-form__label font-medium">태그</span>
<input
v-model="form.tagsText"
class="admin-post-form__input h-[38px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2"
class="admin-post-form__input h-[38px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2 transition-colors hover:border-[#c8ced3] focus:border-[#8e9cac] focus:outline-none"
type="text"
>
</label>
@@ -658,7 +664,7 @@ defineExpose({
<span class="admin-post-form__label font-medium">SEO 제목</span>
<input
v-model="form.seoTitle"
class="admin-post-form__input h-[38px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2"
class="admin-post-form__input h-[38px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2 transition-colors hover:border-[#c8ced3] focus:border-[#8e9cac] focus:outline-none"
type="text"
maxlength="80"
placeholder="비워두면 글 제목을 사용"
@@ -672,7 +678,7 @@ defineExpose({
<span class="admin-post-form__label font-medium">SEO 설명</span>
<textarea
v-model="form.seoDescription"
class="admin-post-form__textarea min-h-[108px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2"
class="admin-post-form__textarea min-h-[108px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2 transition-colors hover:border-[#c8ced3] focus:border-[#8e9cac] focus:outline-none"
maxlength="180"
placeholder="비워두면 요약을 사용"
/>
@@ -685,7 +691,7 @@ defineExpose({
<span class="admin-post-form__label font-medium">Canonical URL</span>
<input
v-model="form.canonicalUrl"
class="admin-post-form__input h-[38px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2"
class="admin-post-form__input h-[38px] rounded border border-[#e3e6e8] bg-[#eff1f2] px-3 py-2 transition-colors hover:border-[#c8ced3] focus:border-[#8e9cac] focus:outline-none"
type="url"
placeholder="비워두면 기본 글 주소를 사용"
>
@@ -713,32 +719,32 @@ defineExpose({
{{ form.ogImage }}
</p>
<div class="admin-post-form__og-buttons flex flex-wrap gap-2">
<button class="admin-post-form__og-change rounded border border-line px-3 py-1.5 text-xs font-semibold" type="button" @click="openMediaPicker('ogImage')">
<button class="admin-post-form__og-change rounded border border-line px-3 py-1.5 text-xs font-semibold transition-colors hover:border-[#c8ced3] hover:bg-[#eff1f2]" type="button" @click="openMediaPicker('ogImage')">
변경
</button>
<label class="admin-post-form__og-reupload cursor-pointer rounded border border-line px-3 py-1.5 text-xs font-semibold">
<label class="admin-post-form__og-reupload cursor-pointer rounded border border-line px-3 py-1.5 text-xs font-semibold transition-colors hover:border-[#c8ced3] hover:bg-[#eff1f2]">
업로드
<input class="sr-only" type="file" accept="image/*" @change="uploadOgImage">
</label>
<button class="admin-post-form__og-remove rounded border border-red-200 px-3 py-1.5 text-xs font-semibold text-red-700" type="button" @click="removeOgImage">
<button class="admin-post-form__og-remove rounded border border-red-200 px-3 py-1.5 text-xs font-semibold text-red-700 transition-colors hover:bg-red-50" type="button" @click="removeOgImage">
삭제
</button>
</div>
</figcaption>
</figure>
<div v-else class="admin-post-form__og-empty grid gap-2 rounded border border-dashed border-line bg-white p-4">
<button class="admin-post-form__og-select rounded border border-line px-3 py-2 text-sm font-semibold" type="button" @click="openMediaPicker('ogImage')">
<button class="admin-post-form__og-select rounded border border-line px-3 py-2 text-sm font-semibold transition-colors hover:border-[#c8ced3] hover:bg-[#eff1f2]" type="button" @click="openMediaPicker('ogImage')">
미디어에서 선택
</button>
<label class="admin-post-form__og-upload cursor-pointer rounded bg-[#15171a] px-3 py-2 text-center text-sm font-semibold text-white">
<label class="admin-post-form__og-upload cursor-pointer rounded bg-[#15171a] px-3 py-2 text-center text-sm font-semibold text-white transition-colors hover:bg-black">
{{ isUploadingOgImage ? '업로드 중' : '새 이미지 업로드' }}
<input class="sr-only" type="file" accept="image/*" @change="uploadOgImage">
</label>
</div>
</div>
</div>
</div>
</aside>
</div>
<div
v-if="isMediaPickerOpen"
@@ -752,7 +758,7 @@ defineExpose({
<h2 class="admin-post-form__media-picker-title text-lg font-semibold">
{{ mediaPickerTarget === 'ogImage' ? 'OG 이미지 선택' : '대표 이미지 선택' }}
</h2>
<button class="admin-post-form__media-picker-close rounded border border-line px-3 py-1.5 text-sm font-semibold" type="button" @click="closeMediaPicker">
<button class="admin-post-form__media-picker-close rounded border border-line px-3 py-1.5 text-sm font-semibold transition-colors hover:bg-[#eff1f2]" type="button" @click="closeMediaPicker">
닫기
</button>
</div>
@@ -764,7 +770,7 @@ defineExpose({
<button
v-for="item in mediaItems"
:key="item.url"
class="admin-post-form__media-picker-item overflow-hidden border border-line bg-white text-left"
class="admin-post-form__media-picker-item overflow-hidden border border-line bg-white text-left transition hover:border-[#8e9cac] hover:shadow-sm"
type="button"
@click="selectPickedImage(item)"
>

View File

@@ -1,5 +1,13 @@
# 의사결정 이력
## 2026-05-07 v0.0.35
### 관리자 글쓰기 전체 화면 모드 보정 결정
관리자 글 작성/수정 화면에서는 좌측 관리자 네비게이션과 공통 내부 패딩을 숨기고, 글쓰기 폼이 브라우저 높이를 직접 사용하는 전체 화면 편집 모드로 동작하게 한다. Ghost와 WordPress류 편집 화면은 작성 중 관리자 메뉴보다 글 본문과 설정 패널의 관계가 더 중요하므로, 네비게이션이 보이면 작성 영역을 불필요하게 압축하고 시선을 분산시키기 때문이다.
글쓰기 화면의 1차 레이아웃은 상단 헤더 전체 폭이 아니라 에디터 작업 영역과 우측 설정 패널의 좌우 분할로 둔다. 설정 패널이 열리거나 닫힐 때 에디터 작업 영역의 상단 도구막대와 본문 폭이 함께 변해야 사용자가 현재 편집 가능한 폭 변화를 자연스럽게 인식할 수 있다.
## 2026-05-07 v0.0.32
### 관리자 글 작성 화면 구조 정리 결정

View File

@@ -8,7 +8,7 @@
|------|------|
| layouts/default.vue | 메인, 목록, 태그 페이지 |
| layouts/post.vue | 개별 게시물 |
| layouts/admin.vue | 관리자 전체 |
| layouts/admin.vue | 관리자 전체, 글 작성/수정 화면의 전체 화면 편집 모드 |
| layouts/page.vue | 고정 페이지 전체 화면 |
## 사이트 컴포넌트
@@ -26,7 +26,7 @@
| 파일 | 화면 위치 |
|------|-----------|
| components/admin/AdminPostForm.vue | 관리자 글 작성/수정 폼, Ghost 스타일 상단 바, 중앙 에디터, 우측 설정 패널, 대표 이미지/OG 이미지 선택, 로컬 자동 저장, 예약 발행 시각 입력, SEO 설정, 미리보기 요청 |
| components/admin/AdminPostForm.vue | 관리자 글 작성/수정 폼, Ghost 스타일 전체 화면 에디터, 좌우 분할 설정 패널, 설정 패널 전환 애니메이션, 대표 이미지/OG 이미지 선택, 로컬 자동 저장, 예약 발행 시각 입력, SEO 설정, 미리보기 요청 |
| components/admin/AdminPageForm.vue | 관리자 페이지 작성/수정 폼, 대표 이미지 선택 |
| components/admin/AdminBlockEditor.vue | 관리자 글 블록형 에디터, 이미지/갤러리/콜아웃/토글/임베드 블록, 한글 조합 입력 처리, 하단 빈 입력 블록 유지, 본문 placeholder 표시 |
| components/admin/AdminTagForm.vue | 관리자 태그 생성/수정 폼 |

View File

@@ -288,8 +288,10 @@ components/content/
- 에디터 마지막에는 클릭 가능한 빈 문단 블록을 항상 유지하며, 해당 블록이 비어 있으면 저장 콘텐츠에는 포함하지 않는다.
- 제목은 별도 라벨 영역이 아니라 에디터 상단의 큰 제목 입력으로 표시한다.
- 글 작성/수정 화면은 페이지 제목 헤더를 별도로 두지 않고, 폼 상단의 Ghost 스타일 도구막대에서 목록 이동, 상태, 미리보기, 저장, 설정 패널 토글을 제공한다.
- 글 작성/수정 화면은 관리자 사이드바 네비게이션을 숨기고, 관리자 공통 내부 패딩 없이 전체 화면 편집 모드로 표시한다.
- 글 작성/수정 폼은 에디터 작업 영역과 우측 설정 패널을 먼저 좌우로 나누고, 에디터 작업 영역 안에 상단 도구막대와 본문 스크롤 영역을 배치한다.
- 본문 에디터는 데스크톱에서 좌우 32px 패딩을 포함한 804px 중앙 컬럼으로 배치해 실제 입력 영역 최대 폭을 740px로 유지한다.
- 게시물 설정은 데스크톱에서 420px 우측 패널로 표시하며, 도구막대 버튼으로 열고 닫을 수 있다.
- 게시물 설정은 데스크톱에서 420px 우측 패널로 표시하며, 도구막대 버튼으로 열고 닫을 수 있고 너비 전환 애니메이션을 적용한다.
- 대표 이미지는 본문 제목 위의 에디터 흐름 안에서 추가, 변경, 삭제한다.
- 제목 입력에서 Enter를 누르면 본문 첫 블록으로 포커스를 이동한다.
- 새 글 작성처럼 본문이 비어 있는 경우에도 빈 문단 블록을 먼저 생성한다.
@@ -437,6 +439,6 @@ APP_PORT=43118
## 버전 관리
- 현재 버전: v0.0.34
- 현재 버전: v0.0.35
- 첫 커밋 이후 변경사항을 커밋할 때마다 패치 버전 증가
- 메이저/마이너 버전은 구조 변경 또는 기능 묶음 단위로 결정

View File

@@ -1,5 +1,15 @@
# 업데이트 이력
## v0.0.35
- 관리자 공통 레이아웃의 기본 내부 패딩 제거.
- 관리자 글 작성/수정 화면에서 좌측 관리자 네비게이션을 숨기도록 수정.
- 관리자 글 작성/수정 폼을 에디터 작업 영역과 우측 설정 패널의 1차 좌우 분할 구조로 수정.
- 게시물 설정 패널 열림/닫힘 너비 전환 애니메이션 추가.
- 관리자 글 작성/수정 화면의 버튼, 입력, 미디어 선택 요소 hover/focus 효과 보강.
- 기술 명세 현재 버전을 v0.0.35로 갱신.
- 패키지 버전을 0.0.35로 갱신.
## v0.0.34
- 배포 문서에 개발/운영 DB 분리 검증 절차 추가.

View File

@@ -1,4 +1,9 @@
<script setup>
const route = useRoute()
const isPostEditorRoute = computed(() => route.path === '/admin/posts/new'
|| (route.path.startsWith('/admin/posts/') && route.path !== '/admin/posts/preview'))
/**
* 관리자 로그아웃
* @returns {Promise<void>} 로그아웃 처리 결과
@@ -13,35 +18,41 @@ const logoutAdmin = async () => {
<template>
<div class="admin-layout min-h-screen bg-[#f5f5f2] text-ink">
<aside class="admin-layout__sidebar fixed inset-y-0 left-0 hidden w-64 border-r border-line bg-[#15171a] p-5 text-white lg:block">
<aside
v-if="!isPostEditorRoute"
class="admin-layout__sidebar fixed inset-y-0 left-0 hidden w-64 border-r border-line bg-[#15171a] p-5 text-white lg:block"
>
<NuxtLink class="admin-layout__brand block text-lg font-semibold" to="/admin">
sori.studio
</NuxtLink>
<nav class="admin-layout__nav mt-8 grid gap-2 text-sm text-white/75">
<NuxtLink class="admin-layout__nav-link rounded px-3 py-2 hover:bg-white/10 hover:text-white" to="/admin/posts">
<NuxtLink class="admin-layout__nav-link rounded px-3 py-2 transition-colors hover:bg-white/10 hover:text-white" to="/admin/posts">
</NuxtLink>
<NuxtLink class="admin-layout__nav-link rounded px-3 py-2 hover:bg-white/10 hover:text-white" to="/admin/pages">
<NuxtLink class="admin-layout__nav-link rounded px-3 py-2 transition-colors hover:bg-white/10 hover:text-white" to="/admin/pages">
페이지
</NuxtLink>
<NuxtLink class="admin-layout__nav-link rounded px-3 py-2 hover:bg-white/10 hover:text-white" to="/admin/tags">
<NuxtLink class="admin-layout__nav-link rounded px-3 py-2 transition-colors hover:bg-white/10 hover:text-white" to="/admin/tags">
태그
</NuxtLink>
<NuxtLink class="admin-layout__nav-link rounded px-3 py-2 hover:bg-white/10 hover:text-white" to="/admin/media">
<NuxtLink class="admin-layout__nav-link rounded px-3 py-2 transition-colors hover:bg-white/10 hover:text-white" to="/admin/media">
미디어
</NuxtLink>
<NuxtLink class="admin-layout__nav-link rounded px-3 py-2 hover:bg-white/10 hover:text-white" to="/admin/navigation">
<NuxtLink class="admin-layout__nav-link rounded px-3 py-2 transition-colors hover:bg-white/10 hover:text-white" to="/admin/navigation">
메뉴
</NuxtLink>
<NuxtLink class="admin-layout__nav-link rounded px-3 py-2 hover:bg-white/10 hover:text-white" to="/admin/settings">
<NuxtLink class="admin-layout__nav-link rounded px-3 py-2 transition-colors hover:bg-white/10 hover:text-white" to="/admin/settings">
설정
</NuxtLink>
<button class="admin-layout__logout rounded px-3 py-2 text-left hover:bg-white/10 hover:text-white" type="button" @click="logoutAdmin">
<button class="admin-layout__logout rounded px-3 py-2 text-left transition-colors hover:bg-white/10 hover:text-white" type="button" @click="logoutAdmin">
로그아웃
</button>
</nav>
</aside>
<main class="admin-layout__main min-h-screen p-5 lg:ml-64">
<main
class="admin-layout__main min-h-screen"
:class="{ 'lg:ml-64': !isPostEditorRoute }"
>
<slot />
</main>
</div>

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "sori.studio",
"version": "0.0.34",
"version": "0.0.35",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sori.studio",
"version": "0.0.34",
"version": "0.0.35",
"hasInstallScript": true,
"dependencies": {
"@nuxtjs/tailwindcss": "^6.14.0",

View File

@@ -1,6 +1,6 @@
{
"name": "sori.studio",
"version": "0.0.34",
"version": "0.0.35",
"private": true,
"type": "module",
"scripts": {