127 lines
4.6 KiB
Vue
127 lines
4.6 KiB
Vue
<template>
|
|
<Teleport to="body">
|
|
<Transition name="fade" mode="out-in">
|
|
<div v-if="isOpen" class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm"
|
|
@click.self="close">
|
|
<div class="bg-white rounded-xl shadow-2xl p-6 w-full max-w-md">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h2 class="text-xl font-bold text-gray-900">Partager cette carte</h2>
|
|
<button @click="close" class="text-gray-400 hover:text-gray-500">
|
|
<span class="sr-only">Fermer</span>
|
|
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div v-if="currentTrack" class="space-y-4">
|
|
<div class="flex items-center space-x-4 p-3 bg-gray-50 rounded-lg">
|
|
<img :src="currentTrack.coverId || '/card-dock.svg'" :alt="currentTrack.title"
|
|
class="w-12 h-12 rounded-md object-cover">
|
|
<div class="min-w-0">
|
|
<p class="text-sm font-medium text-gray-900 truncate">{{ currentTrack.title }}</p>
|
|
<p class="text-sm text-gray-500 truncate">{{ typeof currentTrack.artist === 'object' ?
|
|
currentTrack.artist?.name : currentTrack.artist || 'Artiste inconnu' }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-2">
|
|
<label for="share-link" class="block text-sm font-medium text-gray-700">Lien de partage</label>
|
|
<div class="flex rounded-md shadow-sm">
|
|
<input type="text" id="share-link" readonly :value="shareLink"
|
|
class="flex-1 min-w-0 block w-full px-3 py-2 rounded-l-md border border-gray-300 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
|
@focus="selectText">
|
|
<button @click="copyToClipboard"
|
|
class="inline-flex items-center px-3 py-2 border border-l-0 border-gray-300 bg-gray-50 text-gray-700 text-sm font-medium rounded-r-md hover:bg-gray-100 focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24"
|
|
stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex justify-end space-x-3 pt-2">
|
|
<button @click="close"
|
|
class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
|
|
Fermer
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Transition>
|
|
</Teleport>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed, watch } from 'vue'
|
|
import { useUiStore } from '~/store/ui'
|
|
import type { Track } from '~~/types'
|
|
|
|
const uiStore = useUiStore()
|
|
const currentTrack = ref<Track | null>(null)
|
|
|
|
// Utilisation d'une ref locale pour éviter les réactivités inutiles
|
|
const isOpen = ref(false)
|
|
|
|
// Mise à jour de l'état uniquement quand nécessaire
|
|
watch(() => uiStore.showCardSharer, (newVal) => {
|
|
isOpen.value = newVal
|
|
})
|
|
|
|
const shareLink = computed(() => {
|
|
if (!currentTrack.value) return ''
|
|
return `${window.location.origin}/track/${currentTrack.value.id}`
|
|
})
|
|
|
|
const open = (track: Track) => {
|
|
currentTrack.value = track
|
|
isOpen.value = true
|
|
uiStore.openCardSharer()
|
|
}
|
|
|
|
const close = () => {
|
|
isOpen.value = false
|
|
uiStore.showCardSharer = false
|
|
// Nettoyage différé pour permettre l'animation
|
|
setTimeout(() => {
|
|
if (!isOpen.value) {
|
|
currentTrack.value = null
|
|
}
|
|
}, 300)
|
|
}
|
|
|
|
const copyToClipboard = async () => {
|
|
try {
|
|
await navigator.clipboard.writeText(shareLink.value)
|
|
// Vous pourriez ajouter un toast ou une notification ici
|
|
console.log('Lien copié dans le presse-papier')
|
|
} catch (err) {
|
|
console.error('Erreur lors de la copie :', err)
|
|
}
|
|
}
|
|
|
|
const selectText = (event: Event) => {
|
|
const input = event.target as HTMLInputElement
|
|
input.select()
|
|
}
|
|
|
|
defineExpose({
|
|
open,
|
|
close
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.fade-enter-active,
|
|
.fade-leave-active {
|
|
transition: opacity 0.2s ease;
|
|
}
|
|
|
|
.fade-enter-from,
|
|
.fade-leave-to {
|
|
opacity: 0;
|
|
}
|
|
</style> |