Simplify ledger summary and nav icons

This commit is contained in:
2026-08-13 17:19:58 +09:00
parent 90e8b48c2b
commit f1456586b9
7 changed files with 62 additions and 32 deletions

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M200-200v-560 560Zm0 80q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v100h-80v-100H200v560h560v-100h80v100q0 33-23.5 56.5T760-120H200Zm320-160q-33 0-56.5-23.5T440-360v-240q0-33 23.5-56.5T520-680h280q33 0 56.5 23.5T880-600v240q0 33-23.5 56.5T800-280H520Zm280-80v-240H520v240h280Zm-117.5-77.5Q700-455 700-480t-17.5-42.5Q665-540 640-540t-42.5 17.5Q580-505 580-480t17.5 42.5Q615-420 640-420t42.5-17.5Z"/></svg>

After

Width:  |  Height:  |  Size: 555 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M640-160v-280h160v280H640Zm-240 0v-640h160v640H400Zm-240 0v-440h160v440H160Z"/></svg>

After

Width:  |  Height:  |  Size: 201 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M240-80q-50 0-85-35t-35-85v-120h120v-560l60 60 60-60 60 60 60-60 60 60 60-60 60 60 60-60 60 60 60-60v680q0 50-35 85t-85 35H240Zm480-80q17 0 28.5-11.5T760-200v-560H320v440h360v120q0 17 11.5 28.5T720-160ZM360-600v-80h240v80H360Zm0 120v-80h240v80H360Zm320-120q-17 0-28.5-11.5T640-640q0-17 11.5-28.5T680-680q17 0 28.5 11.5T720-640q0 17-11.5 28.5T680-600Zm0 120q-17 0-28.5-11.5T640-520q0-17 11.5-28.5T680-560q17 0 28.5 11.5T720-520q0 17-11.5 28.5T680-480ZM240-160h360v-80H200v40q0 17 11.5 28.5T240-160Zm-40 0v-80 80Z"/></svg>

After

Width:  |  Height:  |  Size: 636 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="m370-80-16-128q-13-5-24.5-12T307-235l-119 50L78-375l103-78q-1-7-1-13.5v-27q0-6.5 1-13.5L78-585l110-190 119 50q11-8 23-15t24-12l16-128h220l16 128q13 5 24.5 12t22.5 15l119-50 110 190-103 78q1 7 1 13.5v27q0 6.5-2 13.5l103 78-110 190-118-50q-11 8-23 15t-24 12L590-80H370Zm70-80h79l14-106q31-8 57.5-23.5T639-327l99 41 39-68-86-65q5-14 7-29.5t2-31.5q0-16-2-31.5t-7-29.5l86-65-39-68-99 42q-22-23-48.5-38.5T533-694l-13-106h-79l-14 106q-31 8-57.5 23.5T321-633l-99-41-39 68 86 64q-5 15-7 30t-2 32q0 16 2 31t7 30l-86 65 39 68 99-42q22 23 48.5 38.5T427-266l13 106Zm42-180q58 0 99-41t41-99q0-58-41-99t-99-41q-59 0-99.5 41T342-480q0 58 40.5 99t99.5 41Zm-2-140Z"/></svg>

After

Width:  |  Height:  |  Size: 771 B

View File

@@ -26,3 +26,6 @@
- 거래 목록의 카테고리 표시는 하위 카테고리명 중심으로 단순화했다.
- 내역 화면 상단을 헤더, 월 요약, 주간 날짜 스트립 구조로 개편했다.
- 방향 이동 버튼을 `assets/icons`의 SVG 화살표로 통일했다.
- 내역 화면의 선택일 요약 박스를 제거하고 날짜별 수입/지출 금액을 주간 날짜 셀 안에 작게 표시했다.
- 월 지출 하단 설명을 수입/차액 대신 지난달 대비 지출 비교 문구로 단순화했다.
- 하단 네비게이션과 PC 사이드바에 SVG 메뉴 아이콘을 적용하고 활성 탭 색상을 명확하게 표시했다.

View File

@@ -13,10 +13,10 @@
v-for="item in items"
:key="item.to"
:to="item.to"
class="mb-2 flex min-h-12 items-center gap-3 rounded-md px-4 text-sm font-semibold text-muted"
active-class="bg-red-50 text-red-600"
class="mb-2 flex min-h-12 items-center gap-3 rounded-md px-4 text-sm font-semibold"
:class="isActive(item.to) ? 'bg-red-50 text-red-600' : 'text-muted hover:bg-paper'"
>
<span class="text-lg leading-none">{{ item.icon }}</span>
<span class="h-6 w-6 bg-current" :style="iconStyle(item.icon)" aria-hidden="true" />
<span>{{ item.label }}</span>
</NuxtLink>
</nav>
@@ -36,10 +36,10 @@
v-for="item in items"
:key="item.to"
:to="item.to"
class="flex min-h-14 flex-col items-center justify-center gap-0.5 text-[11px] font-medium text-muted"
active-class="text-brand-700"
class="flex min-h-14 flex-col items-center justify-center gap-0.5 text-[11px] font-bold"
:class="isActive(item.to) ? 'text-red-600' : 'text-muted'"
>
<span class="text-lg leading-none">{{ item.icon }}</span>
<span class="h-6 w-6 bg-current" :style="iconStyle(item.icon)" aria-hidden="true" />
<span>{{ item.label }}</span>
</NuxtLink>
</div>
@@ -56,15 +56,31 @@
</template>
<script setup lang="ts">
import assetIcon from '~/assets/icons/account_balance_wallet.svg'
import reportIcon from '~/assets/icons/bar_chart.svg'
import receiptIcon from '~/assets/icons/receipt_long.svg'
import settingsIcon from '~/assets/icons/settings.svg'
const route = useRoute()
const items = [
{ to: '/', label: '내역', icon: '≡' },
{ to: '/stats', label: '통계', icon: '∑' },
{ to: '/assets', label: '자산', icon: '◎' },
{ to: '/settings', label: '설정', icon: '⚙' }
{ to: '/', label: '내역', icon: receiptIcon },
{ to: '/stats', label: '통계', icon: reportIcon },
{ to: '/assets', label: '자산', icon: assetIcon },
{ to: '/settings', label: '설정', icon: settingsIcon }
]
const showNav = computed(() => route.path !== '/login')
const showFab = computed(() => showNav.value && route.path !== '/add' && !route.path.startsWith('/transactions/'))
function isActive(to: string) {
return to === '/' ? route.path === '/' : route.path.startsWith(to)
}
function iconStyle(icon: string) {
return {
mask: `url(${icon}) center / contain no-repeat`,
WebkitMask: `url(${icon}) center / contain no-repeat`
}
}
</script>

