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>