Files
website/layers/diary/app/components/DiaryEntry.vue
T
2026-09-30 19:15:57 +02:00

56 lines
2.1 KiB
Vue

<script setup lang="ts">
import type { Entry } from '../types/entry'
const props = defineProps<{ entry: Entry, search: string }>()
const COLLAPSE_AFTER_CHARS = 320
const COLLAPSE_AFTER_LINES = 5
const { showCovers } = useAppConfig().diary
const expanded = ref(false)
const searching = computed(() => searchTerms(props.search).length > 0)
const isLong = computed(() =>
props.entry.text.length > COLLAPSE_AFTER_CHARS || props.entry.text.split('\n').length > COLLAPSE_AFTER_LINES
)
const collapsed = computed(() => isLong.value && !expanded.value && !searching.value)
const wordCount = computed(() => props.entry.text.split(/\s+/).filter(Boolean).length)
const parts = computed(() => highlight(props.entry.text, props.search))
</script>
<template>
<div class="flex gap-4">
<div
v-if="showCovers && entry.kind === 'review'"
class="aspect-2/3 w-16 shrink-0 self-start overflow-hidden rounded shadow-sm ring-1 ring-default"
>
<CoverTile :title="entry.review.title" :subtitle="entry.review.author" />
</div>
<article class="min-w-0 flex-1">
<div class="flex min-w-0 items-baseline gap-3">
<span class="shrink-0 text-xs text-muted tabular-nums">{{ formatDate(entry.date) }}</span>
<p v-if="entry.kind === 'review'" class="min-w-0 truncate">
<span class="font-medium text-highlighted">{{ entry.review.title }}</span>
<span v-if="entry.review.author" class="ml-3 text-sm text-muted">{{ entry.review.author }}</span>
</p>
</div>
<p
class="mt-1.5 text-sm leading-relaxed whitespace-pre-line text-default"
:class="{ 'line-clamp-5': collapsed }"
><template v-for="(part, index) in parts" :key="index"><mark v-if="part.hit" class="rounded-sm bg-primary/30 px-0.5 text-highlighted">{{ part.text }}</mark><template v-else>{{ part.text }}</template></template></p>
<UButton
v-if="isLong && !searching"
size="xs"
color="neutral"
variant="link"
class="mt-1 px-0"
:label="expanded ? 'Show less' : `Read more (${wordCount} words)`"
@click="expanded = !expanded"
/>
</article>
</div>
</template>