Co-authored-by: dbroqua <contact@darkou.fr>
Reviewed-on: https://git.darkou.fr/dbroqua/MusicTopus/pulls/28
Co-authored-by: Damien Broqua <dbroqua@noreply.localhost>
Co-committed-by: Damien Broqua <dbroqua@noreply.localhost>
This commit is contained in:
Damien Broqua 2022-03-04 16:33:45 +01:00
parent cf63d8b6d8
commit b27a81a0b6
26 changed files with 1094 additions and 97 deletions

View file

@ -52,12 +52,12 @@
</div>
</div>
<div class="modal" :class="{'is-visible': modalIsVisible}" id="addAlbum">
<div class="modal" :class="{'is-visible': modalIsVisible}">
<div class="modal-background"></div>
<div class="modal-card">
<header>
<div>{{details.artists_sort}} - {{details.title}}</div>
<button aria-label="Fermer" @click="toggleModal"></button>
<button aria-label="Fermer" class="close" @click="toggleModal"></button>
</header>
<section>
<div class="grid grid-cols-2 gap-16">
@ -217,8 +217,6 @@
this.modalIsVisible = !this.modalIsVisible;
},
loadDetails(discogsId) {
console.log('discogsId:', discogsId);
axios.get(`/api/v1/search/${discogsId}`)
.then( response => {
const {
@ -245,5 +243,5 @@
});
},
}
}).mount('#app')
}).mount('#app');
</script>

View file

@ -230,6 +230,8 @@
<i class="icon-moon">.icon-moon</i>
<i class="icon-trash">.icon-trash</i>
<i class="icon-blind">.icon-blind</i>
<i class="icon-left-open">.icon-left-open</i>
<i class="icon-right-open">.icon-right-open</i>
<h2 id="listes">Les listes</h2>
<div class="grid grid-cols-1 md:grid-cols-2 list">

View file

@ -40,12 +40,12 @@
<div class="grid grid-cols-1 md:grid-cols-2 list">
<div class="item" v-if="!loading" v-for="item in items">
<span class="title">
{{ item.artists_sort}} - {{ item.title }}
<a :href="'/ma-collection/' + item._id">{{ item.artists_sort}} - {{ item.title }}</a>
<i class="icon-trash" @click="showConfirmDelete(item._id)"></i>
</span>
<div class="grid grid-cols-2 md:grid-cols-4">
<div>
<img :src="item.thumb" :alt="item.title" />
<a :href="'/ma-collection/' + item._id"><img :src="item.thumb" :alt="item.title" /></a>
</div>
<div class="md:col-span-3">
<span><strong>Année :</strong> {{ item.year }}</span>
@ -175,7 +175,6 @@
this.fetch();
},
changeSort() {
console.log('TEST:', this.sortOrder);
const [sort,order] = this.sortOrder.split('-');
this.sort = sort;
this.order = order;
@ -208,5 +207,5 @@
});
}
}
}).mount('#app')
}).mount('#app');
</script>

View file

@ -0,0 +1,282 @@
<main class="layout-maxed ma-collection-details" id="app" v-cloak @keyup="changeImage">
<h1>{{item.artists_sort}} - {{item.title}}</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.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>
</main>
<script>
Vue.createApp({
data() {
return {
item: <%- JSON.stringify(page.item) %>,
tracklist: [],
identifiers: [],
modalIsVisible: false,
identifiersMode: 'preview',
identifiersPreviewLength: 16,
preview: null,
index: null,
}
},
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' });
},
},
}).mount('#app');
</script>

View file

@ -0,0 +1,68 @@
<main class="layout-maxed ma-collection-exporter" id="app">
<h1>Exporter ma collection</h1>
<p>
Les formats CSV et Excel sont facilement lisiblent par un humain. Dans ces 2 formats vous trouverez seulement les informations principales de vos albums, à savoir :
</p>
<ul>
<li>Nom de l'artiste</li>
<li>Nom de l'album</li>
<li>Liste des genres</li>
<li>Liste des styles</li>
<li>Pays (ou région) de distribution</li>
<li>Année de sortie</li>
<li>Date de sortie</li>
<li>Format de l'album</li>
</ul>
<p>
Le format XML quand a lui est un peu moins lisible par un humain, même s'il reste un fichier texte. Dans ce format vous retrouverez toute les informations de vos albums.
</p>
<p>
Enfin le dernier format, MusicTopus, vous permettra d'exporter votre collection afin de l'importer ensuite sur une autre instance MusicTopus.
</p>
<form @submit="exportCollection">
<strong>Choisir le format d'export</strong>
<div class="field inline">
<input type="radio" name="format" v-model="format" value="csv" id="csv">
<label for="csv">CSV</label>
</div>
<div class="field inline">
<input type="radio" name="format" v-model="format" value="xls" id="xls">
<label for="xls">Excel</label>
</div>
<div class="field inline">
<input type="radio" name="format" v-model="format" value="xml" id="xml">
<label for="xml">XML</label>
</div>
<div class="field inline">
<input type="radio" name="format" v-model="format" value="musictopus" id="musictopus">
<label for="musictopus">MusicTopus</label>
</div>
<button type="submit" class="button is-primary my-16">
<i class="icon-export"></i>
Exporter
</button>
</form>
</main>
<script>
Vue.createApp({
data() {
return {
format: 'xml',
}
},
created() {
},
destroyed() {
},
methods: {
exportCollection(event) {
event.preventDefault();
window.open(`/api/v1/albums?exportFormat=${this.format}`, '_blank');
}
},
}).mount('#app');
</script>