<main class="layout-maxed ma-collection-details" id="app" v-cloak @keyup="changeImage"> <h1> {{item.artists_sort}} - {{item.title}} <i class="icon-trash" title="Supprimer cette fiche" @click="showConfirmDelete()"></i> <i class="icon-refresh" title="Mettre à jour les données de cette fiche" @click="updateItem()"></i> </h1> <div class="grid sm:grid-cols-3 gap-16"> <div class="text-center"> <img :src="item.thumb %>" :alt="`Miniature pour l'album ${item.title}`" /> </div> <div class="sm:col-span-2 text-center galerie"> <div v-for="(image, index) in item.images" :data-index="index" @click.stop.prevent="showGallery"> <img :src="image.uri150" :alt="`Miniature de type ${image.type}`" /> </div> </div> </div> <hr /> <div class="grid md:grid-cols-3 gap-16"> <div> <template v-for="album in tracklist"> <strong v-if="album.title">{{album.title}}</strong> <ol class="ml-4"> <li v-for="track in album.tracks"> {{ track.title }} <template v-if="track.duration">({{track.duration}})</template> <ul v-if="track.extraartists && track.extraartists.length > 0" class="sm-hidden ml-4"> <li v-for="extra in track.extraartists"> <small>{{extra.role}} : {{extra.name}}</small> </li> </ul> </li> </ol> </template> </div> <div class="md:col-span-2"> <div class="grid grid-cols-2 gap-10"> <div> <strong>Genres</strong> <br /> <template v-for="(genre, index) in item.genres"> {{genre}}<template v-if="index < item.genres.length - 1">, </template> </template> </div> <div> <strong>Styles</strong> <br /> <span v-for="(style, index) in item.styles"> {{style}}<template v-if="index < item.styles.length - 1">, </template> </span> </div> </div> <hr /> <div class="grid grid-cols-3 gap-10"> <div> <strong>Pays</strong> <br /> <span>{{item.country}}</span> </div> <div> <strong>Année</strong> <br /> <span>{{item.year}}</span> </div> <div> <strong>Date de sortie</strong> <br /> <span>{{item.released}}</span> </div> </div> <hr /> <div class="grid gap-10"> <div> <strong>Format</strong> <ul class="ml-4"> <li v-for="(format) in item.formats"> {{format.name}} <template v-if="format.text"> - <i>{{format.text}}</i> </template> <template v-if="format.descriptions && format.descriptions.length > 0"> (<span v-for="(description, index) in format.descriptions"> {{description}}<template v-if="index < format.descriptions.length - 1">, </template> </span>) </template> </li> </ul> </div> </div> <hr /> <div class="grid grid-cols-2 gap-10"> <div> <strong id="identifiers">Codes barres</strong> <ol class="ml-4"> <li v-for="identifier in identifiers"> {{identifier.value}} ({{identifier.type}}) </li> </ol> <template v-if="item.identifiers.length > identifiersPreviewLength"> <button type="button" class="button is-link" v-if="identifiersMode === 'preview'" @click="showAllIdentifiers"> Voir la suite </button> <button type="button" class="button is-link" v-if="identifiersMode === 'all'" @click="showLessIdentifiers"> Voir moins </button> </template> </div> <div> <strong>Label</strong> <br /> <template v-for="label in item.labels"> {{label.name}} {{label.catno}} <br /> </template> <hr /> <strong>Sociétés</strong> <br /> <template v-for="company in item.companies"> <strong>{{company.entity_type_name}}</strong> : {{company.name}} <br /> </template> </div> </div> <!-- <hr /> <div class="grid gap-10"> <div> <strong>Note</strong> <br /> <span>{{item.notes}}</span> </div> </div> --> <hr /> <div class="grid gap-10"> <div> <strong>Vidéos</strong> <dl> <template v-for="video in item.videos"> <dt> <a :href="video.uri" target="_blank" rel="noopener noreferrer">{{video.title}}</a> </dt> <dd> {{video.description}} </dd> </template> </dl> </div> </div> </div> </div> <div class="modal" :class="{'is-visible': modalIsVisible}"> <div class="modal-background"></div> <button type="button" aria-label="Fermer" class="close" @click="toggleModal"></button> <button type="button" aria-label="Image précédente" class="navigation previous" @click="previous" v-if="index > 0"> <i class="icon-left-open"></i> </button> <button type="button" aria-label="Image suivante" class="navigation next" @click="next" v-if="index + 1 < item.images.length"> <i class="icon-right-open"></i> </button> <div class="modal-card"> <img :src="preview" /> </div> </div> <div class="modal" :class="{'is-visible': showModalDelete}"> <div class="modal-background"></div> <div class="modal-card"> <header></header> <section> Êtes-vous sûr de vouloir supprimer cet album ? </section> <footer> <button class="button is-primary" @click="deleteItem">Supprimer</button> <button class="button" @click="toggleModal">Annuler</button> </footer> </div> </div> </main> <script> Vue.createApp({ data() { return { item: <%- JSON.stringify(page.item) %>, tracklist: [], identifiers: [], modalIsVisible: false, identifiersMode: 'preview', identifiersPreviewLength: 16, preview: null, index: null, showModalDelete: false, } }, created() { this.setTrackList(); this.setIdentifiers(); window.addEventListener("keydown", this.changeImage); }, destroyed() { window.removeEventListener('keydown', this.changeImage); }, methods: { setIdentifiers() { this.identifiers = []; let max = this.identifiersMode == 'preview' && this.item.identifiers.length > this.identifiersPreviewLength ? this.identifiersPreviewLength : this.item.identifiers.length; for ( let i = 0 ; i < max ; i += 1 ) { this.identifiers.push(this.item.identifiers[i]); } }, setTrackList() { let subTrack = { type: null, title: null, tracks: [], }; for (let i = 0 ; i < this.item.tracklist.length ; i += 1 ) { const { type_, title, position, duration, extraartists, } = this.item.tracklist[i]; if ( type_ === 'heading' ) { if ( subTrack.type ) { this.tracklist.push(subTrack); subTrack = { type: null, title: null, tracks: [], }; } subTrack.type = type_; subTrack.title = title; } else { subTrack.tracks.push({ title, position, duration, extraartists }); } } this.tracklist.push(subTrack); }, setImage() { this.preview = this.item.images[this.index].uri; }, showGallery(event) { const item = event.target.tagName === 'IMG' ? event.target.parentElement : event.target; const { index, } = item.dataset; this.index = Number(index); this.modalIsVisible = true; this.setImage(); }, toggleModal() { this.modalIsVisible = !this.modalIsVisible; }, previous() { this.index = this.index > 0 ? this.index - 1 : this.item.images.length -1; this.setImage(); }, next() { this.index = (this.index +1) === this.item.images.length ? 0 : this.index + 1; this.setImage(); }, changeImage(event) { const direction = event.code; if ( this.modalIsVisible && ['ArrowRight', 'ArrowLeft', 'Escape'].indexOf(direction) !== -1 ) { switch (direction) { case 'ArrowRight': return this.next(); case 'ArrowLeft': return this.previous(); default: this.modalIsVisible = false; return true; } } }, showAllIdentifiers() { this.identifiersMode = 'all'; this.setIdentifiers(); }, showLessIdentifiers() { this.identifiersMode = 'preview'; this.setIdentifiers(); document.querySelector('#identifiers').scrollIntoView({ behavior: 'smooth' }); }, showConfirmDelete() { this.toggleModal(); }, toggleModal() { this.showModalDelete = !this.showModalDelete; }, updateItem() { showToastr("Mise à jour en cours…", true); axios.patch(`/api/v1/albums/${this.item._id}`) .then( (res) => { showToastr("Mise à jour réalisée avec succès", true); this.item = res.data; }) .catch((err) => { showToastr(err.response?.data?.message || "Impossible de mettre à jour cet album", false); }); }, deleteItem() { axios.delete(`/api/v1/albums/${this.item._id}`) .then( () => { return locatiom.href = "/ma-collection"; }) .catch((err) => { showToastr(err.response?.data?.message || "Impossible de supprimer cet album"); }) .finally(() => { this.toggleModal(); }); }, }, }).mount('#app'); </script>