feat: 홈 캘린더 일별 내역 팝업(모달)화 + 릴리스 노트 갱신
CI / build (push) Failing after 10m39s

- HomeView: 날짜 탭 시 아래 인라인 패널 대신 중앙 팝업으로 내역 표시(시인성)
  · @mouseenter 제거로 터치 '두 번 탭' 버그 해소(단일 탭 동작)
- docs/release-2026-06-06.md: 이어진 세션 변경(하단 내비·설정/계정·매매수정·보안·테스트/배포·안드로이드) 추가

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ByungCheol
2026-06-06 17:09:05 +09:00
parent 006fc87f70
commit 095ba942eb
2 changed files with 154 additions and 43 deletions
+118 -40
View File
@@ -66,8 +66,16 @@ const calendarCells = computed(() => {
return cells
})
// 마우스 오버 / 탭한 날짜의 내역 목록
// 탭한 날짜의 내역을 팝업(모달)으로 표시 — 캘린더 아래가 가려져도 잘 보이게
const activeDay = ref(0)
const dayModalOpen = ref(false)
function openDay(c) {
activeDay.value = c.day
dayModalOpen.value = true
}
function closeDayModal() {
dayModalOpen.value = false
}
const activeItems = computed(() => (activeDay.value ? dayMap.value[activeDay.value]?.items || [] : []))
const activeDateLabel = computed(() => {
if (!activeDay.value) return ''
@@ -230,8 +238,7 @@ onMounted(load)
type="button"
class="cal-cell"
:class="{ today: c.day === todayDate, active: c.day === activeDay, has: c.items.length }"
@mouseenter="activeDay = c.day"
@click="activeDay = activeDay === c.day ? 0 : c.day"
@click="openDay(c)"
>
<span class="cal-day">{{ c.day }}</span>
<span v-if="c.income" class="cal-amt income">+{{ won(c.income) }}</span>
@@ -240,24 +247,35 @@ onMounted(load)
</template>
</div>
<!-- 선택/오버한 날짜의 내역 목록 -->
<div class="cal-detail" :class="{ open: activeDay && activeItems.length }">
<template v-if="activeDay && activeItems.length">
<div class="cd-date">{{ activeDateLabel }}</div>
<ul class="cd-list">
<li v-for="(e, idx) in activeItems" :key="idx" class="cd-item">
<span class="cd-cat">{{ itemLabel(e) }}</span>
<span v-if="e.memo" class="cd-memo">{{ e.memo }}</span>
<span class="cd-amt" :class="{ income: e.type === 'INCOME', expense: e.type === 'EXPENSE' }">
{{ itemSign(e.type) }}{{ won(e.amount) }}
</span>
</li>
</ul>
</template>
<p v-else class="cd-hint">날짜에 마우스를 올리거나 탭하면 내역이 표시됩니다.</p>
</div>
<p class="cal-hint">날짜를 탭하면 날의 내역이 표시됩니다.</p>
</div>
<!-- 일별 내역 팝업 -->
<Teleport to="body">
<Transition name="fade">
<div v-if="dayModalOpen" class="day-modal-backdrop" @click.self="closeDayModal">
<div class="day-modal" role="dialog" aria-modal="true" aria-label="일별 내역">
<button class="day-modal-close" type="button" aria-label="닫기" @click="closeDayModal">×</button>
<div class="dm-date">{{ activeDateLabel }}</div>
<div class="dm-sum">
<span v-if="dayMap[activeDay]?.income" class="income">수입 +{{ won(dayMap[activeDay].income) }}</span>
<span v-if="dayMap[activeDay]?.expense" class="expense">지출 -{{ won(dayMap[activeDay].expense) }}</span>
</div>
<ul v-if="activeItems.length" class="dm-list">
<li v-for="(e, idx) in activeItems" :key="idx" class="dm-item">
<span class="dm-cat">{{ itemLabel(e) }}</span>
<span v-if="e.memo" class="dm-memo">{{ e.memo }}</span>
<span class="dm-amt" :class="{ income: e.type === 'INCOME', expense: e.type === 'EXPENSE' }">
{{ itemSign(e.type) }}{{ won(e.amount) }}
</span>
</li>
</ul>
<p v-else class="dm-empty"> 날은 내역이 없습니다.</p>
</div>
</div>
</Transition>
</Teleport>
<!-- 바로가기 -->
<div class="shortcuts">
<RouterLink v-for="s in shortcuts" :key="s.to" :to="s.to" class="shortcut">
@@ -490,57 +508,117 @@ onMounted(load)
.cal-amt.expense {
color: #c0392b;
}
.cal-detail {
margin-top: 0.7rem;
padding-top: 0.7rem;
border-top: 1px solid var(--color-border);
min-height: 1.2rem;
.cal-hint {
margin: 0.6rem 0 0;
font-size: 0.76rem;
opacity: 0.5;
text-align: center;
}
.cd-date {
font-size: 0.82rem;
/* 일별 내역 팝업 */
.day-modal-backdrop {
position: fixed;
inset: 0;
z-index: 1100;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.5);
padding: 1rem;
}
.day-modal {
position: relative;
width: 100%;
max-width: 360px;
max-height: 75vh;
overflow-y: auto;
padding: 1.4rem 1.25rem 1.25rem;
background: var(--color-background);
border: 1px solid var(--color-border);
border-radius: 10px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.3);
}
.day-modal-close {
position: absolute;
top: 0.4rem;
right: 0.55rem;
width: 2rem;
height: 2rem;
border: 0;
background: transparent;
color: var(--color-text);
font-size: 1.5rem;
line-height: 1;
cursor: pointer;
}
.dm-date {
font-size: 1rem;
font-weight: 700;
margin-bottom: 0.4rem;
}
.cd-list {
.dm-sum {
display: flex;
gap: 0.8rem;
font-size: 0.82rem;
font-weight: 600;
margin-bottom: 0.7rem;
padding-bottom: 0.6rem;
border-bottom: 1px solid var(--color-border);
}
.dm-sum .income {
color: #2e7d32;
}
.dm-sum .expense {
color: #c0392b;
}
.dm-list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 0.25rem;
gap: 0.5rem;
}
.cd-item {
.dm-item {
display: flex;
align-items: baseline;
gap: 0.5rem;
font-size: 0.82rem;
font-size: 0.86rem;
}
.cd-cat {
.dm-cat {
font-weight: 600;
flex-shrink: 0;
}
.cd-memo {
.dm-memo {
opacity: 0.6;
font-size: 0.76rem;
font-size: 0.78rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.cd-amt {
.dm-amt {
margin-left: auto;
font-weight: 700;
white-space: nowrap;
}
.cd-amt.income {
.dm-amt.income {
color: #2e7d32;
}
.cd-amt.expense {
.dm-amt.expense {
color: #c0392b;
}
.cd-hint {
font-size: 0.78rem;
opacity: 0.5;
margin: 0;
.dm-empty {
font-size: 0.86rem;
opacity: 0.6;
margin: 0.5rem 0 0;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.18s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
/* 바로가기 그리드 */