You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
2.3 KiB
101 lines
2.3 KiB
<script setup lang="ts">
|
|
import type { ArticleListItem } from '@/generated/api'
|
|
import ArticleMetaBar from '@/components/ArticleMetaBar.vue'
|
|
|
|
const props = defineProps<{
|
|
article: ArticleListItem
|
|
}>()
|
|
|
|
function coverSrc(): string | undefined {
|
|
const url = props.article.coverImage
|
|
if (!url) return undefined
|
|
if (url.startsWith('http://') || url.startsWith('https://')) return url
|
|
return url.startsWith('/') ? url : `/${url}`
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<router-link class="article-card" :to="`/post/${article.slug}`">
|
|
<img v-if="coverSrc()" :src="coverSrc()" class="article-cover" alt="" loading="lazy" />
|
|
<div class="article-body">
|
|
<h3 class="article-title">{{ article.title }}</h3>
|
|
<p v-if="article.summary" class="article-summary">{{ article.summary }}</p>
|
|
<div class="article-meta">
|
|
<span class="meta-author">{{ article.authorName }}</span>
|
|
<ArticleMetaBar
|
|
mode="card"
|
|
:created-at="article.publishedAt || article.createdAt"
|
|
:content="article.summary"
|
|
/>
|
|
</div>
|
|
<div class="article-tags">
|
|
<span v-for="tag in article.tagNames" :key="tag" class="tag">{{ tag }}</span>
|
|
</div>
|
|
</div>
|
|
</router-link>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.article-card {
|
|
display: block;
|
|
background: var(--ac-bg-card);
|
|
border: 1px solid var(--ac-border);
|
|
border-radius: var(--song-radius-l);
|
|
padding: 16px;
|
|
margin-bottom: 16px;
|
|
text-decoration: none;
|
|
color: inherit;
|
|
transition: box-shadow var(--song-dur-1) var(--song-ease);
|
|
}
|
|
|
|
.article-card:hover {
|
|
box-shadow: var(--ac-shadow-2);
|
|
}
|
|
|
|
.article-cover {
|
|
width: 100%;
|
|
max-height: 220px;
|
|
object-fit: cover;
|
|
border-radius: var(--song-radius-m);
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.article-title {
|
|
margin: 0 0 8px;
|
|
font-family: 'Noto Serif SC', 'SimSun', 'STSong', serif;
|
|
font-weight: 600;
|
|
font-size: 18px;
|
|
color: var(--ac-text);
|
|
}
|
|
|
|
.article-summary {
|
|
margin: 0 0 12px;
|
|
color: var(--ac-text-secondary);
|
|
font-size: 14px;
|
|
}
|
|
|
|
.article-meta {
|
|
display: flex;
|
|
gap: 16px;
|
|
font-size: 13px;
|
|
color: var(--ac-text-disabled);
|
|
}
|
|
|
|
.meta-author {
|
|
color: var(--ac-primary-ink);
|
|
}
|
|
|
|
.article-tags {
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.tag {
|
|
display: inline-block;
|
|
margin-right: 8px;
|
|
padding: 2px 10px;
|
|
background: var(--ac-primary-bg);
|
|
color: var(--ac-primary-ink);
|
|
border-radius: var(--song-radius-m);
|
|
font-size: 12px;
|
|
}
|
|
</style>
|