72 lines
2.2 KiB
Vue
72 lines
2.2 KiB
Vue
<template>
|
|
<component
|
|
:is="rowComponent"
|
|
v-bind="rowAttrs"
|
|
class="grid grid-cols-[2.5rem_minmax(0,1fr)_auto] items-start gap-3 px-4 py-3 active:bg-paper md:px-5"
|
|
>
|
|
<div
|
|
class="mt-0.5 flex h-10 w-10 items-center justify-center rounded-md text-sm font-extrabold"
|
|
:style="categoryIconStyle"
|
|
aria-hidden="true"
|
|
>
|
|
{{ categoryIconGlyph }}
|
|
</div>
|
|
|
|
<div class="min-w-0">
|
|
<p class="truncate text-[15px] font-bold leading-5 text-ink">
|
|
{{ transaction.title }}
|
|
</p>
|
|
<p class="mt-1 truncate text-xs font-medium leading-5 text-muted">
|
|
{{ metaLine }}
|
|
</p>
|
|
<p v-if="memoPreview" class="mt-1 truncate text-xs font-medium leading-5 text-muted">
|
|
{{ memoPreview }}
|
|
</p>
|
|
</div>
|
|
|
|
<p
|
|
class="whitespace-nowrap pt-0.5 text-right text-[15px] font-bold leading-5"
|
|
:class="transaction.type === 'income' ? 'text-brand-700' : 'text-ink'"
|
|
>
|
|
{{ formatWon(transaction.amount) }}
|
|
</p>
|
|
</component>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import type { Transaction } from '~/composables/useMoney'
|
|
import { categoryColor, categoryGlyph } from '~/utils/categoryPresentation'
|
|
|
|
const props = defineProps<{
|
|
transaction: Transaction
|
|
readonly?: boolean
|
|
}>()
|
|
|
|
const rowComponent = computed(() => props.readonly ? 'div' : resolveComponent('NuxtLink'))
|
|
const rowAttrs = computed(() => props.readonly ? {} : { to: `/transactions/${props.transaction.id}` })
|
|
const categoryLabel = computed(() => {
|
|
const category = props.transaction.category
|
|
return category.name
|
|
})
|
|
|
|
const presentationCategory = computed(() => {
|
|
const category = props.transaction.category
|
|
return category.icon || category.color ? category : category.parent || category
|
|
})
|
|
|
|
const categoryIconGlyph = computed(() => categoryGlyph(presentationCategory.value.icon))
|
|
const categoryIconStyle = computed(() => {
|
|
const color = categoryColor(presentationCategory.value.color)
|
|
return {
|
|
color,
|
|
backgroundColor: `${color}14`
|
|
}
|
|
})
|
|
|
|
const metaLine = computed(() => {
|
|
return [props.transaction.asset.name, categoryLabel.value].filter(Boolean).join(' · ')
|
|
})
|
|
|
|
const memoPreview = computed(() => props.transaction.memo?.trim().slice(0, 60) || '')
|
|
</script>
|