SongsList.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. <template>
  2. <div class="sidebar" transition="slide">
  3. <div class="inner-wrapper">
  4. <div class="title" v-if="$parent.type === 'community'">Queue</div>
  5. <div class="title" v-else>Playlist</div>
  6. <article class="media" v-if="!$parent.noSong">
  7. <figure class="media-left" v-if="$parent.currentSong.thumbnail">
  8. <p class="image is-64x64">
  9. <img
  10. :src="$parent.currentSong.thumbnail"
  11. onerror="this.src='/assets/notes-transparent.png'"
  12. />
  13. </p>
  14. </figure>
  15. <div class="media-content">
  16. <div class="content">
  17. <p>
  18. Current Song:
  19. <strong>{{ $parent.currentSong.title }}</strong>
  20. <br />
  21. <small>{{ $parent.currentSong.artists }}</small>
  22. </p>
  23. </div>
  24. </div>
  25. <div class="media-right">{{ $parent.formatTime($parent.currentSong.duration) }}</div>
  26. </article>
  27. <p v-if="$parent.noSong" class="center">There is currently no song playing.</p>
  28. <article class="media" v-for="(song, index) in $parent.songsList" :key="index">
  29. <div class="media-content">
  30. <div class="content" style="display: block;padding-top: 10px;">
  31. <strong class="songTitle">{{ song.title }}</strong>
  32. <small>{{ song.artists.join(', ') }}</small>
  33. <div v-if="$parent.type === 'community' && $parent.station.partyMode === true">
  34. <small>
  35. Requested by
  36. <b>{{$parent.$parent.getUsernameFromId(song.requestedBy)}} {{userIdMap['Z' + song.requestedBy]}}</b>
  37. </small>
  38. <i
  39. class="material-icons"
  40. style="vertical-align: middle;"
  41. v-on:click="removeFromQueue(song.songId)"
  42. v-if="isOwnerOnly() || isAdminOnly()"
  43. >delete_forever</i>
  44. </div>
  45. </div>
  46. </div>
  47. <div class="media-right">{{ $parent.formatTime(song.duration) }}</div>
  48. </article>
  49. <div
  50. v-if="$parent.type === 'community' && $parent.$parent.loggedIn && $parent.station.partyMode === true"
  51. >
  52. <button
  53. class="button add-to-queue"
  54. v-on:click="toggleModal({ sector: 'station', modal: 'addSongToQueue' })"
  55. v-if="($parent.station.locked && isOwnerOnly()) || !$parent.station.locked || ($parent.station.locked && isAdminOnly() && dismissedWarning)"
  56. >Add Song to Queue</button>
  57. <button
  58. class="button add-to-queue add-to-queue-warning"
  59. v-on:click="dismissedWarning = true"
  60. v-if="$parent.station.locked && isAdminOnly() && !isOwnerOnly() && !dismissedWarning"
  61. >THIS STATION'S QUEUE IS LOCKED.</button>
  62. <button
  63. class="button add-to-queue add-to-queue-disabled"
  64. v-if="$parent.station.locked && !isAdminOnly() && !isOwnerOnly()"
  65. >THIS STATION'S QUEUE IS LOCKED.</button>
  66. </div>
  67. </div>
  68. </div>
  69. </template>
  70. <script>
  71. import { mapActions } from "vuex";
  72. import io from "../../io";
  73. import { Toast } from "vue-roaster";
  74. export default {
  75. data: function() {
  76. return {
  77. dismissedWarning: false,
  78. userIdMap: this.$parent.$parent.userIdMap
  79. };
  80. },
  81. methods: {
  82. isOwnerOnly: function() {
  83. return (
  84. this.$parent.$parent.loggedIn &&
  85. this.$parent.$parent.userId === this.$parent.station.owner
  86. );
  87. },
  88. isAdminOnly: function() {
  89. return (
  90. this.$parent.$parent.loggedIn && this.$parent.$parent.role === "admin"
  91. );
  92. },
  93. removeFromQueue: function(songId) {
  94. socket.emit(
  95. "stations.removeFromQueue",
  96. this.$parent.station._id,
  97. songId,
  98. res => {
  99. if (res.status === "success") {
  100. Toast.methods.addToast(
  101. "Successfully removed song from the queue.",
  102. 4000
  103. );
  104. } else Toast.methods.addToast(res.message, 8000);
  105. }
  106. );
  107. },
  108. ...mapActions("modals", ["toggleModal"])
  109. },
  110. mounted: function() {
  111. /*let _this = this;
  112. io.getSocket((socket) => {
  113. _this.socket = socket;
  114. });*/
  115. }
  116. };
  117. </script>
  118. <style lang='scss' scoped>
  119. .sidebar {
  120. position: fixed;
  121. z-index: 1;
  122. top: 0;
  123. right: 0;
  124. width: 300px;
  125. height: 100vh;
  126. background-color: #fff;
  127. box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
  128. }
  129. .inner-wrapper {
  130. top: 64px;
  131. position: relative;
  132. overflow: auto;
  133. height: 100%;
  134. }
  135. .slide-transition {
  136. transition: transform 0.6s ease-in-out;
  137. transform: translateX(0);
  138. }
  139. .slide-enter,
  140. .slide-leave {
  141. transform: translateX(100%);
  142. }
  143. .title {
  144. background-color: rgb(3, 169, 244);
  145. text-align: center;
  146. padding: 10px;
  147. color: white;
  148. font-weight: 600;
  149. }
  150. .media {
  151. padding: 0 25px;
  152. }
  153. .media-content .content {
  154. min-height: 64px;
  155. display: flex;
  156. align-items: center;
  157. }
  158. .content p strong {
  159. word-break: break-word;
  160. }
  161. .content p small {
  162. word-break: break-word;
  163. }
  164. .add-to-queue {
  165. width: 100%;
  166. margin-top: 25px;
  167. height: 40px;
  168. border-radius: 0;
  169. background: rgb(3, 169, 244);
  170. color: #fff !important;
  171. border: 0;
  172. &:active,
  173. &:focus {
  174. border: 0;
  175. }
  176. }
  177. .add-to-queue.add-to-queue-warning {
  178. background-color: red;
  179. }
  180. .add-to-queue.add-to-queue-disabled {
  181. background-color: gray;
  182. }
  183. .add-to-queue.add-to-queue-disabled:focus {
  184. background-color: gray;
  185. }
  186. .add-to-queue:focus {
  187. background: #029ce3;
  188. }
  189. .media-right {
  190. line-height: 64px;
  191. }
  192. .songTitle {
  193. word-wrap: break-word;
  194. overflow: hidden;
  195. text-overflow: ellipsis;
  196. display: -webkit-box;
  197. -webkit-box-orient: vertical;
  198. -webkit-line-clamp: 2;
  199. line-height: 20px;
  200. max-height: 40px;
  201. }
  202. </style>