mirror of https://github.com/nocodb/nocodb
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.
121 lines
3.5 KiB
121 lines
3.5 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, |
|
) |
|
}) |
|
|
|
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"> |
|
.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-2xl text-nc-content-gray-emphasis truncate leading-9 mb-0; |
|
font-weight: 700; |
|
} |
|
p { |
|
@apply text-nc-content-gray-emphasis leading-5; |
|
font-size: 14px !important; |
|
} |
|
|
|
h3 { |
|
@apply text-nc-content-gray-emphasis text-lg leading-5 mb-0; |
|
} |
|
} |
|
} |
|
</style>
|
|
|