feat(theme): add component <ImageCard />

This commit is contained in:
pengzhanbo 2024-08-18 09:57:40 +08:00
parent e6f2e3fe64
commit edc0297c0c
2 changed files with 105 additions and 10 deletions

View File

@ -1,5 +1,41 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useMediaQuery } from '@vueuse/core'
const props = defineProps<{
cols?: string | number | { sm?: number, md?: number, lg?: number }
}>()
const md = useMediaQuery('(min-width: 768px)')
const lg = useMediaQuery('(min-width: 960px)')
const cols = computed(() => {
const reset = { sm: 1, md: 2, lg: 2 }
if (!props.cols)
return reset
if (typeof props.cols === 'number' || typeof props.cols === 'string') {
const cols = Number(props.cols)
return { sm: cols, md: cols, lg: cols }
}
return { ...reset, ...props.cols }
})
const repeat = computed(() => {
if (lg.value)
return cols.value.lg
else if (md.value)
return cols.value.md
else
return cols.value.sm
})
</script>
<template>
<div class="vp-card-grid">
<div
class="vp-card-grid" :class="[`cols-${repeat}`]" :style="{
gridTemplateColumns: `repeat(${repeat}, 1fr)`,
}"
>
<slot />
</div>
</template>
@ -14,10 +50,4 @@
.vp-card-grid > * {
margin: 0 !important;
}
@media (min-width: 768px) {
.vp-card-grid {
grid-template-columns: 1fr 1fr;
}
}
</style>

View File

@ -13,6 +13,14 @@ const props = defineProps<{
const lang = usePageLang()
const title = computed(() => {
if (props.title)
return props.title
const image = props.image || ''
const dirs = image.split('/')
return dirs[dirs.length - 1]
})
const date = computed(() => {
if (!props.date)
return ''
@ -30,8 +38,8 @@ const date = computed(() => {
<div class="vp-image-card">
<div class="image-container">
<img :src="image" :alt="title" loading="lazy">
<div v-if="title" class="image-info">
<h3 v-if="title" class="title">
<div class="image-info">
<h3 class="title">
<a v-if="href" :href="href" target="_blank" rel="noopener noreferrer">{{ title }}</a>
<span v-else>{{ title }}</span>
</h3>
@ -87,7 +95,21 @@ const date = computed(() => {
transform: translateY(calc(100% - 60px));
}
.vp-image-card:hover .image-info {
:where(.vp-card-grid.cols-3) .image-info {
padding: 8px 8px 0;
font-size: 12px;
transform: translateY(calc(100% - 36px));
}
@media (max-width: 767px) {
:where(.vp-card-grid.cols-2) .image-info {
padding: 8px 8px 0;
font-size: 12px;
transform: translateY(calc(100% - 36px));
}
}
.image-info:hover {
transform: translateY(0);
}
@ -100,6 +122,22 @@ const date = computed(() => {
white-space: nowrap;
}
:where(.vp-card-grid.cols-3) .image-info .title {
min-height: 20px;
margin: 0 0 8px;
font-size: 14px;
line-height: 20px;
}
@media (max-width: 767px) {
:where(.vp-card-grid.cols-2) .image-info .title {
min-height: 20px;
margin: 0 0 8px;
font-size: 14px;
line-height: 20px;
}
}
.image-info .title a {
color: inherit;
text-decoration: none;
@ -107,15 +145,37 @@ const date = computed(() => {
.image-info p {
margin: 0;
line-height: 24px;
color: var(--vp-c-white);
}
:where(.vp-card-grid.cols-3) .image-info p {
line-height: 20px;
}
@media (max-width: 767px) {
:where(.vp-card-grid.cols-2) .image-info p {
line-height: 20px;
}
}
.image-info p:last-child {
margin-bottom: 16px;
}
.image-info .copyright {
display: flex;
gap: 4px;
align-items: center;
justify-content: flex-end;
}
.image-info .copyright span:first-child {
flex: 1;
overflow: hidden;
text-align: right;
text-overflow: ellipsis;
white-space: nowrap;
}
.image-info .description {
@ -123,4 +183,9 @@ const date = computed(() => {
height: 1px;
overflow-y: auto;
}
.image-info .description::-webkit-scrollbar {
width: 0;
height: 0;
}
</style>