PlaylistItem.vue 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. <script setup lang="ts">
  2. import { defineAsyncComponent, ref, computed, onMounted } from "vue";
  3. import utils from "@/utils";
  4. const UserLink = defineAsyncComponent(
  5. () => import("@/components/UserLink.vue")
  6. );
  7. const props = defineProps({
  8. playlist: { type: Object, default: () => {} },
  9. showOwner: { type: Boolean, default: false }
  10. });
  11. const sitename = ref("Musare");
  12. const totalLength = playlist => {
  13. let length = 0;
  14. playlist.songs.forEach(song => {
  15. length += song.duration;
  16. });
  17. return utils.formatTimeLong(length);
  18. };
  19. const playlistLength = computed(
  20. () =>
  21. `${totalLength(props.playlist)} • ${props.playlist.songs.length} ${
  22. props.playlist.songs.length === 1 ? "song" : "songs"
  23. }`
  24. );
  25. onMounted(async () => {
  26. sitename.value = await lofig.get("siteSettings.sitename");
  27. });
  28. </script>
  29. <template>
  30. <div class="playlist-item universal-item">
  31. <slot name="item-icon">
  32. <span></span>
  33. </slot>
  34. <div class="item-title-description">
  35. <p class="item-title">
  36. {{ playlist.displayName }}
  37. <i
  38. v-if="playlist.privacy === 'private'"
  39. class="private-playlist-icon material-icons"
  40. content="This playlist is not visible to other users."
  41. v-tippy="{ theme: 'info' }"
  42. >lock</i
  43. >
  44. </p>
  45. <p class="item-description">
  46. <span v-if="showOwner"
  47. ><a
  48. v-if="playlist.createdBy === 'Musare'"
  49. :title="sitename"
  50. >{{ sitename }}</a
  51. ><user-link v-else :user-id="playlist.createdBy" />
  52. </span>
  53. <span :title="playlistLength">
  54. {{ playlistLength }}
  55. </span>
  56. </p>
  57. </div>
  58. <div class="universal-item-actions">
  59. <div class="icons-group">
  60. <slot name="actions" />
  61. </div>
  62. </div>
  63. </div>
  64. </template>
  65. <style lang="less" scoped>
  66. .night-mode {
  67. .playlist-item {
  68. background-color: var(--dark-grey-2) !important;
  69. border: 0 !important;
  70. p {
  71. color: var(--light-grey-2) !important;
  72. }
  73. }
  74. }
  75. .playlist-item {
  76. width: 100%;
  77. height: 72px;
  78. column-gap: 7.5px;
  79. .item-title-description {
  80. flex: 1;
  81. overflow: hidden;
  82. .item-title {
  83. color: var(--dark-grey-2);
  84. font-size: 20px;
  85. line-height: 23px;
  86. margin-bottom: 0;
  87. display: flex;
  88. align-items: center;
  89. .private-playlist-icon {
  90. color: var(--dark-pink);
  91. font-size: 18px;
  92. margin-left: 5px;
  93. }
  94. }
  95. }
  96. .universal-item-actions {
  97. margin-left: none;
  98. div {
  99. display: flex;
  100. align-items: center;
  101. line-height: 1;
  102. button,
  103. .button {
  104. width: 100%;
  105. font-size: 17px;
  106. height: 36px;
  107. }
  108. }
  109. }
  110. }
  111. </style>