返回 slidev
Tweet.vue
根目录 / packages / client / builtin / Tweet.vue
1 <!--
2 A simple wrapper for embedded Tweet
3
4 Usage:
5
6 <Tweet id="20" />
7 <Tweet url="https://x.com/jack/status/20" />
8 -->
9
10 <script setup lang="ts">
11 import { onMounted, ref } from 'vue'
12 import { isDark } from '../logic/dark'
13 import { resolveTweetId } from '../logic/tweet'
14
15 const props = defineProps<{
16 id?: string | number
17 url?: string
18 scale?: string | number
19 conversation?: string
20 cards?: 'hidden' | 'visible'
21 }>()
22
23 const tweet = ref<HTMLElement | null>()
24
25 const loaded = ref(false)
26 const tweetNotFound = ref(false)
27
28 async function create(retries = 10) {
29 const tweetId = resolveTweetId(props.id, props.url)
30 if (!tweetId) {
31 loaded.value = true
32 tweetNotFound.value = true
33 console.error('Tweet requires a valid id or X post URL.')
34 return
35 }
36
37 // @ts-expect-error global
38 if (!window.twttr?.widgets?.createTweet) {
39 if (retries <= 0)
40 return console.error('Failed to load Twitter widget after 10 retries.')
41 setTimeout(create, 1000, retries - 1)
42 return
43 }
44 // @ts-expect-error global
45 const element = await window.twttr.widgets.createTweet(
46 tweetId,
47 tweet.value,
48 {
49 theme: isDark.value ? 'dark' : 'light',
50 conversation: props.conversation || 'none',
51 cards: props.cards,
52 },
53 )
54 loaded.value = true
55 if (element === undefined)
56 tweetNotFound.value = true
57 }
58
59 onMounted(() => {
60 create()
61 })
62 </script>
63
64 <template>
65 <Transform :scale="scale || 1">
66 <div ref="tweet" class="tweet slidev-tweet">
67 <div v-if="!loaded || tweetNotFound" class="w-30 h-30 my-10px bg-gray-400 bg-opacity-10 rounded-lg flex opacity-50">
68 <div class="m-auto animate-pulse text-4xl">
69 <div class="i-carbon:logo-twitter" />
70 <span v-if="tweetNotFound">Could not load tweet</span>
71 </div>
72 </div>
73 </div>
74 </Transform>
75 </template>
76
77 <style>
78 .slidev-tweet iframe {
79 border-radius: 12px;
80 overflow: hidden;
81 }
82 </style>
83
83 lines Plain Text