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.
207 lines
4.0 KiB
207 lines
4.0 KiB
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { marked } from 'marked'
|
|
|
|
const props = defineProps<{
|
|
title: string
|
|
description: string
|
|
content: string
|
|
tags: string[]
|
|
aspectRatio: number
|
|
categoryName?: string
|
|
}>()
|
|
|
|
const contentHtml = computed(() => {
|
|
if (!props.content) return ''
|
|
return marked(props.content, { breaks: true }) as string
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="card">
|
|
<span v-if="categoryName" class="card-cat-chip">{{ categoryName }}</span>
|
|
|
|
<!-- 上部分:正文内容预览 -->
|
|
<div class="card-preview">
|
|
<div class="preview-text" v-html="contentHtml" />
|
|
<div class="content-fade" />
|
|
</div>
|
|
|
|
<!-- 下部分:标签 / 标题 / 描述 -->
|
|
<div class="card-footer">
|
|
<div v-if="tags && tags.length" class="tags">
|
|
<span v-for="tag in tags" :key="tag" class="tag">{{ tag }}</span>
|
|
</div>
|
|
<h3>{{ title }}</h3>
|
|
<p v-if="description" class="desc">{{ description }}</p>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.card-cat-chip {
|
|
position: absolute;
|
|
top: 8px;
|
|
left: 8px;
|
|
z-index: 2;
|
|
font-size: 10px;
|
|
font-weight: 600;
|
|
padding: 2px 8px;
|
|
border-radius: 9999px;
|
|
background: rgba(204, 120, 92, 0.12);
|
|
color: var(--color-primary);
|
|
letter-spacing: 0.3px;
|
|
}
|
|
|
|
.card {
|
|
position: relative;
|
|
border-radius: 12px;
|
|
background: var(--color-surface-card);
|
|
overflow: hidden;
|
|
border: 1px solid var(--color-hairline-soft);
|
|
display: flex;
|
|
flex-direction: column;
|
|
transition: transform 0.4s var(--ease-out-expo), box-shadow 0.4s var(--ease-out-expo);
|
|
}
|
|
|
|
.card:hover {
|
|
transform: translateY(-2px) scale(1.005);
|
|
box-shadow: 0 8px 24px rgba(20, 20, 19, 0.08);
|
|
}
|
|
|
|
/* ── 上部分:正文预览 ── */
|
|
|
|
.card-preview {
|
|
position: relative;
|
|
padding: 20px 20px 16px;
|
|
}
|
|
|
|
.preview-text {
|
|
font-size: 13px;
|
|
font-weight: 400;
|
|
line-height: 1.7;
|
|
color: var(--color-body);
|
|
max-height: 96px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
/* markdown 元素降级样式(预览态,不让标题/代码过于抢眼) */
|
|
.preview-text :deep(h1),
|
|
.preview-text :deep(h2),
|
|
.preview-text :deep(h3) {
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
line-height: 1.5;
|
|
color: var(--color-ink);
|
|
margin: 0 0 4px;
|
|
}
|
|
|
|
.preview-text :deep(p) {
|
|
margin: 0 0 4px;
|
|
}
|
|
|
|
.preview-text :deep(ul),
|
|
.preview-text :deep(ol) {
|
|
margin: 0 0 4px;
|
|
padding-left: 18px;
|
|
}
|
|
|
|
.preview-text :deep(li) {
|
|
margin-bottom: 2px;
|
|
}
|
|
|
|
.preview-text :deep(code) {
|
|
font-size: 12px;
|
|
background: var(--color-surface-cream-strong);
|
|
padding: 1px 5px;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.preview-text :deep(pre) {
|
|
font-size: 12px;
|
|
background: var(--color-surface-cream-strong);
|
|
padding: 8px 12px;
|
|
border-radius: 6px;
|
|
margin: 0 0 6px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.preview-text :deep(blockquote) {
|
|
margin: 0 0 4px;
|
|
padding-left: 12px;
|
|
border-left: 2px solid var(--color-hairline);
|
|
color: var(--color-muted);
|
|
}
|
|
|
|
.preview-text :deep(a) {
|
|
color: var(--color-primary);
|
|
pointer-events: none;
|
|
}
|
|
|
|
.preview-text :deep(img) {
|
|
display: none;
|
|
}
|
|
|
|
.content-fade {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 52px;
|
|
background: linear-gradient(
|
|
to bottom,
|
|
transparent 0%,
|
|
var(--color-surface-card) 100%
|
|
);
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* ── 下部分:标签 / 标题 / 描述 ── */
|
|
|
|
.card-footer {
|
|
padding: 0 20px 20px;
|
|
}
|
|
|
|
.tags {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 6px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.tag {
|
|
font-size: 11px;
|
|
font-weight: 500;
|
|
color: var(--color-primary);
|
|
background: rgba(204, 120, 92, 0.08);
|
|
padding: 3px 10px;
|
|
border-radius: 9999px;
|
|
line-height: 1.3;
|
|
}
|
|
|
|
.card-footer h3 {
|
|
font-family: var(--font-display);
|
|
font-size: 15.5px;
|
|
font-weight: 400;
|
|
line-height: 1.3;
|
|
color: var(--color-ink);
|
|
margin: 0 0 6px;
|
|
letter-spacing: -0.01em;
|
|
overflow: hidden;
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 2;
|
|
-webkit-box-orient: vertical;
|
|
}
|
|
|
|
.desc {
|
|
font-size: 12px;
|
|
font-weight: 400;
|
|
line-height: 1.55;
|
|
color: var(--color-muted);
|
|
margin: 0;
|
|
overflow: hidden;
|
|
display: -webkit-box;
|
|
-webkit-line-clamp: 2;
|
|
-webkit-box-orient: vertical;
|
|
}
|
|
</style>
|
|
|