Compare commits

...

2 Commits

Author SHA1 Message Date
ByungCheol 1996c3355e Merge branch 'dev'
Deploy / deploy (push) Failing after 11m28s
2026-07-01 00:14:58 +09:00
ByungCheol 28ebe06767 fix: 분류 선택 UI — 세로 아코디언→가로 칩 그리드로 변경
- 대분류: flex-wrap 그리드(한 줄 4개)로 나열, 분류 수 증가해도 가로로 쌓임
- 대분류 선택 시 소분류가 구분선 아래 동일 그리드로 펼침
- 선택된 항목 초록 테두리·배경 강조

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-01 00:13:58 +09:00
+63 -82
View File
@@ -282,7 +282,11 @@ const categoryMajor = ref('') // 펼쳐진 대분류 이름
const majorOptionsData = computed(() => const majorOptionsData = computed(() =>
categories.value.filter((c) => c.type === form.type && c.parentId == null) categories.value.filter((c) => c.type === form.type && c.parentId == null)
) )
// 특정 대분류의 소분류 객체 목록 // 현재 펼쳐진 대분류 객체
const selectedMajorObj = computed(() =>
majorOptionsData.value.find((m) => m.name === categoryMajor.value) ?? null
)
// 특정 대분류의 소분류 목록
function subsByMajor(majorId) { function subsByMajor(majorId) {
return categories.value.filter((c) => c.parentId === majorId) return categories.value.filter((c) => c.parentId === majorId)
} }
@@ -1120,28 +1124,28 @@ onMounted(async () => {
</template> </template>
<label v-if="form.type === 'INCOME' || form.type === 'EXPENSE'">분류 <label v-if="form.type === 'INCOME' || form.type === 'EXPENSE'">분류
<div v-if="!addingCategory" class="cat-accordion"> <div v-if="!addingCategory" class="cat-picker">
<div v-for="m in majorOptionsData" :key="m.id" class="acc-major"> <!-- 대분류: 줄에 4개씩 -->
<div class="acc-major-grid">
<button <button
type="button" class="acc-major-btn" v-for="m in majorOptionsData" :key="m.id"
:class="{ active: form.category === m.name && !subsByMajor(m.id).length, expanded: categoryMajor === m.name && subsByMajor(m.id).length }" type="button" class="acc-chip major"
:class="{ active: categoryMajor === m.name }"
:disabled="submitting" :disabled="submitting"
@click="onMajorClick(m)" @click="onMajorClick(m)"
> >{{ m.name }}</button>
<span class="acc-arrow">{{ subsByMajor(m.id).length ? (categoryMajor === m.name ? '▼' : '▶') : '' }}</span> <button type="button" class="acc-chip add-chip" :disabled="submitting" @click="startAddCategory">+ 추가</button>
{{ m.name }} </div>
</button> <!-- 소분류: 선택된 대분류가 있을 때만 표시 -->
<div v-if="categoryMajor === m.name && subsByMajor(m.id).length" class="acc-subs"> <div v-if="selectedMajorObj && subsByMajor(selectedMajorObj.id).length" class="acc-sub-grid">
<button <button
v-for="s in subsByMajor(m.id)" :key="s.id" v-for="s in subsByMajor(selectedMajorObj.id)" :key="s.id"
type="button" class="acc-sub-btn" type="button" class="acc-chip sub"
:class="{ active: form.category === s.name }" :class="{ active: form.category === s.name }"
:disabled="submitting" :disabled="submitting"
@click="form.category = s.name" @click="form.category = s.name"
>{{ s.name }}</button> >{{ s.name }}</button>
</div>
</div> </div>
<button type="button" class="cat-add-btn acc-add" :disabled="submitting" @click="startAddCategory">+ 추가</button>
</div> </div>
<div v-else class="cat-input"> <div v-else class="cat-input">
<input <input
@@ -1896,78 +1900,55 @@ button.primary {
border-color: hsla(160, 100%, 37%, 1); border-color: hsla(160, 100%, 37%, 1);
color: hsla(160, 100%, 37%, 1); color: hsla(160, 100%, 37%, 1);
} }
/* 분류 아코디언 */ /* 분류 칩 그리드 */
.cat-accordion { .cat-picker {
border: 1px solid var(--color-border);
border-radius: 6px;
overflow: hidden;
max-height: 200px;
overflow-y: auto;
}
.acc-major-btn {
width: 100%;
display: flex;
align-items: center;
gap: 0.35rem;
padding: 0.45rem 0.7rem;
border: 0;
border-bottom: 1px solid var(--color-border);
background: transparent;
cursor: pointer;
text-align: left;
font-size: 0.88rem;
color: var(--color-text);
}
.acc-major-btn:last-child {
border-bottom: 0;
}
.acc-major-btn.active,
.acc-major-btn.expanded {
background: var(--color-background-soft);
font-weight: 600;
}
.acc-major-btn.active {
color: hsla(160, 100%, 37%, 1);
}
.acc-arrow {
font-size: 0.6rem;
flex: none;
width: 0.9rem;
text-align: center;
opacity: 0.6;
}
.acc-subs {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0.4rem;
} }
.acc-sub-btn { .acc-major-grid,
padding: 0.38rem 0.7rem 0.38rem 2rem; .acc-sub-grid {
border: 0; display: flex;
border-bottom: 1px solid var(--color-border); flex-wrap: wrap;
background: var(--color-background-soft); gap: 0.35rem;
}
.acc-sub-grid {
padding-top: 0.15rem;
border-top: 1px solid var(--color-border);
}
.acc-chip {
flex: 1 1 calc(25% - 0.35rem);
min-width: 0;
padding: 0.38rem 0.4rem;
border: 1px solid var(--color-border);
border-radius: 6px;
background: transparent;
cursor: pointer; cursor: pointer;
text-align: left; font-size: 0.82rem;
font-size: 0.84rem;
color: var(--color-text); color: var(--color-text);
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
} }
.acc-sub-btn:last-child { .acc-chip.major.active {
border-bottom: 0; border-color: hsla(160, 100%, 37%, 1);
} background: hsla(160, 100%, 37%, 0.1);
.acc-sub-btn.active {
color: hsla(160, 100%, 37%, 1); color: hsla(160, 100%, 37%, 1);
font-weight: 600; font-weight: 600;
} }
.acc-add { .acc-chip.sub {
display: block; background: var(--color-background-soft);
width: 100%; }
border: 0; .acc-chip.sub.active {
border-top: 1px dashed var(--color-border); border-color: hsla(160, 100%, 37%, 1);
border-radius: 0; background: hsla(160, 100%, 37%, 0.1);
background: transparent; color: hsla(160, 100%, 37%, 1);
text-align: center; font-weight: 600;
color: var(--color-text); }
opacity: 0.6; .acc-chip.add-chip {
font-size: 0.82rem; opacity: 0.55;
border-style: dashed;
} }
.tag-field { .tag-field {
display: flex; display: flex;