commit
0d5ee5262b
14 changed files with 362 additions and 248 deletions
15
app.js
15
app.js
|
|
@ -8,7 +8,14 @@ let app = new Vue({
|
|||
show: {
|
||||
popularity_popup: false,
|
||||
popularity_hover: false,
|
||||
follower_hover: false
|
||||
follower_hover: false,
|
||||
modal_content: false,
|
||||
modal: {
|
||||
popularity: false,
|
||||
track: false,
|
||||
artist: false,
|
||||
playlist_export: false,
|
||||
}
|
||||
},
|
||||
error: {
|
||||
main: ``,
|
||||
|
|
@ -67,5 +74,11 @@ let app = new Vue({
|
|||
})
|
||||
},
|
||||
get_data: fetch_data,
|
||||
hide_modal: function () {
|
||||
this.show.modal.popularity = false;
|
||||
this.show.modal.track = false;
|
||||
this.show.modal.artist = false;
|
||||
this.show.modal.playlist_export = false;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,19 +1,17 @@
|
|||
<div class="artist">
|
||||
<div class="image profile_pic" v-if="artist.image">
|
||||
<img :src="artist.image.url" :alt="artist.name + 's profile picture'">
|
||||
</div>
|
||||
<div class="image profile_pic" v-else>
|
||||
<div class="missing-circle">
|
||||
<div class="card">
|
||||
<div class="image">
|
||||
<img v-if="artist.image" :src="artist.image.url" :alt="artist.name + 's profile picture'" target="_blank" rel="noopener">
|
||||
<div class="missing-image" v-else>
|
||||
<music-note colour="#1DB954"></music-note>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info">
|
||||
<span class="name">
|
||||
<span class="title">
|
||||
<a :href="artist.link" target="_blank" rel="noopener">{{artist.name}}</a>
|
||||
</span>
|
||||
<br>
|
||||
<span class="genres">{{artist.genres.join(", ")}}</span>
|
||||
<span class="subtitle">{{genres}}</span>
|
||||
</div>
|
||||
<div class="popularity">{{artist.popularity}}</div>
|
||||
<div class="followers">{{artist.follower_count}}</div>
|
||||
<div class="bottom left corner popularity" v-tooltip="popularity_tooltip" @click.self="show_popularity_modal()">{{artist.popularity}}</div>
|
||||
<div class="bottom right corner followers" v-tooltip="followers_tooltip">{{artist.follower_count.toLocaleString()}}</div>
|
||||
</div>
|
||||
|
|
@ -2,25 +2,42 @@ Vue.component(
|
|||
`artist`,
|
||||
{
|
||||
props: [ `artist` ],
|
||||
computed: {},
|
||||
template: `<div class="artist">
|
||||
<div class="image profile_pic" v-if="artist.image">
|
||||
<img :src="artist.image.url" :alt="artist.name + 's profile picture'">
|
||||
</div>
|
||||
<div class="image profile_pic" v-else>
|
||||
<div class="missing-circle">
|
||||
data: function () {
|
||||
return {
|
||||
popularity_tooltip: `Popularity`,
|
||||
followers_tooltip: `Followers`,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
genres: function () {
|
||||
let genres = [];
|
||||
for (var genre of this.artist.genres) {
|
||||
genres.push(genre.toTitleCase());
|
||||
};
|
||||
return genres.join(`, `);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
show_popularity_modal: function () {
|
||||
this.$emit(`popularity_click`)
|
||||
}
|
||||
},
|
||||
template: `<div class="card">
|
||||
<div class="image">
|
||||
<img v-if="artist.image" :src="artist.image.url" :alt="artist.name + 's profile picture'" target="_blank" rel="noopener">
|
||||
<div class="missing-image" v-else>
|
||||
<music-note colour="#1DB954"></music-note>
|
||||
</div>
|
||||
</div>
|
||||
<div class="info">
|
||||
<span class="name">
|
||||
<span class="title">
|
||||
<a :href="artist.link" target="_blank" rel="noopener">{{artist.name}}</a>
|
||||
</span>
|
||||
<br>
|
||||
<span class="genres">{{artist.genres.join(", ")}}</span>
|
||||
<span class="subtitle">{{genres}}</span>
|
||||
</div>
|
||||
<div class="popularity">{{artist.popularity}}</div>
|
||||
<div class="followers">{{artist.follower_count}}</div>
|
||||
<div class="bottom left corner popularity" v-tooltip="popularity_tooltip" @click.self="show_popularity_modal()">{{artist.popularity}}</div>
|
||||
<div class="bottom right corner followers" v-tooltip="followers_tooltip">{{artist.follower_count.toLocaleString()}}</div>
|
||||
</div>`
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
@ -4,4 +4,13 @@ Vue.component(
|
|||
props: [ `colour` ],
|
||||
template: `<svg width="72" height="72" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="24" height="24" fill="none" rx="0" ry="0"></rect><path fill-rule="evenodd" clip-rule="evenodd" d="M17.4911 2.11667L21.4511 4.09667C21.9411 4.34667 22.1411 4.93667 21.8911 5.43667C21.6411 5.93667 21.0411 6.13667 20.5511 5.88667L18.0011 4.61667L17.9911 16.4367C17.9911 16.4467 17.9936 16.4567 17.9961 16.4667C17.9986 16.4767 18.0011 16.4867 18.0011 16.4967C18.0011 18.4267 16.4311 19.9967 14.5011 19.9967C12.5711 19.9967 11.0011 18.4267 11.0011 16.4967C11.0011 14.5667 12.5711 12.9967 14.5011 12.9967C15.0411 12.9967 15.5411 13.1267 16.0011 13.3467L16.0111 3.10667C15.9911 2.99667 16.0011 2.87667 16.0311 2.75667C16.1711 2.14667 16.9411 1.80667 17.4911 2.11667ZM12.8911 5.43664C12.6511 5.93664 12.0511 6.13664 11.5511 5.88664L9.0011 4.61664L8.9911 18.4366C8.9911 18.4466 8.9936 18.4566 8.9961 18.4666C8.9986 18.4766 9.0011 18.4866 9.0011 18.4966C9.0011 20.4266 7.4311 21.9966 5.5011 21.9966C3.5711 21.9966 2.0011 20.4266 2.0011 18.4966C2.0011 16.5666 3.5711 14.9966 5.5011 14.9966C6.0411 14.9966 6.5411 15.1266 7.0011 15.3466L7.0111 3.10664C6.9911 2.99664 7.0011 2.87664 7.0311 2.76664C7.1711 2.14664 7.9411 1.81664 8.4911 2.12664L12.4411 4.09664C12.9411 4.34664 13.1411 4.94664 12.8911 5.43664Z" :fill="colour || '#ffffff'"></path></svg>`
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
|
||||
Vue.component(
|
||||
`close`,
|
||||
{
|
||||
props: [ `colour` ],
|
||||
template: `<svg width="72" height="72" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="24" height="24" fill="none" rx="0" ry="0"></rect><path fill-rule="evenodd" clip-rule="evenodd" d="M13.4049 12.0025L18.6949 6.7125C19.0849 6.3225 19.0849 5.6925 18.6949 5.3025C18.3049 4.9125 17.6749 4.9125 17.2849 5.3025L11.9949 10.5925L6.70494 5.2925C6.31494 4.9025 5.68494 4.9025 5.29494 5.2925C4.90494 5.6825 4.90494 6.3125 5.29494 6.7025L10.5849 12.0025L5.29494 17.2925C4.90494 17.6825 4.90494 18.3125 5.29494 18.7025C5.48494 18.9025 5.73494 19.0025 5.99494 19.0025C6.25494 19.0025 6.50494 18.9025 6.70494 18.7125L11.9949 13.4125L17.2849 18.7025C17.4849 18.9025 17.7349 19.0025 17.9949 19.0025C18.2549 19.0025 18.5049 18.9025 18.7049 18.7125C19.0949 18.3225 19.0949 17.6925 18.7049 17.3025L13.4049 12.0025Z" :fill="colour || '#ffffff'"></path></svg>`
|
||||
}
|
||||
)
|
||||
|
|
@ -1,20 +1,22 @@
|
|||
<div class="track">
|
||||
<div class="cover center">
|
||||
<a :href="track.album.link" target="_blank" rel="noopener">
|
||||
<div class="card">
|
||||
<div class="image">
|
||||
<a v-if="track.album.image.url" :href="track.album.link" target="_blank" rel="noopener">
|
||||
<img :src="track.album.image.url" :alt="track.album.name + ' Cover Image'" class="cover">
|
||||
</a>
|
||||
<a v-else :href="track.album.link" target="_blank" rel="noopener">
|
||||
<div class="missing-image">
|
||||
<music-note colour="#1DB954"></music-note>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="info">
|
||||
<span class="name remote" v-if="!track.locality">
|
||||
<span class="title remote" v-if="!track.locality">
|
||||
<a :href="track.link" target="_blank" rel="noopener">{{track.name}}</a>
|
||||
</span>
|
||||
<span class="name local" v-else>
|
||||
{{track.name}}
|
||||
</span>
|
||||
<br>
|
||||
<span class="artist" v-html="artists"></span>
|
||||
<span class="title local" v-else>{{track.name}}</span>
|
||||
<br>
|
||||
<span class="subtitle" v-html="artists"></span>
|
||||
</div>
|
||||
<div class="popularity" v-tooltip="popularity_tooltip">{{track.popularity}}</div>
|
||||
<div class="duration">{{duration}}</div>
|
||||
<div class="popularity bottom left corner" v-tooltip="popularity_tooltip" @click.self="show_popularity_modal()">{{track.popularity}}</div>
|
||||
<div class="duration bottom right corner">{{duration}}</div>
|
||||
</div>
|
||||
|
|
@ -7,26 +7,6 @@ Vue.component(
|
|||
popularity_tooltip: `Popularity`
|
||||
}
|
||||
},
|
||||
template: `<div class="track">
|
||||
<div class="cover center">
|
||||
<a :href="track.album.link" target="_blank" rel="noopener">
|
||||
<img :src="track.album.image.url" :alt="track.album.name + ' Cover Image'" class="cover">
|
||||
</a>
|
||||
</div>
|
||||
<div class="info">
|
||||
<span class="name remote" v-if="!track.locality">
|
||||
<a :href="track.link" target="_blank" rel="noopener">{{track.name}}</a>
|
||||
</span>
|
||||
<span class="name local" v-else>
|
||||
{{track.name}}
|
||||
</span>
|
||||
<br>
|
||||
<span class="artist" v-html="artists"></span>
|
||||
<br>
|
||||
</div>
|
||||
<div class="popularity" v-tooltip="popularity_tooltip">{{track.popularity}}</div>
|
||||
<div class="duration">{{duration}}</div>
|
||||
</div>`,
|
||||
computed: {
|
||||
duration: function () {
|
||||
let timestamp = ``;
|
||||
|
|
@ -58,6 +38,33 @@ Vue.component(
|
|||
}
|
||||
return artists.join(`, `)
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
show_popularity_modal: function () {
|
||||
this.$emit('popularity_click')
|
||||
}
|
||||
},
|
||||
template: `<div class="card">
|
||||
<div class="image">
|
||||
<a v-if="track.album.image.url" :href="track.album.link" target="_blank" rel="noopener">
|
||||
<img :src="track.album.image.url" :alt="track.album.name + ' Cover Image'" class="cover">
|
||||
</a>
|
||||
<a v-else :href="track.album.link" target="_blank" rel="noopener">
|
||||
<div class="missing-image">
|
||||
<music-note colour="#1DB954"></music-note>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="info">
|
||||
<span class="title remote" v-if="!track.locality">
|
||||
<a :href="track.link" target="_blank" rel="noopener">{{track.name}}</a>
|
||||
</span>
|
||||
<span class="title local" v-else>{{track.name}}</span>
|
||||
<br>
|
||||
<span class="subtitle" v-html="artists"></span>
|
||||
</div>
|
||||
<div class="popularity bottom left corner" v-tooltip="popularity_tooltip" @click.self="show_popularity_modal()">{{track.popularity}}</div>
|
||||
<div class="duration bottom right corner">{{duration}}</div>
|
||||
</div>`
|
||||
}
|
||||
);
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
div.artist {
|
||||
background-color: var(--card-colour);
|
||||
color: var(--card-text);
|
||||
border-radius: 7px;
|
||||
border-style: none;
|
||||
padding: 10px;
|
||||
padding-top: 20px;
|
||||
margin: 5px auto;
|
||||
width: 90%;
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
div.artist > div.profile_pic {
|
||||
text-align: center;
|
||||
}
|
||||
div.artist > div.profile_pic img {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
div.artist > div.profile_pic > div.missing-circle {
|
||||
background-color: #3a3a3aaa;
|
||||
border-radius: 100px;
|
||||
display: flex;
|
||||
height: 200px;
|
||||
width: 200px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
|
||||
div.artist > div.info {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
div.artist > div.info > span.name {
|
||||
text-decoration: none;
|
||||
color: var(--text-on-card);
|
||||
vertical-align: middle;
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
div.artist > .followers {
|
||||
background-color: var(--on-card-colour);
|
||||
color: var(--on-card-text);
|
||||
vertical-align: middle;
|
||||
position: absolute;
|
||||
padding: 1px 6px;
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
|
||||
/* top-left top-right lower-right lower-left */
|
||||
border-radius: 7px 0 7px 0;
|
||||
}
|
||||
|
||||
div.artist > div.info > span.genres {
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
|
||||
div.artist > .popularity {
|
||||
background-color: var(--on-card-colour);
|
||||
color: var(--on-card-text);
|
||||
position: absolute;
|
||||
padding: 1px 6px;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
|
||||
/* top-left top-right lower-right lower-left */
|
||||
border-radius: 0px 7px 0px 7px;
|
||||
}
|
||||
|
||||
div.artist a {
|
||||
color: var(--text-on-card);
|
||||
text-decoration: none;
|
||||
}
|
||||
div.artist a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
/* DESKTOP STYLES */
|
||||
@media only screen and (min-width: 768px) {
|
||||
div.artist {
|
||||
width: 230px;
|
||||
margin: 5px;
|
||||
}
|
||||
}
|
||||
87
css/card.css
Normal file
87
css/card.css
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
div.card {
|
||||
/* Card only variables */
|
||||
--border-radius: 5px;
|
||||
|
||||
background-color: var(--card-colour);
|
||||
color: var(--card-text);
|
||||
border-radius: var(--border-radius);
|
||||
border-style: none;
|
||||
padding: 10px;
|
||||
padding-top: 20px;
|
||||
margin: 5px auto;
|
||||
width: 90%;
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
div.card > div.image {
|
||||
text-align: center;
|
||||
}
|
||||
div.card > div.image img {
|
||||
--size: 200px;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
}
|
||||
|
||||
div.card div.missing-image {
|
||||
background-color: #3a3a3aaa;
|
||||
justify-content: center;
|
||||
border-radius: 100px;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
height: 200px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
|
||||
div.card > div.info {
|
||||
text-align: center;
|
||||
padding-bottom: 20px;
|
||||
margin: 0;
|
||||
}
|
||||
div.card > div.info > .title { font-size: larger; }
|
||||
div.card > div.info > .subtitle { font-size: smaller; }
|
||||
|
||||
/* Positioning For Absolute Elements */
|
||||
div.card .corner {
|
||||
position: absolute;
|
||||
padding: 1px 6px;
|
||||
background-color: var(--on-card-colour);
|
||||
color: var(--on-card-text);
|
||||
}
|
||||
div.card .right { right: 0; }
|
||||
div.card .left { left: 0; }
|
||||
div.card .top { top: 0; }
|
||||
div.card .bottom { bottom: 0; }
|
||||
|
||||
|
||||
/* border-radius: top-left top-right lower-right lower-left */
|
||||
div.card .popularity {
|
||||
border-radius: 0 var(--border-radius) 0 var(--border-radius);
|
||||
cursor: pointer;
|
||||
}
|
||||
div.card .followers,
|
||||
div.card .duration { border-radius: var(--border-radius) 0 var(--border-radius) 0; }
|
||||
|
||||
|
||||
div.card a {
|
||||
color: var(--text-on-card);
|
||||
text-decoration: none;
|
||||
}
|
||||
div.card a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
/* DESKTOP STYLES */
|
||||
@media only screen and (min-width: 768px) {
|
||||
div.card {
|
||||
width: 230px;
|
||||
margin: 5px;
|
||||
}
|
||||
}
|
||||
56
css/modal.css
Normal file
56
css/modal.css
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
div.modal-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 5;
|
||||
background-color: var(--modal-container-background);
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
div.modal {
|
||||
z-index: 6;
|
||||
width: 90%;
|
||||
max-height: 85%;
|
||||
background-color: var(--modal-background);
|
||||
border-radius: 5px;
|
||||
padding: 0 15px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
div.modal * { color: var(--modal-text); }
|
||||
|
||||
div.modal h2 { margin-top: 30px; }
|
||||
|
||||
div.modal p { padding: 0px 5px 15px 5px; }
|
||||
|
||||
div.modal .close-modal {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
color: var(--spotify-green);
|
||||
}
|
||||
div.modal .close-modal:hover {
|
||||
color: var(--error);
|
||||
transform: scale(1.2, 1.2);
|
||||
transition: ease-in-out;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media only screen and (min-width: 768px) {
|
||||
div.modal {
|
||||
width: 50%;
|
||||
max-height: 75%;
|
||||
}
|
||||
div.modal h2 {
|
||||
margin-top: 19.920px;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
div.track {
|
||||
background-color: var(--card-colour);
|
||||
color: var(--card-text);
|
||||
border-radius: 7px;
|
||||
border-style: none;
|
||||
padding: 10px;
|
||||
padding-top: 20px;
|
||||
margin: 5px auto;
|
||||
width: 90%;
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
div.track > div.cover {
|
||||
text-align: center;
|
||||
}
|
||||
div.track > div.cover img {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
div.track > div.info {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
div.track > div.info > span.name {
|
||||
text-decoration: none;
|
||||
color: var(--text-on-card);
|
||||
vertical-align: middle;
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
div.track > .duration {
|
||||
background-color: var(--on-card-colour);
|
||||
color: var(--on-card-text);
|
||||
vertical-align: middle;
|
||||
position: absolute;
|
||||
padding: 1px 6px;
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
|
||||
/* top-left top-right lower-right lower-left */
|
||||
border-radius: 7px 0 7px 0;
|
||||
}
|
||||
|
||||
div.track > div.info > span.artist {
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
|
||||
div.track > .popularity {
|
||||
background-color: var(--on-card-colour);
|
||||
color: var(--on-card-text);
|
||||
position: absolute;
|
||||
padding: 1px 6px;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
|
||||
/* top-left top-right lower-right lower-left */
|
||||
border-radius: 0px 7px 0px 7px;
|
||||
}
|
||||
|
||||
div.track a {
|
||||
color: var(--text-on-card);
|
||||
text-decoration: none;
|
||||
}
|
||||
div.track a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
/* DESKTOP STYLES */
|
||||
@media only screen and (min-width: 768px) {
|
||||
div.track {
|
||||
width: 230px;
|
||||
margin: 5px;
|
||||
}
|
||||
}
|
||||
62
css/transitions.css
Normal file
62
css/transitions.css
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/* Transition for modal background appearing/disappearing */
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity .5s;
|
||||
}
|
||||
|
||||
.fade-enter, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Transition for modal card appearing disappearing */
|
||||
.burst-enter-active {
|
||||
animation: burst-in .5s;
|
||||
}
|
||||
.burst-leave-active { animation: burst-out .5s; }
|
||||
|
||||
@keyframes burst-in {
|
||||
0% {
|
||||
transform: scale(0);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes burst-out {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
100% {
|
||||
transform: scale(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media only screen and (min-width: 768px) {
|
||||
@keyframes burst-in {
|
||||
0% {
|
||||
transform: scale(0);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.25);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes burst-out {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.25);
|
||||
}
|
||||
100% {
|
||||
transform: scale(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
39
index.html
39
index.html
|
|
@ -8,8 +8,9 @@
|
|||
<!-- Stylesheets -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@800&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link rel="stylesheet" href="./css/track.css">
|
||||
<link rel="stylesheet" href="./css/artist.css">
|
||||
<link rel="stylesheet" href="./css/card.css">
|
||||
<link rel="stylesheet" href="./css/modal.css">
|
||||
<link rel="stylesheet" href="./css/transitions.css">
|
||||
|
||||
<!-- Javascript Imports -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
|
||||
|
|
@ -19,6 +20,7 @@
|
|||
<script src="./components/icons.js" defer async></script>
|
||||
<script src="https://unpkg.com/v-tooltip"></script>
|
||||
<script src="./js/text_computation.js"></script>
|
||||
<script src="./js/prototypes.js" async></script>
|
||||
<script src="./app.js" defer></script>
|
||||
<script src="./js/auth.js"></script>
|
||||
<script src="./js/data.js"></script>
|
||||
|
|
@ -26,7 +28,7 @@
|
|||
<body>
|
||||
<div id="app" v-cloak>
|
||||
<div id="login" v-if="!is_authed">
|
||||
<div class="card center">
|
||||
<div class="center">
|
||||
<a :href="spotify_auth_url">
|
||||
<button id="spotify-login">Login With Spotify</button>
|
||||
</a>
|
||||
|
|
@ -59,7 +61,7 @@
|
|||
<input type="number" v-model="count" placeholder="How Many?">
|
||||
</div>
|
||||
<div id="submit-button" v-if="button_type && duration">
|
||||
<button @click="get_data()">Get Top {{count > 1 ? count : ``}} {{button_type}}</button>
|
||||
<button @click="get_data()">Get Top {{count > 1 ? count : `10`}} {{button_type}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-row error" v-if="error.main">{{error.main}}</div>
|
||||
|
|
@ -68,6 +70,7 @@
|
|||
v-for="top_track in data.tracks"
|
||||
:track="top_track"
|
||||
:key="top_track.id"
|
||||
@popularity_click="show.modal.popularity = true"
|
||||
></track-card>
|
||||
</div>
|
||||
<div class="body" v-if="data.artists.length > 0">
|
||||
|
|
@ -75,8 +78,36 @@
|
|||
v-for="top_artist in data.artists"
|
||||
:artist="top_artist"
|
||||
:key="top_artist.id"
|
||||
@popularity_click="show.modal.popularity = true"
|
||||
></artist>
|
||||
</div>
|
||||
|
||||
<!-- Modals Needed -->
|
||||
<transition name="fade" @after-enter="show.modal_content = true">
|
||||
<div
|
||||
v-if="Object.values(this.show.modal).includes(true)"
|
||||
class="modal-container"
|
||||
@click.self="show.modal_content = false"
|
||||
>
|
||||
<transition name="burst" @after-leave="hide_modal">
|
||||
<div v-if="show.modal_content && show.modal.popularity" class="modal">
|
||||
<span @click="show.modal_content = false">
|
||||
<close class="close-modal" colour="#ffffff80" @click="show.modal_content = false"></close>
|
||||
</span>
|
||||
<h2 class="center">How is Popularity Calculated?</h2>
|
||||
<p class="center">
|
||||
Popularity is a value between 0 and 100 that is calculated by Spotify based on how many plays the song/artist has recieved and how recent those plays are.
|
||||
</p>
|
||||
<p class="center">
|
||||
This means that an artist/song that has had 100 plays today will have a higher popularity than a song/artist that has 100 from a month ago.
|
||||
</p>
|
||||
<p class="center">
|
||||
This number is not updated in real time so refreshing the page will not reflect it's absolute accurate value.
|
||||
</p>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
|||
10
js/prototypes.js
vendored
Normal file
10
js/prototypes.js
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
String.prototype.toTitleCase = function () {
|
||||
let words = this.split(` `);
|
||||
let new_words = [];
|
||||
for (var word of words) {
|
||||
new_words.push(
|
||||
`${word[0].toUpperCase()}${word.slice(1).toLowerCase()}`
|
||||
);
|
||||
};
|
||||
return new_words.join(` `);
|
||||
}
|
||||
17
style.css
17
style.css
|
|
@ -17,6 +17,10 @@
|
|||
--on-card-colour: #4c4c4c;
|
||||
--on-card-text: var(--spotify-green);
|
||||
|
||||
--modal-container-background: #0e0f10eb;
|
||||
--modal-background: var(--card-colour);
|
||||
--modal-text: var(--card-text);
|
||||
|
||||
--fonts: 'Open Sans', sans-serif;
|
||||
}
|
||||
|
||||
|
|
@ -49,10 +53,8 @@ select {
|
|||
font-family: var(--fonts);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
select:focus {
|
||||
border-style: none;
|
||||
}
|
||||
select:hover { cursor: pointer; }
|
||||
select:focus { border-style: none; }
|
||||
|
||||
button {
|
||||
padding: 10px 20px;
|
||||
|
|
@ -63,6 +65,7 @@ button {
|
|||
font-family: var(--fonts);
|
||||
outline: none;
|
||||
}
|
||||
button:hover { cursor: pointer; }
|
||||
|
||||
input[type=number] {
|
||||
background-color: var(--spotify-black);
|
||||
|
|
@ -140,7 +143,7 @@ div.body {
|
|||
border-width: 2px;
|
||||
}
|
||||
|
||||
.card {
|
||||
div#login > div {
|
||||
display: inline-block;
|
||||
color: var(--card-text);
|
||||
padding: 20px;
|
||||
|
|
@ -168,7 +171,7 @@ div.body {
|
|||
/* Tooltip Styling */
|
||||
.tooltip {
|
||||
display: none !important;
|
||||
z-index: 10000;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.tooltip .tooltip-inner {
|
||||
|
|
@ -287,7 +290,7 @@ div.body {
|
|||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.card {
|
||||
div#login > div {
|
||||
width: 33%;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue