YoutubeSearchItem.vue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <script lang="ts" setup>
  2. import { defineAsyncComponent, ref } from "vue";
  3. import { useModalsStore } from "@/stores/modals";
  4. const AddToPlaylistDropdown = defineAsyncComponent(
  5. () => import("@/pages/NewStation/Components/AddToPlaylistDropdown.vue")
  6. );
  7. const Button = defineAsyncComponent(
  8. () => import("@/pages/NewStation/Components/Button.vue")
  9. );
  10. const DropdownList = defineAsyncComponent(
  11. () => import("@/pages/NewStation/Components/DropdownList.vue")
  12. );
  13. const DropdownListItem = defineAsyncComponent(
  14. () => import("@/pages/NewStation/Components/DropdownListItem.vue")
  15. );
  16. const SongThumbnail = defineAsyncComponent(
  17. () => import("@/components/SongThumbnail.vue")
  18. );
  19. const props = defineProps<{
  20. item: {
  21. id: string;
  22. url: string;
  23. title: string;
  24. thumbnail: string;
  25. channelId: string;
  26. channelTitle: string;
  27. isAddedToQueue: boolean;
  28. };
  29. }>();
  30. const { openModal } = useModalsStore();
  31. const actions = ref();
  32. const expandActions = () => {
  33. actions.value.expand();
  34. };
  35. const collapseActions = () => {
  36. actions.value.collapse();
  37. };
  38. const view = () => {
  39. collapseActions();
  40. openModal({
  41. modal: "viewMedia",
  42. props: { mediaSource: `youtube:${props.item.id}` }
  43. });
  44. };
  45. defineExpose({
  46. expandActions,
  47. collapseActions
  48. });
  49. </script>
  50. <template>
  51. <div class="youtube-search-item">
  52. <SongThumbnail
  53. :song="{
  54. thumbnail: item.thumbnail,
  55. youtubeId: item.id
  56. }"
  57. />
  58. <div class="youtube-search-item__content">
  59. <p class="youtube-search-item__title" :title="item.title">
  60. {{ item.title }}
  61. </p>
  62. <a
  63. v-if="item.channelTitle && item.channelId"
  64. class="youtube-search-item__channel"
  65. :title="item.channelTitle"
  66. :href="'https://youtube.com/channel/' + item.channelId"
  67. target="_blank"
  68. >
  69. {{ item.channelTitle }}
  70. </a>
  71. </div>
  72. <slot name="featuredAction" />
  73. <DropdownList ref="actions">
  74. <Button icon="more_horiz" square inverse title="Actions" />
  75. <template #options>
  76. <slot name="actions" />
  77. <DropdownListItem>
  78. <AddToPlaylistDropdown :media-source="`youtube:${item.id}`">
  79. <button class="dropdown-list-item__action">
  80. <span
  81. class="material-icons dropdown-list-item__icon"
  82. aria-hidden="true"
  83. >
  84. playlist_add
  85. </span>
  86. Add to playlist
  87. </button>
  88. </AddToPlaylistDropdown>
  89. </DropdownListItem>
  90. <DropdownListItem
  91. icon="play_arrow"
  92. label="View media"
  93. @click="view"
  94. />
  95. </template>
  96. </DropdownList>
  97. </div>
  98. </template>
  99. <style lang="less" scoped>
  100. .youtube-search-item {
  101. display: flex;
  102. align-items: center;
  103. flex-shrink: 0;
  104. height: 48px;
  105. background-color: var(--white);
  106. border-radius: 5px;
  107. border: solid 1px var(--light-grey-1);
  108. gap: 5px;
  109. overflow: hidden;
  110. :deep(.thumbnail) {
  111. height: 48px;
  112. min-width: 48px;
  113. flex-shrink: 0;
  114. margin: 0;
  115. }
  116. &__content {
  117. display: flex;
  118. flex-direction: column;
  119. flex-grow: 1;
  120. min-width: 0;
  121. justify-content: center;
  122. }
  123. &__title {
  124. font-size: 11.75px !important;
  125. line-height: 14px;
  126. overflow: hidden;
  127. text-overflow: ellipsis;
  128. display: -webkit-box;
  129. -webkit-box-orient: vertical;
  130. -webkit-line-clamp: 2;
  131. word-wrap: break-word;
  132. }
  133. &__channel {
  134. display: inline-flex;
  135. align-items: center;
  136. align-self: start;
  137. font-size: 10px !important;
  138. font-weight: 500 !important;
  139. line-height: 12px;
  140. color: var(--dark-grey-1);
  141. overflow: hidden;
  142. text-overflow: ellipsis;
  143. white-space: nowrap;
  144. }
  145. & > :deep(.dropdown-list__reference) {
  146. display: flex;
  147. flex-direction: column;
  148. justify-content: center;
  149. padding-right: 5px;
  150. }
  151. :deep(.dropdown-list-item > .dropdown-list__reference) {
  152. display: flex;
  153. flex-grow: 1;
  154. }
  155. }
  156. </style>