多维表格
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.

130 lines
3.7 KiB

<script setup lang="ts">
import { unified } from 'unified'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import rehypeSanitize from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'
import { YoutubeVue3 } from 'youtube-vue3'
import type { ProductFeedItem } from '../../../lib/types'
import { extractYoutubeVideoId } from '../../../utils/urlUtils'
import { timeAgo } from '~/utils/datetimeUtils'
const props = defineProps<{
item: ProductFeedItem
}>()
const { getPossibleAttachmentSrc } = useAttachment()
const {
item: { 'Published Time': CreatedAt, Description, Url, Title, 'Feed Source': source, Images },
} = props
const feedIcon = {
Twitter: iconMap.twitter,
Youtube: iconMap.youtube,
Github: iconMap.githubSolid,
}
const truncate = ref(true)
const renderedText = computedAsync(async () => {
return await unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeSanitize)
.use(rehypeStringify)
.process(
truncate.value
? Description.replace(/!\[.*?\]\(.*?\)/g, '')
.substring(0, 250)
.concat('...')
: Description.replace(/^\[!\[.*?\]\(https?:\/\/.*?\)\]\(https?:\/\/.*?\)/m, ''),
)
})
const { width } = useWindowSize()
</script>
<template>
<div class="bg-white recent-card border-gray-200 border-1 rounded-2xl max-w-[540px] xl:max-w-[640px]">
<div class="flex items-center justify-between px-5 py-4">
<div class="flex items-center gap-3">
<component :is="feedIcon[source as any]" class="w-4 h-4 stroke-transparent" />
<span class="font-weight-medium text-nc-content-gray leading-5 cursor-pointer" @click="openLink(Url)">
{{ source }}
</span>
</div>
<div class="text-sm text-nc-content-gray-muted leading-5">
{{ timeAgo(CreatedAt) }}
</div>
</div>
<template v-if="source === 'Github'">
<div class="pb-5">
<LazyCellAttachmentPreviewImage
v-if="Images?.length"
class="cursor-pointer"
:srcs="getPossibleAttachmentSrc(Images[0], 'card_cover')"
@click="openLink(Url)"
/>
<div class="prose px-5 mt-5" v-html="renderedText"></div>
<NcButton v-if="truncate" size="small" class="w-29 mx-5" type="text" @click="truncate = false">
<div class="gap-2 flex items-center">
Show more
<GeneralIcon icon="arrowDown" />
</div>
</NcButton>
</div>
</template>
<template v-else-if="source === 'Youtube'">
<YoutubeVue3
:videoid="extractYoutubeVideoId(Url)"
:controls="1"
:height="width < 1280 ? 330 : 392"
:width="width < 1280 ? 538 : 638"
:autoplay="0"
/>
<div class="p-5 flex flex-col text-nc-content-gray-emphasis gap-4">
<div class="text-2xl font-semibold truncate">
{{ Title }}
</div>
<div class="font-weight-base text-md">
{{ Description.substring(0, 200).concat('...') }}
</div>
</div>
</template>
</div>
</template>
<style scoped lang="scss">
2 months ago
.recent-card {
box-shadow: 0px 4px 8px -2px rgba(0, 0, 0, 0.08), 0px 2px 4px -2px rgba(0, 0, 0, 0.04);
:deep(.prose) {
a {
@apply text-gray-900;
}
h1 {
@apply text-3xl text-nc-content-gray-emphasis truncate leading-9 mb-0;
font-weight: 700;
}
h2 {
@apply text-nc-content-gray-emphasis text-xl leading-6 !mb-0;
}
p {
@apply text-nc-content-gray-emphasis leading-6;
font-size: 14px !important;
}
li {
@apply text-nc-content-gray-emphasis leading-6;
font-size: 14px !important;
}
h3 {
@apply text-nc-content-gray-emphasis text-lg leading-6 mb-0;
}
}
2 months ago
}
2 months ago
</style>