QueueItem.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. <template>
  2. <div class="universal-item queue-item">
  3. <div id="thumbnail-and-info">
  4. <img
  5. class="item-thumbnail"
  6. :src="
  7. song.songId &&
  8. (!song.thumbnail ||
  9. (song.thumbnail &&
  10. (song.thumbnail.lastIndexOf('notes-transparent') !==
  11. -1 ||
  12. song.thumbnail.lastIndexOf(
  13. '/assets/notes.png'
  14. ) !== -1)) ||
  15. song.thumbnail === 'empty' ||
  16. song.thumbnail == null)
  17. ? `https://img.youtube.com/vi/${song.songId}/mqdefault.jpg`
  18. : song.thumbnail
  19. "
  20. onerror="this.src='/assets/notes-transparent.png'"
  21. />
  22. <div id="song-info">
  23. <h4
  24. class="item-title"
  25. :style="
  26. song.artists.length < 1 ? { fontSize: '16px' } : null
  27. "
  28. :title="song.title"
  29. >
  30. {{ song.title }}
  31. <i
  32. v-if="song.status === 'verified'"
  33. class="material-icons verified-song"
  34. content="Verified Song"
  35. v-tippy
  36. >
  37. check_circle
  38. </i>
  39. </h4>
  40. <h5
  41. class="item-description"
  42. v-if="song.artists"
  43. :title="song.artists.join(', ')"
  44. >
  45. {{ song.artists.join(", ") }}
  46. </h5>
  47. <p
  48. id="song-request-time"
  49. v-if="
  50. station.type === 'community' &&
  51. station.partyMode === true
  52. "
  53. >
  54. Requested by
  55. <strong>
  56. <user-id-to-username
  57. :user-id="song.requestedBy"
  58. :link="true"
  59. />
  60. {{
  61. formatDistance(
  62. parseISO(song.requestedAt),
  63. new Date(),
  64. {
  65. includeSeconds: true
  66. }
  67. )
  68. }}
  69. ago
  70. </strong>
  71. </p>
  72. </div>
  73. </div>
  74. <div id="duration-and-actions">
  75. <p id="song-duration">
  76. {{ utils.formatTime(song.duration) }}
  77. </p>
  78. <div class="universal-item-actions">
  79. <tippy
  80. v-if="$parent.loggedIn"
  81. interactive="true"
  82. placement="left"
  83. theme="songActions"
  84. trigger="click"
  85. >
  86. <template #trigger>
  87. <i
  88. class="material-icons action-dropdown-icon"
  89. content="Song Options"
  90. v-tippy
  91. >more_horiz</i
  92. >
  93. </template>
  94. <a
  95. target="_blank"
  96. :href="`https://www.youtube.com/watch?v=${song.songId}`"
  97. content="View on Youtube"
  98. v-tippy
  99. >
  100. <div class="youtube-icon"></div>
  101. </a>
  102. <i
  103. class="material-icons report-icon"
  104. @click="report(song)"
  105. content="Report Song"
  106. v-tippy
  107. >
  108. flag
  109. </i>
  110. <add-to-playlist-dropdown :song="song">
  111. <i
  112. slot="button"
  113. class="material-icons add-to-playlist-icon"
  114. content="Add Song to Playlist"
  115. v-tippy
  116. >queue</i
  117. >
  118. </add-to-playlist-dropdown>
  119. <i
  120. v-if="$parent.isAdminOnly()"
  121. class="material-icons edit-icon"
  122. @click="edit(song)"
  123. content="Edit Song"
  124. v-tippy
  125. >
  126. edit
  127. </i>
  128. <i
  129. v-if="$parent.isOwnerOnly() || $parent.isAdminOnly()"
  130. class="material-icons delete-icon"
  131. @click="$parent.removeFromQueue(song.songId)"
  132. content="Remove Song from Queue"
  133. v-tippy
  134. >delete_forever</i
  135. >
  136. <slot name="actions" />
  137. </tippy>
  138. <a
  139. v-else
  140. target="_blank"
  141. :href="`https://www.youtube.com/watch?v=${song.songId}`"
  142. content="View on Youtube"
  143. v-tippy
  144. >
  145. <div class="youtube-icon"></div>
  146. </a>
  147. </div>
  148. </div>
  149. </div>
  150. </template>
  151. <script>
  152. import { mapActions } from "vuex";
  153. import { formatDistance, parseISO } from "date-fns";
  154. import AddToPlaylistDropdown from "../../../../../components/ui/AddToPlaylistDropdown.vue";
  155. import UserIdToUsername from "../../../../../components/common/UserIdToUsername.vue";
  156. import utils from "../../../../../../js/utils";
  157. export default {
  158. components: { UserIdToUsername, AddToPlaylistDropdown },
  159. props: {
  160. song: {
  161. type: Object,
  162. default: () => {}
  163. },
  164. station: {
  165. type: Object,
  166. default: () => {
  167. return { type: "community", partyMode: false };
  168. }
  169. }
  170. },
  171. data() {
  172. return {
  173. utils
  174. };
  175. },
  176. methods: {
  177. report(song) {
  178. this.reportSong(song);
  179. this.openModal({ sector: "station", modal: "report" });
  180. },
  181. edit(song) {
  182. this.editSong(song);
  183. this.openModal({ sector: "admin", modal: "editSong" });
  184. },
  185. ...mapActions("modals/editSong", ["editSong"]),
  186. ...mapActions("modals/report", ["reportSong"]),
  187. ...mapActions("modalVisibility", ["openModal"]),
  188. formatDistance,
  189. parseISO
  190. }
  191. };
  192. </script>
  193. <style lang="scss" scoped>
  194. .night-mode {
  195. .queue-item {
  196. background-color: var(--dark-grey-2) !important;
  197. border: 0 !important;
  198. }
  199. }
  200. /deep/ #nav-dropdown {
  201. margin-top: 36px;
  202. width: 0;
  203. height: 0;
  204. .nav-dropdown-items {
  205. width: 250px;
  206. max-width: 100vw;
  207. position: relative;
  208. right: 175px;
  209. }
  210. }
  211. .queue-item {
  212. #thumbnail-and-info,
  213. #duration-and-actions {
  214. display: flex;
  215. align-items: center;
  216. }
  217. #duration-and-actions {
  218. margin-left: 5px;
  219. .universal-item-actions div i {
  220. margin-left: 5px;
  221. }
  222. }
  223. #thumbnail-and-info {
  224. width: calc(100% - 90px);
  225. }
  226. #song-info {
  227. display: flex;
  228. flex-direction: column;
  229. justify-content: center;
  230. margin-left: 20px;
  231. width: calc(100% - 80px);
  232. *:not(i) {
  233. margin: 0;
  234. font-family: Karla, Arial, sans-serif;
  235. }
  236. #song-request-time {
  237. font-size: 12px;
  238. margin-top: 7px;
  239. }
  240. }
  241. #song-duration {
  242. font-size: 20px;
  243. }
  244. .edit-icon {
  245. color: var(--primary-color);
  246. }
  247. }
  248. </style>