- 내역 추가/수정 폼을 전체화면 모달로(바깥 영역 없음·× 로만 닫힘) → 입력 중 바깥 실수 터치로 닫히는 불편 해소. PC는 내용 폭 460px 가운데정렬 - 분류 화면: 대분류 삼각형(▶) 토글로 소분류 펼침/접힘(기본 접힘, 개수 뱃지) 소분류 추가 시 해당 대분류 자동 펼침. 순서변경 모드에선 모두 펼침 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1012,8 +1012,8 @@ onMounted(async () => {
|
||||
<!-- 추가/수정 모달 -->
|
||||
<Teleport to="body">
|
||||
<Transition name="fade">
|
||||
<div v-if="formOpen" class="modal-backdrop" @click.self="formOpen = false">
|
||||
<div class="modal" role="dialog" aria-modal="true">
|
||||
<div v-if="formOpen" class="modal-backdrop entry-backdrop">
|
||||
<div class="modal entry-modal" role="dialog" aria-modal="true">
|
||||
<button class="close" type="button" @click="formOpen = false">×</button>
|
||||
<h2>{{ editId ? '내역 수정' : '내역 추가' }}</h2>
|
||||
|
||||
@@ -1661,6 +1661,27 @@ button.primary {
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.6;
|
||||
}
|
||||
/* 내역 추가/수정: 전체화면 모달 — 바깥 영역이 없어 실수로 닫히지 않음(× 로만 닫힘) */
|
||||
.entry-backdrop {
|
||||
padding: 0;
|
||||
}
|
||||
.modal.entry-modal {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: none;
|
||||
max-height: 100%;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
padding-top: calc(1.5rem + env(safe-area-inset-top));
|
||||
}
|
||||
/* 넓은 화면(PC)에서도 입력 내용은 읽기 좋은 폭으로 가운데 정렬 */
|
||||
.modal.entry-modal > h2,
|
||||
.modal.entry-modal .entry-form {
|
||||
max-width: 460px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.modal {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
@@ -65,6 +65,18 @@ async function reload() {
|
||||
// 스크롤하다 실수로 순서가 바뀌는 것 방지: 기본은 드래그 비활성, '순서변경' 버튼으로 켠다.
|
||||
const majorListEl = ref(null)
|
||||
const reorderMode = ref(false)
|
||||
|
||||
// ===== 대분류 펼침(아코디언) — 삼각형 누르면 소분류 표시 =====
|
||||
const expanded = ref(new Set())
|
||||
function toggleExpand(id) {
|
||||
const s = new Set(expanded.value)
|
||||
if (s.has(id)) s.delete(id)
|
||||
else s.add(id)
|
||||
expanded.value = s
|
||||
}
|
||||
function isExpanded(id) {
|
||||
return expanded.value.has(id)
|
||||
}
|
||||
let sortables = []
|
||||
function destroySortables() {
|
||||
sortables.forEach((s) => s.destroy())
|
||||
@@ -128,9 +140,16 @@ async function addCategory() {
|
||||
if (!name) return
|
||||
error.value = null
|
||||
try {
|
||||
await accountApi.createCategory({ type: activeType.value, name, parentId: newParent.value || null })
|
||||
const parentId = newParent.value || null
|
||||
await accountApi.createCategory({ type: activeType.value, name, parentId })
|
||||
newName.value = ''
|
||||
await reload()
|
||||
// 소분류를 추가했으면 그 대분류를 펼쳐 바로 보이게
|
||||
if (parentId) {
|
||||
const s = new Set(expanded.value)
|
||||
s.add(Number(parentId))
|
||||
expanded.value = s
|
||||
}
|
||||
} catch (e) {
|
||||
showError(e, '추가에 실패했습니다.')
|
||||
}
|
||||
@@ -226,12 +245,18 @@ onBeforeUnmount(destroySortables)
|
||||
<div class="cat-row major-row">
|
||||
<div class="cat-main">
|
||||
<span v-show="reorderMode" class="drag-handle major-handle" title="대분류 순서 변경(소분류 함께 이동)">≡</span>
|
||||
<button
|
||||
type="button" class="expand-btn" :class="{ open: isExpanded(g.major.id), empty: !g.children.length }"
|
||||
:title="g.children.length ? (isExpanded(g.major.id) ? '소분류 접기' : '소분류 펼치기') : '소분류 없음'"
|
||||
:disabled="!g.children.length" @click="toggleExpand(g.major.id)"
|
||||
>▶</button>
|
||||
<input v-model="g.major.name" class="cat-name" @keyup.enter="saveCategory(g.major)" />
|
||||
<span v-if="g.children.length && !isExpanded(g.major.id)" class="sub-count">{{ g.children.length }}</span>
|
||||
<IconBtn icon="check" title="저장" size="sm" @click="saveCategory(g.major)" />
|
||||
<IconBtn icon="trash" title="삭제" variant="danger" size="sm" @click="removeCategory(g.major)" />
|
||||
</div>
|
||||
</div>
|
||||
<ul class="sub-list" :data-parent="g.major.id">
|
||||
<ul v-show="isExpanded(g.major.id) || reorderMode" class="sub-list" :data-parent="g.major.id">
|
||||
<li v-for="s in g.children" :key="s.id" :data-id="s.id" class="sub-item cat-row child">
|
||||
<div class="cat-main">
|
||||
<span v-show="reorderMode" class="drag-handle sub-handle" title="소분류 순서 변경">≡</span>
|
||||
@@ -440,6 +465,37 @@ button.danger {
|
||||
.sub-mark {
|
||||
opacity: 0.45;
|
||||
}
|
||||
/* 대분류 펼침 삼각형 */
|
||||
.expand-btn {
|
||||
flex: none;
|
||||
width: 1.4rem;
|
||||
height: 1.4rem;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--color-text);
|
||||
font-size: 0.7rem;
|
||||
cursor: pointer;
|
||||
transition: transform 0.15s ease;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.expand-btn.open {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
.expand-btn.empty {
|
||||
opacity: 0.15;
|
||||
cursor: default;
|
||||
}
|
||||
.sub-count {
|
||||
flex: none;
|
||||
min-width: 1.2rem;
|
||||
text-align: center;
|
||||
font-size: 0.72rem;
|
||||
padding: 0.05rem 0.3rem;
|
||||
border-radius: 999px;
|
||||
background: var(--color-border);
|
||||
color: var(--color-text);
|
||||
opacity: 0.75;
|
||||
}
|
||||
.hint.sm {
|
||||
font-size: 0.78rem;
|
||||
margin: 0 0 0.75rem;
|
||||
|
||||
Reference in New Issue
Block a user