Skip to content

Commit 51d3989

Browse files
committed
update ArticleCardV2 component
1 parent 8839eb2 commit 51d3989

4 files changed

Lines changed: 256 additions & 4 deletions

File tree

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<template>
2+
<article
3+
class="group relative flex flex-col h-full bg-white dark:bg-[#111] border border-gray-200 dark:border-gray-800 transition-all duration-300 hover:border-gray-900 dark:hover:border-gray-500 hover:shadow-xl"
4+
>
5+
<div class="relative w-full h-56 overflow-hidden bg-gray-100 dark:bg-gray-800 border-b border-gray-100 dark:border-gray-800">
6+
<img
7+
v-if="article.coverImage"
8+
:src="article.coverImage"
9+
:alt="article.title"
10+
class="w-full h-full object-cover transition-transform duration-700 group-hover:scale-105"
11+
/>
12+
<div v-else class="w-full h-full flex items-center justify-center text-gray-300 dark:text-gray-700">
13+
<span class="text-4xl font-mono font-bold opacity-20">M / 451</span>
14+
</div>
15+
16+
<router-link
17+
v-if="article.category"
18+
:to="`/categories/${article.category.slug || article.category.id}`"
19+
class="absolute top-4 right-4 bg-white/90 dark:bg-black/80 backdrop-blur-sm px-3 py-1 text-xs font-mono font-medium uppercase tracking-wider text-gray-900 dark:text-white border border-gray-200 dark:border-gray-700 hover:bg-black hover:text-white transition-colors"
20+
>
21+
{{ article.category.name }}
22+
</router-link>
23+
</div>
24+
25+
<div class="flex flex-col flex-grow p-6">
26+
<div class="flex items-center text-xs font-mono text-gray-500 mb-3 space-x-4">
27+
<time :datetime="article.createdAt">
28+
{{ formatDate(article.createdAt) }}
29+
</time>
30+
<span v-if="article.views" class="flex items-center">
31+
<span class="mr-1">/</span> {{ article.views }} READS
32+
</span>
33+
</div>
34+
35+
<router-link :to="`/posts/${article.id}`" class="block group-hover:underline decoration-2 decoration-blue-600 underline-offset-4">
36+
<h3 class="text-xl font-bold text-gray-900 dark:text-gray-100 leading-tight mb-3">
37+
{{ article.title }}
38+
</h3>
39+
</router-link>
40+
41+
<p class="text-gray-600 dark:text-gray-400 text-sm leading-relaxed line-clamp-3 mb-4 flex-grow">
42+
{{ article.excerpt || stripHtml(article.content) }}
43+
</p>
44+
45+
<div class="pt-4 border-t border-gray-100 dark:border-gray-800 flex items-center justify-between mt-auto">
46+
<div class="flex flex-wrap gap-2">
47+
<router-link
48+
v-for="tag in article.tags.slice(0, 3)"
49+
:key="tag.id"
50+
:to="`/tags/${tag.slug || tag.id}`"
51+
class="text-xs font-mono text-gray-500 hover:text-blue-600 transition-colors"
52+
>
53+
#{{ tag.name }}
54+
</router-link>
55+
</div>
56+
57+
<router-link :to="`/posts/${article.id}`" class="text-gray-900 dark:text-white group-hover:translate-x-1 transition-transform">
58+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
59+
<path stroke-linecap="round" stroke-linejoin="round" d="M17.25 8.25L21 12m0 0l-3.75 3.75M21 12H3" />
60+
</svg>
61+
</router-link>
62+
</div>
63+
</div>
64+
</article>
65+
</template>
66+
67+
<script setup>
68+
import { defineProps } from 'vue';
69+
70+
const props = defineProps({
71+
article: {
72+
type: Object,
73+
required: true,
74+
// 默认值保护,防止报错
75+
default: () => ({
76+
tags: [],
77+
category: null,
78+
title: 'Untitled Post',
79+
content: ''
80+
})
81+
}
82+
});
83+
84+
// 1. 更优雅的日期格式化 (Intl API)
85+
const formatDate = (dateString) => {
86+
if (!dateString) return '';
87+
return new Intl.DateTimeFormat('en-US', {
88+
year: 'numeric',
89+
month: 'short', // "Dec" 比 "12月" 在技术博客里更好看
90+
day: 'numeric'
91+
}).format(new Date(dateString));
92+
};
93+
94+
// 2. 简单的去 HTML 标签工具 (防止摘要显示 raw markdown)
95+
const stripHtml = (html) => {
96+
if (!html) return 'No preview available.';
97+
// 创建一个临时的 DOM 元素来提取纯文本
98+
const tmp = document.createElement("DIV");
99+
tmp.innerHTML = html;
100+
return tmp.textContent || tmp.innerText || "";
101+
};
102+
</script>
103+
104+
<style scoped>
105+
/* 确保 line-clamp 生效 (Tailwind 通常自带,但以防万一) */
106+
.line-clamp-3 {
107+
display: -webkit-box;
108+
-webkit-line-clamp: 3;
109+
-webkit-box-orient: vertical;
110+
overflow: hidden;
111+
}
112+
</style>

client/src/views/HomeView.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
<!-- 文章列表 -->
3939
<div v-else class="space-y-6">
40-
<ArticleCard
40+
<ArticleCardV2
4141
v-for="post in posts"
4242
:key="post.id"
4343
:article="post"
@@ -85,7 +85,8 @@
8585
<script setup>
8686
import { ref, onMounted } from 'vue';
8787
import Navbar from '../components/Navbar.vue';
88-
import ArticleCard from '../components/ArticleCard.vue';
88+
// import ArticleCard from '../components/ArticleCard.vue';
89+
import ArticleCardV2 from '@/components/ArticleCardV2.vue'; // 引入新的
8990
import Pagination from '../components/Pagination.vue';
9091
import Footer from '../components/Footer.vue';
9192
import CategoryList from '../components/CategoryList.vue';

client/tailwind.config.cjs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,15 @@ module.exports = {
55
"./src/**/*.{vue,js,ts,jsx,tsx}",
66
],
77
theme: {
8-
extend: {},
8+
extend: {
9+
fontFamily: {
10+
// 让正文用无衬线字体,代码/元数据用等宽字体
11+
sans: ['Inter', 'ui-sans-serif', 'system-ui', 'sans-serif'],
12+
mono: ['"JetBrains Mono"', '"Fira Code"', 'Consolas', 'monospace'],
13+
},
14+
},
915
},
10-
plugins: [],
16+
plugins: [
17+
require('@tailwindcss/line-clamp'), // 如果你的 tailwind 版本较老,需要这个插件
18+
],
1119
}

node_modules/.vue-global-types/vue_3.5_0.d.ts

Lines changed: 131 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)