1<script setup>
2const config = useRuntimeConfig().public.sharingProviders;
3
4const props = defineProps({
5 author: {
6 type: String,
7 default: null
8 },
9 title: {
10 type: String,
11 default: null
12 },
13 description: {
14 type: String,
15 default: null
16 }
17});
18
19const { author, title, description } = props;
20
21const hasShareSupport = ref(false);
22const hasClipboardSupport = ref(false);
23const copied = ref(false);
24const url = ref(null);
25
26const shareMessageText = computed(
27 () => `Check out this post from ${author}!\n\n${url.value}`
28);
29
30const triggerShare = () => {
31 if (!process.client || !hasShareSupport.value) return;
32
33 navigator
34 .share({
35 title,
36 url,
37 text: description
38 })
39 .catch((error) => console.error("Error sharing", error));
40};
41
42const copyToClipboard = () => {
43 if (!process.client || !hasClipboardSupport.value) return;
44
45 navigator.clipboard
46 .writeText(window.location)
47 .then(() => {
48 copied.value = true;
49 setTimeout(() => {
50 copied.value = false;
51 }, 2000);
52 })
53 .catch((error) => console.error(error));
54};
55
56// Lifecycle hooks
57onMounted(() => {
58 // Check API support only on client-side
59 if (process.client) {
60 url.value = window.location;
61 hasShareSupport.value = !!navigator.share;
62 hasClipboardSupport.value = !!navigator.clipboard;
63
64 if (!hasShareSupport.value && !hasClipboardSupport.value) {
65 console.log("No support so revert to fallback content");
66 }
67 }
68});
69</script>
70
71<template>
72 <aside
73 class="print:hidden flex flex-row justify-center items-center gap-4 mt-16 md:w-[80%] mx-auto"
74 >
75 <div class="h-1 bg-stone-200 dark:bg-stone-700 grow" />
76 <div class="whitespace-nowrap px-4 flex flex-row items-center gap-4">
77 Share this post
78 <NuxtLink
79 v-if="config.bluesky"
80 target="_blank"
81 rel="noopener noreferer"
82 :to="`https://bsky.app/intent/compose?text=${encodeURIComponent(shareMessageText)}`"
83 >
84 <Icon
85 name="ri:bluesky-fill"
86 size="1.5rem"
87 title="Share on Bluesky"
88 />
89 </NuxtLink>
90
91 <template v-if="config.clipboard && hasClipboardSupport">
92 <div class="relative">
93 <button @click="copyToClipboard">
94 <Icon
95 :class="{
96 'hidden': !copied
97 }"
98 data-name="copied"
99 name="ri:checkbox-line"
100 size="1.5rem"
101 title="Copied to clipboard"
102 />
103 <Icon
104 :class="{
105 'hidden': copied
106 }"
107 name="ri:file-copy-2-line"
108 size="1.5rem"
109 title="Copy link to clipboard"
110 />
111 </button>
112 <p v-if="copied" class="absolute left-1/2 -translate-x-1/2 top-full mt-1 text-sm">
113 Copied to clipboard!
114 </p>
115 </div>
116 </template>
117
118 <template v-if="config.native && hasShareSupport">
119 <button @click="triggerShare">
120 <Icon
121 name="ri:share-2-fill"
122 size="1.5rem"
123 title="Other share options"
124 />
125 </button>
126 </template>
127 </div>
128 <div class="h-1 bg-stone-200 dark:bg-stone-700 grow" />
129 </aside>
130</template>
131
132<style scoped>
133
134</style>