PlaylistItem.vue 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. <script setup lang="ts">
  2. import { defineAsyncComponent, computed } from "vue";
  3. import { storeToRefs } from "pinia";
  4. import utils from "@/utils";
  5. import { useConfigStore } from "@/stores/config";
  6. const UserLink = defineAsyncComponent(
  7. () => import("@/components/UserLink.vue")
  8. );
  9. const props = defineProps({
  10. playlist: { type: Object, default: () => {} },
  11. showOwner: { type: Boolean, default: false }
  12. });
  13. const configStore = useConfigStore();
  14. const { sitename } = storeToRefs(configStore);
  15. const totalLength = playlist => {
  16. let length = 0;
  17. playlist.songs.forEach(song => {
  18. length += song.duration;
  19. });
  20. return utils.formatTimeLong(length);
  21. };
  22. const playlistLength = computed(
  23. () =>
  24. `${totalLength(props.playlist)} • ${props.playlist.songs.length} ${
  25. props.playlist.songs.length === 1 ? "song" : "songs"
  26. }`
  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>