View File

@@ -31,8 +31,7 @@
{{ formatWon(data?.summary.expense || 0) }}
</p>
<p class="mt-2 text-sm font-semibold text-muted">
수입 <span class="text-brand-700">{{ formatWon(data?.summary.income || 0) }}</span>
· 차액 <span :class="(data?.summary.diff || 0) >= 0 ? 'text-brand-700' : 'text-red-600'">{{ formatWon(data?.summary.diff || 0) }}</span>
{{ monthlyComparisonLabel }}
</p>
</div>
<NuxtLink to="/stats" class="btn-secondary flex shrink-0 gap-2 px-3 text-xs md:px-4">
@@ -53,7 +52,7 @@
v-for="day in weekDays"
:key="day.key"
type="button"
class="min-h-[4.75rem] rounded-md px-1 py-2"
class="min-h-[4.35rem] rounded-md px-1 py-2"
:class="day.key === selectedDate ? 'text-ink' : day.inMonth ? 'text-muted active:bg-paper' : 'text-slate-300'"
@click="selectDate(day.key)"
>
@@ -63,26 +62,12 @@
>
{{ day.day }}
</span>
<span class="mt-1 block min-h-4 truncate text-[11px] font-bold" :class="day.key === selectedDate ? 'text-ink' : ''">
{{ day.amountLabel }}
<span class="mt-1 block min-h-7 space-y-0.5 text-[10px] font-bold leading-none">
<span v-if="day.expenseLabel" class="block truncate text-red-500">{{ day.expenseLabel }}</span>
<span v-if="day.incomeLabel" class="block truncate text-brand-700">{{ day.incomeLabel }}</span>
</span>
</button>
</div>
<div class="mt-2 grid grid-cols-3 gap-2 rounded-md bg-paper px-3 py-2 text-center text-xs font-semibold">
<div>
<p class="text-muted">선택일 수입</p>
<p class="mt-0.5 text-brand-700">{{ formatWon(selectedDaySummary.income) }}</p>
</div>
<div>
<p class="text-muted">선택일 지출</p>
<p class="mt-0.5 text-red-600">{{ formatWon(selectedDaySummary.expense) }}</p>
</div>
<div>
<p class="text-muted">합계</p>
<p class="mt-0.5">{{ formatWon(selectedDaySummary.diff) }}</p>
</div>
</div>
</div>
</div>
</header>
@@ -113,9 +98,17 @@ import type { Transaction } from '~/composables/useMoney'
const selectedDate = ref(formatDateOnly())
const weekSwipeStartX = ref(0)
const selectedMonth = computed(() => monthKey(parse(selectedDate.value, 'yyyy-MM-dd', new Date())))
const previousMonth = computed(() => {
const date = parse(selectedMonth.value, 'yyyy-MM', new Date())
return format(addMonths(date, -1), 'yyyy-MM')
})
const { data } = await useFetch('/api/transactions', {
query: { month: selectedMonth }
})
const { data: previousData } = await useFetch('/api/transactions', {
key: computed(() => `transactions-previous-${previousMonth.value}`),
query: { month: previousMonth }
})
const weekdays = ['일', '월', '화', '수', '목', '금', '토']
const groupedTransactions = computed(() => {
@@ -146,12 +139,21 @@ const weekDays = computed(() => {
key,
day: format(date, 'd'),
inMonth: monthKey(date) === selectedMonth.value,
amountLabel: summary.expense ? shortWon(summary.expense) : summary.income ? shortWon(summary.income) : ''
expenseLabel: summary.expense ? shortWon(summary.expense) : '',
incomeLabel: summary.income ? shortWon(summary.income) : ''
}
})
})
const selectedDaySummary = computed(() => daySummary(selectedDate.value))
const monthlyComparisonLabel = computed(() => {
const currentExpense = data.value?.summary.expense || 0
const previousExpense = previousData.value?.summary.expense || 0
const diff = previousExpense - currentExpense
if (!previousExpense && !currentExpense) return '이번 달 지출 내역을 기다리는 중'
if (diff > 0) return `지난달보다 ${compactWon(diff)} 덜 쓰는 중`
if (diff < 0) return `지난달보다 ${compactWon(Math.abs(diff))} 더 쓰는 중`
return '지난달과 같은 속도로 쓰는 중'
})
function moveMonth(amount: number) {
const date = parse(selectedDate.value, 'yyyy-MM-dd', new Date())
@@ -192,6 +194,11 @@ function shortWon(value: number) {
return value.toLocaleString('ko-KR')
}
function compactWon(value: number) {
if (value >= 10000) return `${Math.round(value / 10000).toLocaleString('ko-KR')}만원`
return formatWon(value)
}
function startWeekSwipe(event: TouchEvent) {
weekSwipeStartX.value = event.changedTouches[0]?.clientX || 0
}