@@ -18,6 +18,8 @@ | |||||
"babel-eslint": "^10.1.0", | "babel-eslint": "^10.1.0", | ||||
"eslint": "^6.7.2", | "eslint": "^6.7.2", | ||||
"eslint-plugin-vue": "^6.2.2", | "eslint-plugin-vue": "^6.2.2", | ||||
"fs": "^0.0.1-security", | |||||
"jsmediatags": "^3.9.3", | |||||
"vue-template-compiler": "^2.6.11" | "vue-template-compiler": "^2.6.11" | ||||
}, | }, | ||||
"eslintConfig": { | "eslintConfig": { | ||||
@@ -0,0 +1,98 @@ | |||||
const jsmediatags = require('jsmediatags'); | |||||
const fs = require('fs'); | |||||
const INPUT = './public/audio/'; | |||||
const OUTPUT = 'src/data.json'; | |||||
const data = {"albums" : []}; | |||||
const promises = []; | |||||
try { | |||||
if (fs.existsSync(INPUT)) { | |||||
//file exists | |||||
} | |||||
else { | |||||
console.log("\n============== Weband Error ====================\n\n"); | |||||
console.log("Audio files are missing. Please run first : \n\n$ ./scripts/weband-init.sh <input_directory> \n"); | |||||
console.log("\n================================================\n\n"); | |||||
process.exit(1); | |||||
} | |||||
} catch(err) { | |||||
console.log(err); | |||||
process.exit(1); | |||||
} | |||||
function is_dir(path) { | |||||
try { | |||||
var stat = fs.lstatSync(path); | |||||
return stat.isDirectory(); | |||||
} catch (e) { | |||||
// lstatSync throws an error if path doesn't exist | |||||
return false; | |||||
} | |||||
} | |||||
function id3ToJSON(path){ | |||||
fs.readdirSync(path).forEach(file => { | |||||
let isDir = is_dir(path + file); | |||||
if(isDir) | |||||
id3ToJSON(path + file + '/'); | |||||
else { | |||||
let filePath = path + file; | |||||
promises.push(new Promise((resolve, reject) => { | |||||
new jsmediatags.Reader(filePath) | |||||
.read({ | |||||
onSuccess: (tag) => { | |||||
var tags = tag.tags; | |||||
if(!data.artist) | |||||
data.artist = tags.artist; | |||||
let album = getAlbum(tags.album); | |||||
if(!album){ | |||||
album = {"title": tags.album, "tracks": [], "year": tags.year} | |||||
data.albums.push(album); | |||||
} | |||||
let track = {"title": tags.title, "file" : filePath.replace(INPUT,'audio/')}; | |||||
album.tracks.push(track); | |||||
resolve(tag); | |||||
}, | |||||
onError: (error) => { | |||||
console.log('Error'); | |||||
console.log(error); | |||||
reject(error); | |||||
} | |||||
}); | |||||
})); | |||||
} | |||||
}); | |||||
} | |||||
function getAlbum(albumTitle){ | |||||
for(let i = 0 ; i < data.albums.length; i++){ | |||||
if(data.albums[i].title === albumTitle) | |||||
return data.albums[i]; | |||||
} | |||||
return null; | |||||
} | |||||
id3ToJSON(INPUT); | |||||
Promise.all(promises).then((values) => { | |||||
var jsonContent = JSON.stringify(data, null, 2); | |||||
console.log(jsonContent); | |||||
fs.writeFile(OUTPUT, jsonContent, 'utf8', function (err) { | |||||
if (err) { | |||||
console.log("An error occured while writing JSON Object to File."); | |||||
return console.log(err); | |||||
} | |||||
console.log("JSON file has been saved : " + OUTPUT); | |||||
}); | |||||
}); |
@@ -0,0 +1,85 @@ | |||||
#!/bin/bash | |||||
DIRECTORY=$(cd `dirname $0` && pwd) | |||||
IMAGES_DIRECTORY=$DIRECTORY'/../src/assets/images/' | |||||
AUDIOS_DIRECTORY=$DIRECTORY'/../public/audio/' | |||||
ICONO_HEADER='icono_1.png' | |||||
ICONO_FOOTER='icono_2.png' | |||||
display_usage(){ | |||||
echo "" | |||||
echo " webbandd script" | |||||
echo "" | |||||
echo " usage : webbandd.sh <input_directory>" | |||||
echo "" | |||||
echo " <input_directory> must contains :" | |||||
echo " - two image files : icono_1.png & icono_2.png" | |||||
echo " - one folder per album with mp3 and/or wav audio files" | |||||
echo "" | |||||
} | |||||
error(){ | |||||
echo "" | |||||
echo " Weband ERROR :" | |||||
echo "" | |||||
echo " "$1 | |||||
echo "" | |||||
} | |||||
# 1 argument required | |||||
if [ $# -ne 1 ] | |||||
then | |||||
display_usage | |||||
exit 1 | |||||
fi | |||||
# check_image(){ | |||||
# if [[ -e $1'.svg' || -e $1'.png' || -e $1'.jpg' ]] | |||||
# then | |||||
# return 0 | |||||
# else | |||||
# error $1' image file is missing !' | |||||
# exit -1 | |||||
# fi | |||||
# } | |||||
check_image(){ | |||||
if [ -e $1 ] | |||||
then | |||||
return 0 | |||||
else | |||||
error $1' image file is missing !' | |||||
exit -1 | |||||
fi | |||||
} | |||||
check_image $1'/'$ICONO_HEADER | |||||
echo " => "$1'/'$ICONO_HEADER" image exists - OK " | |||||
check_image $1'/'$ICONO_FOOTER | |||||
echo " => "$1'/'$ICONO_FOOTER" image exists - OK " | |||||
#copy images (cover and contact) | |||||
cp $1'/'$ICONO_HEADER $IMAGES_DIRECTORY | |||||
cp $1'/'$ICONO_FOOTER $IMAGES_DIRECTORY | |||||
if [ -d $AUDIOS_DIRECTORY ] | |||||
then | |||||
rm -rf $AUDIOS_DIRECTORY | |||||
fi | |||||
mkdir $AUDIOS_DIRECTORY | |||||
for d in `find $1/* -type d` | |||||
do | |||||
echo ' copying audio directory "'$d'"' | |||||
cp -r $d $AUDIOS_DIRECTORY | |||||
done | |||||
echo " => audio files copy - OK " | |||||
node $DIRECTORY'/weband-id3-to-json.js' |
@@ -1,28 +1,38 @@ | |||||
<template> | <template> | ||||
<div id="app"> | <div id="app"> | ||||
<img alt="Vue logo" src="./assets/logo.png"> | |||||
<HelloWorld msg="Welcome to Your Vue.js App"/> | |||||
<Weband/> | |||||
</div> | </div> | ||||
</template> | </template> | ||||
<script> | <script> | ||||
import HelloWorld from './components/HelloWorld.vue' | |||||
import Weband from './components/Weband.vue' | |||||
export default { | export default { | ||||
name: 'App', | name: 'App', | ||||
components: { | components: { | ||||
HelloWorld | |||||
Weband | |||||
} | } | ||||
} | } | ||||
</script> | </script> | ||||
<style> | <style> | ||||
#app { | |||||
font-family: Avenir, Helvetica, Arial, sans-serif; | |||||
-webkit-font-smoothing: antialiased; | |||||
-moz-osx-font-smoothing: grayscale; | |||||
text-align: center; | |||||
color: #2c3e50; | |||||
margin-top: 60px; | |||||
@import './assets/css/_variables.css'; | |||||
*{ | |||||
margin :0; | |||||
padding:0; | |||||
} | |||||
body{ | |||||
font-family: var(--font-family); | |||||
font-size: 2rem; | |||||
letter-spacing: 0.1rem; | |||||
} | |||||
body, html, #app { | |||||
margin :0; | |||||
padding:0; | |||||
} | } | ||||
</style> | </style> |
@@ -0,0 +1,10 @@ | |||||
@font-face { | |||||
font-family: "work-sans"; | |||||
src: url('../fonts/work-sans/WorkSans-Regular.otf'); | |||||
} | |||||
:root{ | |||||
--font-family : 'work-sans'; | |||||
--pretty-margin: 0.5rem; | |||||
--main-color: black; | |||||
--secondary-color: black; | |||||
} |
@@ -1,58 +0,0 @@ | |||||
<template> | |||||
<div class="hello"> | |||||
<h1>{{ msg }}</h1> | |||||
<p> | |||||
For a guide and recipes on how to configure / customize this project,<br> | |||||
check out the | |||||
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>. | |||||
</p> | |||||
<h3>Installed CLI Plugins</h3> | |||||
<ul> | |||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li> | |||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li> | |||||
</ul> | |||||
<h3>Essential Links</h3> | |||||
<ul> | |||||
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li> | |||||
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li> | |||||
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li> | |||||
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li> | |||||
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li> | |||||
</ul> | |||||
<h3>Ecosystem</h3> | |||||
<ul> | |||||
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li> | |||||
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li> | |||||
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li> | |||||
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li> | |||||
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li> | |||||
</ul> | |||||
</div> | |||||
</template> | |||||
<script> | |||||
export default { | |||||
name: 'HelloWorld', | |||||
props: { | |||||
msg: String | |||||
} | |||||
} | |||||
</script> | |||||
<!-- Add "scoped" attribute to limit CSS to this component only --> | |||||
<style scoped> | |||||
h3 { | |||||
margin: 40px 0 0; | |||||
} | |||||
ul { | |||||
list-style-type: none; | |||||
padding: 0; | |||||
} | |||||
li { | |||||
display: inline-block; | |||||
margin: 0 10px; | |||||
} | |||||
a { | |||||
color: #42b983; | |||||
} | |||||
</style> |
@@ -0,0 +1,374 @@ | |||||
<template> | |||||
<div v-if="!collapsed" class="player"> | |||||
<div class="progress-wrap"> | |||||
<div class="time-info"> | |||||
{{audio ? formatDuration(audio.currentTime) : "00:00"}} | |||||
</div> | |||||
<progress :value="audioPosition" :max="audio ? Math.floor(audio.duration): 0"></progress> | |||||
<div class="time-info"> | |||||
{{audio ? formatDuration(audio.duration) : "00:00"}} | |||||
</div> | |||||
</div> | |||||
<h3>{{album.title}}</h3> | |||||
<ul> | |||||
<li | |||||
v-for="(track, index) in album.tracks" | |||||
v-on:click="trackClicked('track-'+index)" | |||||
v-bind:key="index+'-'+track.title" | |||||
v-bind:class="{ active: audio && audio.getAttribute('id') === 'track-'+index }"> | |||||
<span class="track-number">{{index + 1}}</span> | |||||
<span class="track-title">{{track.title.trim()}}</span> | |||||
<audio v-on:timeupdate="updateAudioPosition()" v-bind:src="track.file" v-bind:id="'track-'+ index"></audio> | |||||
</li> | |||||
</ul> | |||||
<div class="button-wrap"> | |||||
<img v-if="playing" v-on:click="pause()" src="../assets/images/pause.png" id="play-button"> | |||||
<img v-else v-on:click="play()" src="../assets/images/play.png" id="play-button"> | |||||
</div> | |||||
<div class="player-switch opened" v-on:click="toggle()"></div> | |||||
</div> | |||||
<div v-else class="player-switch" v-on:click="toggle()"> | |||||
</div> | |||||
</template> | |||||
<script> | |||||
export default { | |||||
name: 'Player', | |||||
props: { | |||||
album: Object, | |||||
}, | |||||
data: function () { | |||||
return { | |||||
switcher : null, | |||||
collapsed: true, | |||||
playing: false, | |||||
audioPosition: 0, | |||||
audio : null, | |||||
startTimeInfo: "00:00", | |||||
endTimeInfo: "00:00", | |||||
playerImage: '../assets/images/play.png' | |||||
} | |||||
}, | |||||
updated() { | |||||
//this.bindAudioTags(); | |||||
}, | |||||
mounted(){ | |||||
this.switcher = document.getElementsByClassName('player-switch')[0]; | |||||
document.body.append(this.switcher); | |||||
// this.currentAudio = null; | |||||
// this.playing = false; | |||||
// this.playerContainer = document.createElement("div"); | |||||
// this.container = document.querySelector('#player') | |||||
// this.playerContainer.classList.add('dd-player'); | |||||
// this.switcher = document.createElement("div"); | |||||
// this.switcher.classList.add('dd-player-switch'); | |||||
// this.playerContainer.classList.add('collapsed'); | |||||
// document.body.appendChild(this.switcher); | |||||
// | |||||
// this.switcher.addEventListener('click', () => { | |||||
// this.playerContainer.classList.toggle('collapsed'); | |||||
// this.switcher.classList.toggle('opened'); | |||||
// }); | |||||
// | |||||
// | |||||
// this.addProgressBar(); | |||||
// this.bindAudioTags(); | |||||
// this.addPlayButton(); | |||||
// | |||||
// let wrap = document.createElement("div"); | |||||
// wrap.setAttribute('id', 'wrap-playlist') | |||||
// this.container.parentElement.appendChild(this.playerContainer); | |||||
// this.playerContainer.appendChild(wrap); | |||||
// wrap.appendChild(this.container); | |||||
}, | |||||
methods: { | |||||
toggle : function(){ | |||||
// this.playerContainer.classList.toggle('collapsed'); | |||||
this.collapsed = !this.collapsed; | |||||
this.switcher.classList.toggle('opened'); | |||||
}, | |||||
play: function(){ | |||||
if(!this.audio) | |||||
this.audio = document.querySelectorAll('audio')[0]; | |||||
this.playing = true; | |||||
this.audio.play(); | |||||
// if(this.playing){ | |||||
// this.audio.play(); | |||||
// // this.currentAudio.parentElement.classList.add('playing'); | |||||
// // self.progressBar.setAttribute('max', Math.floor(self.currentAudio.duration)); | |||||
// // self.endTimeInfo.innerHTML = self.formatDuration(self.currentAudio.duration); | |||||
// // this.playButton.setAttribute('src','./images/pause.png'); | |||||
// } | |||||
// else{ | |||||
// this.audio.pause(); | |||||
// // self.currentAudio.parentElement.classList.remove('playing'); | |||||
// // this.playButton.setAttribute('src','./images/play.png'); | |||||
// } | |||||
}, | |||||
pause: function(){ | |||||
this.playing = false; | |||||
this.audio.pause(); | |||||
}, | |||||
trackClicked: function(audioId){ | |||||
//let track = document.getElementById(audioId); | |||||
if(this.playing){ | |||||
this.pause(); | |||||
this.audio = document.getElementById(audioId); | |||||
} | |||||
else{ | |||||
this.audio = document.getElementById(audioId); | |||||
} | |||||
this.playing = true; | |||||
this.audio.play(); | |||||
}, | |||||
updateAudioPosition: function(){ | |||||
this.audioPosition = Math.floor(this.audio.currentTime); | |||||
}, | |||||
// addProgressBar: function(){ | |||||
// this.progressBar = document.createElement("progress"); | |||||
// this.progressBar.setAttribute('value', 0); | |||||
// this.startTimeInfo = document.createElement('div'); | |||||
// this.endTimeInfo = document.createElement('div'); | |||||
// let progressWrap = document.createElement("div"); | |||||
// this.startTimeInfo.innerHTML = "00:00"; | |||||
// this.endTimeInfo.innerHTML = "00:00"; | |||||
// progressWrap.appendChild(this.startTimeInfo); | |||||
// progressWrap.appendChild(this.progressBar); | |||||
// progressWrap.appendChild(this.endTimeInfo); | |||||
// this.startTimeInfo.classList.add('time-info'); | |||||
// this.endTimeInfo.classList.add('time-info'); | |||||
// progressWrap.classList.add('progress-wrap'); | |||||
// this.playerContainer.append(progressWrap); | |||||
// let self = this; | |||||
// this.progressBar.addEventListener('click', (e) => { | |||||
// if(self.currentAudio){ | |||||
// self.currentAudio.currentTime = Math.floor(((e.layerX - self.progressBar.offsetLeft) * self.currentAudio.duration) / self.progressBar.offsetWidth); | |||||
// self.progressBar.value = Math.floor(self.currentAudio.currentTime ); | |||||
// } | |||||
// }); | |||||
// | |||||
// }, | |||||
// addPlayButton: function(){ | |||||
// this.playButton = document.createElement("img"); | |||||
// this.playButton.setAttribute('src','./images/play.png'); | |||||
// this.playButton.setAttribute('id','play-button'); | |||||
// let wrap = document.createElement("div"); | |||||
// wrap.append(this.playButton); | |||||
// this.container.append(wrap); | |||||
// let self = this; | |||||
// this.playButton.addEventListener('click', () => { | |||||
// self.playing = !self.playing; | |||||
// if(self.playing){ | |||||
// self.currentAudio.play(); | |||||
// self.currentAudio.parentElement.classList.add('playing'); | |||||
// self.progressBar.setAttribute('max', Math.floor(self.currentAudio.duration)); | |||||
// self.endTimeInfo.innerHTML = self.formatDuration(self.currentAudio.duration); | |||||
// this.playButton.setAttribute('src','./images/pause.png'); | |||||
// } | |||||
// else{ | |||||
// self.currentAudio.pause(); | |||||
// self.currentAudio.parentElement.classList.remove('playing'); | |||||
// this.playButton.setAttribute('src','./images/play.png'); | |||||
// } | |||||
// }) | |||||
// }, | |||||
// bindAudioTags: function(){ | |||||
// let liTags = this.container.querySelectorAll('li') | |||||
// let self = this; | |||||
// let i = 0; | |||||
// liTags.forEach(function(itemElement){ | |||||
// let audioTag = itemElement.querySelector('audio') | |||||
// if(audioTag){ | |||||
// audioTag.addEventListener('timeupdate', () => { | |||||
// self.audioTimeUpdate(audioTag); | |||||
// }); | |||||
// audioTag.addEventListener('ended', () => { | |||||
// self.audioEnded(i); | |||||
// }) | |||||
// | |||||
// //itemElement.appendChild(audioElement); | |||||
// audioTag.setAttribute('id','track-'+i); | |||||
// if(i === 0) | |||||
// self.currentAudio = audioTag; | |||||
// itemElement.addEventListener('click', () => { | |||||
// let items = self.container.getElementsByTagName('li'); | |||||
// for(let i = 0; i < items.length; i++){ | |||||
// items[i].classList.remove('playing'); | |||||
// } | |||||
// if(self.currentAudio) | |||||
// self.currentAudio.pause(); | |||||
// audioTag.play(); | |||||
// self.playButton.setAttribute('src','./images/pause.png'); | |||||
// self.playing = true; | |||||
// itemElement.classList.add('playing'); | |||||
// self.currentAudio = audioTag; | |||||
// self.progressBar.setAttribute('max', Math.floor(self.currentAudio.duration)); | |||||
// self.endTimeInfo.innerHTML = self.formatDuration(self.currentAudio.duration); | |||||
// self.progressBar.setAttribute('value', 0); | |||||
// }); | |||||
// | |||||
// i++; | |||||
// } | |||||
// }); | |||||
// }, | |||||
// audioTimeUpdate: function(audioElt){ | |||||
// this.progressBar.value = Math.floor(audioElt.currentTime); | |||||
// this.startTimeInfo.innerHTML = this.formatDuration(audioElt.currentTime); | |||||
// }, | |||||
// | |||||
// audioEnded: function(n){ | |||||
// let audios = document.getElementsByTagName('audio'); | |||||
// let next = n == audios.length - 1 ? 0 : n + 1; | |||||
// this.currentAudio.pause(); | |||||
// this.currentAudio.currentTime = 0; | |||||
// this.currentAudio = document.getElementsByTagName('audio')[next]; | |||||
// this.currentAudio.parentElement.click(); | |||||
// }, | |||||
formatDuration: function(time){ | |||||
let s = parseInt(time% 60); | |||||
let m = parseInt((time / 60) % 60); | |||||
return (m < 10 ? ('0'+m) : m) + ':' + (s < 10 ? ('0'+s) : s); | |||||
} | |||||
} | |||||
} | |||||
</script> | |||||
<style> | |||||
*{ | |||||
--one-dpi: 72px; | |||||
--dd-blue: rgb(0,42,255); | |||||
} | |||||
.player{ | |||||
width: 25vw; | |||||
height: 100vh; | |||||
position:fixed; | |||||
top: 0px; | |||||
background-color: white; | |||||
right:0px; | |||||
color: black; | |||||
padding-top: var(--one-dpi); | |||||
padding-bottom: var(--one-dpi); | |||||
display: flex; | |||||
flex-direction: column; | |||||
/* justify-content: space-between; */ | |||||
} | |||||
.collapsed{ | |||||
display: none; | |||||
} | |||||
.player-switch{ | |||||
position :fixed; | |||||
bottom: 0; | |||||
right: 0; | |||||
width: var(--one-dpi); | |||||
height:var(--one-dpi); | |||||
background-color: white; | |||||
cursor: pointer; | |||||
z-index:10; | |||||
} | |||||
.player-switch.opened{ | |||||
background-color: var(--dd-blue); | |||||
} | |||||
li.active{ | |||||
font-weight: bold; | |||||
} | |||||
.player h3 { | |||||
font-size: 1rem; | |||||
margin: calc(var(--one-dpi) / 2); | |||||
} | |||||
.player ul { | |||||
margin-left : calc(var(--one-dpi) / 2); | |||||
color: var(--dd-blue); | |||||
font-size: 1.5rem; | |||||
list-style-type : none; | |||||
} | |||||
/* | |||||
.dd-player ul li img{ | |||||
width:24px; | |||||
height:24px; | |||||
margin-right: 12px; | |||||
} | |||||
.playing{ | |||||
font-weight: bold; | |||||
color : black; | |||||
} | |||||
*/ | |||||
.progress-wrap{ | |||||
display:flex; | |||||
width: 100%; | |||||
justify-content: space-around; | |||||
} | |||||
.progress-wrap .time-info{ | |||||
font-size:0.66rem; | |||||
display: flex; | |||||
justify-content: center; | |||||
} | |||||
progress{ | |||||
display: inline; | |||||
height: 10px; | |||||
width:66%; | |||||
} | |||||
/* | |||||
#play-button{ | |||||
max-width: calc(var(--one-dpi) / 2); | |||||
max-height: calc(var(--one-dpi) / 2); | |||||
margin: calc(var(--one-dpi) / 2); | |||||
} | |||||
*/ | |||||
progress::-moz-progress-bar{ | |||||
background-color: black; | |||||
} | |||||
progress{ | |||||
background-color: #rgba(200,200,200,0.5); | |||||
} | |||||
.button-wrap{ | |||||
margin-top: 100px; | |||||
} | |||||
/* | |||||
.dd-player ul li, #play-button{ | |||||
cursor : pointer; | |||||
} | |||||
#wrap-playlist{ | |||||
flex: 1; | |||||
} | |||||
*/ | |||||
span.track-number{ | |||||
width: 25px; | |||||
display: inline-block; | |||||
} | |||||
span.track-title:before{ | |||||
content: " - "; | |||||
} | |||||
</style> |
@@ -0,0 +1,149 @@ | |||||
<template> | |||||
<div class="weband"> | |||||
<section class="cover"> | |||||
</section> | |||||
<section class="albums"> | |||||
<h2>{{this.artist}} | Albums</h2> | |||||
<ul> | |||||
<li v-for="album in albums" v-bind:key="album.title" v-on:click="albumSelected(album)"> | |||||
{{album.title}} | {{album.year}} | |||||
</li> | |||||
</ul> | |||||
</section> | |||||
<section class="icono-2"> | |||||
</section> | |||||
<section class="contact"> | |||||
<span>contact<span class="point">@</span>{{this.artist.toLowerCase()}}<span class="point">.</span>space</span> | |||||
<footer class="flex-center"> | |||||
dede<span class='point'>.</span>space<span class='pipe'>|</span>{{new Date().getFullYear()}} | |||||
</footer> | |||||
</section> | |||||
<Player v-bind:album="currentAlbum"/> | |||||
</div> | |||||
</template> | |||||
<script> | |||||
import Player from './Player.vue' | |||||
import * as data from '../data.json'; | |||||
export default { | |||||
name: 'Weband', | |||||
props: { | |||||
msg: String | |||||
}, | |||||
components: { | |||||
Player | |||||
}, | |||||
data: function () { | |||||
return { | |||||
artist: data.artist, | |||||
albums: data.albums, | |||||
currentAlbum: data.albums[0] | |||||
} | |||||
}, | |||||
methods: { | |||||
albumSelected: function(album){ | |||||
this.currentAlbum = album; | |||||
} | |||||
} | |||||
} | |||||
</script> | |||||
<style scoped> | |||||
@import '../assets/css/_variables.css'; | |||||
.point { | |||||
margin: 0px var(--pretty-margin); | |||||
} | |||||
.pipe { | |||||
margin: 0px calc(3 * var(--pretty-margin)); | |||||
} | |||||
section{ | |||||
height: 100vh; | |||||
} | |||||
section h2 { | |||||
font-size: 2rem; | |||||
} | |||||
section:nth-of-type(odd){ | |||||
background-color: white; | |||||
color: var(--secondary-color); | |||||
} | |||||
section:nth-of-type(even){ | |||||
background-color: var(--secondary-color); | |||||
color: white; | |||||
} | |||||
section.cover{ | |||||
background : url(../assets/images/icono_1.png) no-repeat center center; | |||||
background-color: var(--main-color); | |||||
} | |||||
section.albums{ | |||||
background-color: black; | |||||
color:white; | |||||
display: flex; | |||||
flex-direction: column; | |||||
justify-content: center; | |||||
line-height: 200%; | |||||
} | |||||
section.albums > * { | |||||
padding-left: 10vw; | |||||
} | |||||
section.albums h2 { | |||||
padding-left: 20vw; | |||||
font-weight: normal; | |||||
} | |||||
section.albums ul { | |||||
list-style-type: none; | |||||
} | |||||
section.icono-2{ | |||||
background : url(../assets/images/icono_2.png) no-repeat center center; | |||||
background-color: var(--secondary-color); | |||||
} | |||||
section.contact{ | |||||
display : flex; | |||||
flex-direction: column; | |||||
justify-content: center; | |||||
align-items: center; | |||||
position :relative; | |||||
/* background : url(../assets/images/contact.png) no-repeat center center; */ | |||||
background-color: var(--main-color); | |||||
/*color:white; */ | |||||
} | |||||
footer{ | |||||
font-size: 0.92rem; | |||||
position: absolute; | |||||
width: 100%; | |||||
bottom: 0; | |||||
text-align: center; | |||||
} | |||||
.hidden{ | |||||
display: none; | |||||
} | |||||
</style> |
@@ -0,0 +1,36 @@ | |||||
{ | |||||
"albums" : [ | |||||
{ | |||||
"title" : "Album 1", | |||||
"date" : "2019", | |||||
"tracks" : [ | |||||
{ | |||||
"file" : "audio/album_1/01.mp3", | |||||
"title" : "Track 1" | |||||
}, | |||||
{ | |||||
"file" : "audio/album_1/02.mp3", | |||||
"title" : "Track 2" | |||||
}, | |||||
{ | |||||
"file" : "audio/album_1/03.mp3", | |||||
"title" : "Track 3" | |||||
} | |||||
] | |||||
}, | |||||
{ | |||||
"title" : "Album 2", | |||||
"date" : "2020", | |||||
"tracks" : [ | |||||
{ | |||||
"file" : "audio/album_2/04.mp3", | |||||
"title" : "Track X" | |||||
}, | |||||
{ | |||||
"file" : "audio/album_2/05.mp3", | |||||
"title" : "Track Y" | |||||
} | |||||
] | |||||
} | |||||
] | |||||
} |
@@ -3729,6 +3729,11 @@ fs.realpath@^1.0.0: | |||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" | ||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= | ||||
fs@^0.0.1-security: | |||||
version "0.0.1-security" | |||||
resolved "https://registry.yarnpkg.com/fs/-/fs-0.0.1-security.tgz#8a7bd37186b6dddf3813f23858b57ecaaf5e41d4" | |||||
integrity sha1-invTcYa23d84E/I4WLV+yq9eQdQ= | |||||
fsevents@^1.2.7: | fsevents@^1.2.7: | ||||
version "1.2.13" | version "1.2.13" | ||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" | ||||
@@ -4699,6 +4704,13 @@ jsesc@~0.5.0: | |||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" | resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" | ||||
integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= | integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= | ||||
jsmediatags@^3.9.3: | |||||
version "3.9.3" | |||||
resolved "https://registry.yarnpkg.com/jsmediatags/-/jsmediatags-3.9.3.tgz#309632d221d701bd385df65c9c6840cb399e11ff" | |||||
integrity sha512-h53yFnPYF1Y5jwr2ebcVzIIsvRpSalm0jhNiJDUztoPPHGpuHxi9YHUzdDgiw+ykiinXHd1s6HSIbudHw79zQw== | |||||
dependencies: | |||||
xhr2 "^0.1.4" | |||||
json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: | json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: | ||||
version "1.0.2" | version "1.0.2" | ||||
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" | resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" | ||||
@@ -8190,6 +8202,11 @@ ws@^6.0.0, ws@^6.2.1: | |||||
dependencies: | dependencies: | ||||
async-limiter "~1.0.0" | async-limiter "~1.0.0" | ||||
xhr2@^0.1.4: | |||||
version "0.1.4" | |||||
resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f" | |||||
integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8= | |||||
xtend@^4.0.0, xtend@~4.0.1: | xtend@^4.0.0, xtend@~4.0.1: | ||||
version "4.0.2" | version "4.0.2" | ||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" | ||||