@ozdao/martyrs 0.2.493 → 0.2.495

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/_virtual/index.cjs +4 -4
  2. package/dist/_virtual/index.js +4 -4
  3. package/dist/_virtual/index2.cjs +4 -4
  4. package/dist/_virtual/index2.js +4 -4
  5. package/dist/builder.cjs +43 -88
  6. package/dist/builder.js +45 -90
  7. package/dist/martyrs/src/components/FieldTags/FieldTags.vue.cjs +1 -1
  8. package/dist/martyrs/src/components/FieldTags/FieldTags.vue.js +1 -1
  9. package/dist/martyrs/src/modules/community/components/pages/CreateBlogPost.vue.cjs +1 -1
  10. package/dist/martyrs/src/modules/community/components/pages/CreateBlogPost.vue.js +1 -1
  11. package/dist/martyrs/src/modules/globals/globals.client.cjs +1 -1
  12. package/dist/martyrs/src/modules/globals/globals.client.cjs.map +1 -1
  13. package/dist/martyrs/src/modules/globals/globals.client.js +1 -1
  14. package/dist/martyrs/src/modules/globals/globals.client.js.map +1 -1
  15. package/dist/martyrs/src/modules/globals/views/classes/globals.i18n.cjs +1 -1
  16. package/dist/martyrs/src/modules/globals/views/classes/globals.i18n.js +1 -1
  17. package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.cjs +28 -13
  18. package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.cjs.map +1 -1
  19. package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.js +28 -13
  20. package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.js.map +1 -1
  21. package/dist/martyrs/src/modules/globals/views/router/scrollBehavior.cjs +1 -1
  22. package/dist/martyrs/src/modules/globals/views/router/scrollBehavior.cjs.map +1 -1
  23. package/dist/martyrs/src/modules/globals/views/router/scrollBehavior.js +1 -1
  24. package/dist/martyrs/src/modules/globals/views/router/scrollBehavior.js.map +1 -1
  25. package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.cjs +1 -1
  26. package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.cjs.map +1 -1
  27. package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.js +1 -1
  28. package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.js.map +1 -1
  29. package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.cjs +2 -2
  30. package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.cjs.map +1 -1
  31. package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.js +2 -2
  32. package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.js.map +1 -1
  33. package/dist/martyrs/src/modules/music/components/pages/Album.vue.cjs +86 -81
  34. package/dist/martyrs/src/modules/music/components/pages/Album.vue.cjs.map +1 -1
  35. package/dist/martyrs/src/modules/music/components/pages/Album.vue.js +88 -83
  36. package/dist/martyrs/src/modules/music/components/pages/Album.vue.js.map +1 -1
  37. package/dist/martyrs/src/modules/music/components/pages/Artist.vue.cjs +4 -4
  38. package/dist/martyrs/src/modules/music/components/pages/Artist.vue.cjs.map +1 -1
  39. package/dist/martyrs/src/modules/music/components/pages/Artist.vue.js +4 -4
  40. package/dist/martyrs/src/modules/music/components/pages/Artist.vue.js.map +1 -1
  41. package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.cjs +5 -5
  42. package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.cjs.map +1 -1
  43. package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.js +5 -5
  44. package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.js.map +1 -1
  45. package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.cjs +12 -9
  46. package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.cjs.map +1 -1
  47. package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.js +12 -9
  48. package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.js.map +1 -1
  49. package/dist/martyrs/src/modules/music/components/pages/SearchResults.vue.cjs +7 -7
  50. package/dist/martyrs/src/modules/music/components/pages/SearchResults.vue.cjs.map +1 -1
  51. package/dist/martyrs/src/modules/music/components/pages/SearchResults.vue.js +7 -7
  52. package/dist/martyrs/src/modules/music/components/pages/SearchResults.vue.js.map +1 -1
  53. package/dist/martyrs/src/modules/music/components/pages/Track.vue.cjs +43 -37
  54. package/dist/martyrs/src/modules/music/components/pages/Track.vue.cjs.map +1 -1
  55. package/dist/martyrs/src/modules/music/components/pages/Track.vue.js +45 -39
  56. package/dist/martyrs/src/modules/music/components/pages/Track.vue.js.map +1 -1
  57. package/dist/martyrs/src/modules/music/music.client.cjs.map +1 -1
  58. package/dist/martyrs/src/modules/music/music.client.js.map +1 -1
  59. package/dist/martyrs/src/modules/notifications/notifications.client.cjs +1 -1
  60. package/dist/martyrs/src/modules/notifications/notifications.client.cjs.map +1 -1
  61. package/dist/martyrs/src/modules/notifications/notifications.client.js +1 -1
  62. package/dist/martyrs/src/modules/notifications/notifications.client.js.map +1 -1
  63. package/dist/style.css +5 -5
  64. package/package.json +1 -1
  65. package/src/builder/rspack/rspack.config.spa.client.js +0 -44
  66. package/src/builder/rspack/rspack.config.ssr.client.js +41 -41
  67. package/src/modules/globals/globals.client.js +1 -2
  68. package/src/modules/globals/views/components/layouts/Client.vue +13 -11
  69. package/src/modules/globals/views/router/scrollBehavior.js +1 -1
  70. package/src/modules/music/components/SidebarMusic.vue +7 -7
  71. package/src/modules/music/components/cards/TrackListCard.vue +1 -1
  72. package/src/modules/music/components/forms/SearchForm.vue +1 -1
  73. package/src/modules/music/components/pages/Album.vue +26 -29
  74. package/src/modules/music/components/pages/Artist.vue +4 -4
  75. package/src/modules/music/components/pages/MusicLibrary.vue +5 -5
  76. package/src/modules/music/components/pages/Playlist.vue +9 -9
  77. package/src/modules/music/components/pages/SearchResults.vue +6 -6
  78. package/src/modules/music/components/pages/Track.vue +22 -20
  79. package/src/modules/music/music.client.js +1 -1
  80. package/src/modules/notifications/notifications.client.js +1 -1
@@ -50,7 +50,7 @@ const _hoisted_14 = {
50
50
  };
51
51
  const _hoisted_15 = { class: "h1 mn-b-medium" };
52
52
  const _hoisted_16 = { class: "flex gap-small mn-b-medium" };
53
- const _hoisted_17 = { class: "dropdown-menu bg-dark pd-small radius-medium shadow-big mn-t-thin" };
53
+ const _hoisted_17 = { class: "dropdown-menu bg-white pd-small radius-medium shadow-big mn-t-thin" };
54
54
  const _hoisted_18 = { class: "owner-section mn-b-big" };
55
55
  const _hoisted_19 = { class: "owner-card bg-light pd-medium radius-medium flex items-center gap-medium" };
56
56
  const _hoisted_20 = { class: "owner-avatar" };
@@ -346,10 +346,13 @@ const _sfc_main = {
346
346
  onClick: playPlaylist,
347
347
  color: "primary",
348
348
  size: "medium",
349
- class: "flex-1 flex-center gap-thin"
349
+ class: "flex-1 t-white bg-black radius-thin flex-center gap-thin"
350
350
  }, {
351
351
  default: withCtx(() => [
352
- createVNode(_sfc_main$2, { class: "i-medium" }),
352
+ createVNode(_sfc_main$2, {
353
+ fill: "rgb(var(--white))",
354
+ class: "i-medium"
355
+ }),
353
356
  _cache[11] || (_cache[11] = createTextVNode(" Play All "))
354
357
  ]),
355
358
  _: 1
@@ -358,7 +361,7 @@ const _sfc_main = {
358
361
  onClick: shufflePlay,
359
362
  color: "primary",
360
363
  size: "medium",
361
- class: "flex-1 flex-center gap-thin"
364
+ class: "flex-1 bg-light radius-thin flex-center gap-thin"
362
365
  }, {
363
366
  default: withCtx(() => [
364
367
  createVNode(_sfc_main$3, { class: "i-medium" }),
@@ -370,7 +373,7 @@ const _sfc_main = {
370
373
  onClick: toggleFollow,
371
374
  color: "primary",
372
375
  size: "medium",
373
- class: "flex-1 flex-center gap-thin"
376
+ class: "flex-1 bg-light radius-thin flex-center gap-thin"
374
377
  }, {
375
378
  default: withCtx(() => [
376
379
  createTextVNode(toDisplayString(isFollowing.value ? "Follow" : "Unfollow"), 1)
@@ -378,7 +381,7 @@ const _sfc_main = {
378
381
  _: 1
379
382
  }),
380
383
  createVNode(_sfc_main$4, {
381
- label: { component: _sfc_main$5, class: "i-medium" },
384
+ label: { component: _sfc_main$5, class: "bg-light radius-thin pd-thin i-big" },
382
385
  modelValue: showDropdown.value,
383
386
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => showDropdown.value = $event),
384
387
  class: "relative"
@@ -515,7 +518,7 @@ const _sfc_main = {
515
518
  collaborator.photoUrl ? (openBlock(), createBlock(Media, {
516
519
  key: 0,
517
520
  url: collaborator.photoUrl,
518
- class: "w-1-5r h-1-5r radius-full object-cover"
521
+ class: "i-regular radius-full object-cover"
519
522
  }, null, 8, ["url"])) : createCommentVNode("", true),
520
523
  createElementVNode("span", _hoisted_27, toDisplayString(collaborator.name || collaborator.profile?.name || "User"), 1)
521
524
  ]);
@@ -651,7 +654,7 @@ const _sfc_main = {
651
654
  createVNode(_sfc_main$c, {
652
655
  isPopupOpen: showEditModal.value && (isOwner.value || isCollaborator.value),
653
656
  onClosePopup: _cache[4] || (_cache[4] = ($event) => showEditModal.value = false),
654
- class: "bg-dark pd-medium w-m-30r radius-medium"
657
+ class: "bg-white pd-medium w-m-30r radius-medium"
655
658
  }, {
656
659
  default: withCtx(() => [
657
660
  createVNode(_sfc_main$d, {
@@ -666,7 +669,7 @@ const _sfc_main = {
666
669
  createVNode(_sfc_main$c, {
667
670
  isPopupOpen: showDeleteModal.value,
668
671
  onClosePopup: _cache[6] || (_cache[6] = ($event) => showDeleteModal.value = false),
669
- class: "bg-dark pd-medium w-m-25r radius-medium"
672
+ class: "bg-white pd-medium w-m-25r radius-medium"
670
673
  }, {
671
674
  default: withCtx(() => [
672
675
  _cache[34] || (_cache[34] = createElementVNode("h3", { class: "mn-b-medium" }, "Delete Playlist", -1)),
@@ -1 +1 @@
1
- {"version":3,"file":"Playlist.vue.js","sources":["../../../../../../../src/modules/music/components/pages/Playlist.vue"],"sourcesContent":["<template>\n <div class=\"playlist-page pd-small\">\n <!-- Not Found -->\n <div v-if=\"hasLoaded && !playlist\" class=\"t-center pd-big\">\n <h2 class=\"\">Playlist not found</h2>\n <p class=\"t-transp t-medium\">The playlist you're looking for doesn't exist or has been removed.</p>\n </div>\n \n <!-- Playlist Content -->\n <div v-if=\"playlist\" class=\"playlist-content cols-2-fit-content mobile:cols-1 gap-big\">\n <!-- Left Column - Cover & Stats -->\n <div class=\"pos-sticky pos-t-0 mobile:pos-relative playlist-cover-section\">\n <!-- Cover -->\n <div class=\"cover-container relative mn-b-medium radius-big overflow-hidden shadow-big\">\n <Media \n :url=\"playlist.coverUrl || '/assets/placeholder-playlist.jpg'\"\n :alt=\"playlist.title\"\n class=\"aspect-1x1 w-100 radius-medium o-hidden\"\n />\n </div>\n\n <!-- Quick Stats -->\n <div class=\"stats-grid grid cols-2 gap-small\">\n <div class=\"stat-card bg-light pd-medium radius-medium t-center\">\n <div class=\" mn-b-thin\">{{ playlistTracks.length }}</div>\n <div class=\"t-small t-transp t-uppercase\">Tracks</div>\n </div>\n <div class=\"stat-card bg-light pd-medium radius-medium t-center\">\n <div class=\" mn-b-thin\">{{ formatNumber(playlist.followers || 0) }}</div>\n <div class=\"t-small t-transp t-uppercase\">Followers</div>\n </div>\n </div>\n </div>\n\n <!-- Right Column - Playlist Details -->\n <div class=\"playlist-details-section\">\n <!-- Playlist Type Badge -->\n <div class=\"flex items-center gap-small mn-b-small\">\n <span class=\"badge bg-primary-transp-20 t-primary pd-thin-big radius-small t-small t-uppercase\">\n Playlist\n </span>\n <span v-if=\"playlist.isCollaborative\" class=\"badge bg-secondary-transp-20 t-secondary pd-thin-big radius-small t-small\">\n Collaborative\n </span>\n <span v-if=\"playlist.status === 'published'\" class=\"badge bg-success-transp-20 t-success pd-thin-big radius-small t-small\">\n Published\n </span>\n </div>\n\n <!-- Playlist Title -->\n <h1 class=\"h1 mn-b-medium\">{{ playlist.title }}</h1>\n\n <!-- Action Buttons -->\n <div class=\"flex gap-small mn-b-medium\">\n <Button\n @click=\"playPlaylist\"\n color=\"primary\"\n size=\"medium\"\n class=\"flex-1 flex-center gap-thin\"\n >\n <IconPlay class=\"i-medium\" />\n Play All\n </Button>\n\n <Button\n @click=\"shufflePlay\"\n color=\"primary\"\n size=\"medium\"\n class=\"flex-1 flex-center gap-thin\"\n >\n <IconShuffle class=\"i-medium\" />\n Shuffle\n </Button>\n\n <Button\n @click=\"toggleFollow\"\n color=\"primary\"\n size=\"medium\"\n class=\"flex-1 flex-center gap-thin\"\n >\n {{isFollowing ? 'Follow' : 'Unfollow'}}\n </Button>\n\n \n <Dropdown :label=\"{component: IconEllipsis, class: 'i-medium' }\" v-model=\"showDropdown\" class=\"relative\">\n <template #trigger>\n <Button color=\"transp\" size=\"medium\" class=\"w-3r h-3r radius-full\">\n <IconEllipsis class=\"w-1-25r h-1-25r\" />\n </Button>\n </template>\n <template #default>\n <div class=\"dropdown-menu bg-dark pd-small radius-medium shadow-big mn-t-thin\">\n <Button @click=\"addToQueue\" color=\"transp\" size=\"small\" class=\"w-100 justify-start\">\n Add to Queue\n </Button>\n <Button @click=\"copyLink\" color=\"transp\" size=\"small\" class=\"w-100 justify-start\">\n Copy Link\n </Button>\n <template v-if=\"isOwner || isCollaborator\">\n <hr class=\"mn-v-thin border-dark-transp-10\" />\n <Button @click=\"editPlaylist\" color=\"transp\" size=\"small\" class=\"w-100 justify-start\">\n Edit Playlist\n </Button>\n <Button v-if=\"isOwner\" @click=\"toggleCollaborative\" color=\"transp\" size=\"small\" class=\"w-100 justify-start\">\n {{ playlist.isCollaborative ? 'Make Private' : 'Make Collaborative' }}\n </Button>\n <Button v-if=\"isOwner\" @click=\"deletePlaylist\" color=\"danger\" size=\"small\" class=\"w-100 justify-start\">\n Delete Playlist\n </Button>\n </template>\n </div>\n </template>\n </Dropdown>\n </div>\n\n <!-- Owner/Creator Card -->\n <div class=\"owner-section mn-b-big\">\n <h3 class=\"t-medium mn-b-small\">Created by</h3>\n <div class=\"owner-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <router-link \n :to=\"getOwnerProfileLink(playlist.creator || playlist.owner)\"\n class=\"flex items-center gap-medium flex-1 hover-opacity\"\n >\n <div class=\"owner-avatar\">\n <Media \n v-if=\"getOwnerData(playlist)?.photoUrl\"\n :url=\"getOwnerData(playlist).photoUrl\"\n :alt=\"getOwnerData(playlist)?.name\"\n class=\"w-4r h-4r radius-full object-cover\"\n />\n <div v-else class=\"w-4r h-4r radius-full bg-primary flex-center \">\n {{ getPlaylistOwnerName(playlist).charAt(0) }}\n </div>\n </div>\n <div>\n <div class=\"flex items-center gap-thin\">\n <span class=\"t-large \">{{ getPlaylistOwnerName(playlist) }}</span>\n <IconVerified v-if=\"getOwnerData(playlist)?.isVerified\" class=\"w-1r h-1r t-primary\" />\n </div>\n <span class=\"t-small t-transp\">{{ playlist.creator?.type || 'User' }}</span>\n </div>\n </router-link>\n <Button \n v-if=\"!isOwner && authState.user\"\n @click=\"() => toggleFollowUser(getOwnerId(playlist))\"\n :color=\"followedUsers.includes(getOwnerId(playlist)) ? 'primary' : 'transp'\"\n size=\"small\"\n >\n {{ followedUsers.includes(getOwnerId(playlist)) ? 'Following' : 'Follow' }}\n </Button>\n </div>\n </div>\n\n <!-- Collaborators -->\n <div v-if=\"playlist.collaborators && playlist.collaborators.length > 0\" class=\"collaborators-section mn-b-big\">\n <h3 class=\"t-medium mn-b-small\">Collaborators</h3>\n <div class=\"flex flex-wrap gap-small\">\n <div \n v-for=\"collaborator in playlist.collaborators\"\n :key=\"collaborator._id || collaborator\"\n class=\"collaborator-chip bg-light pd-thin-big radius-full flex items-center gap-thin\"\n >\n <Media \n v-if=\"collaborator.photoUrl\"\n :url=\"collaborator.photoUrl\"\n class=\"w-1-5r h-1-5r radius-full object-cover\"\n />\n <span class=\"t-small\">{{ collaborator.name || collaborator.profile?.name || 'User' }}</span>\n </div>\n </div>\n </div>\n\n <!-- Metadata Cards -->\n <div class=\"metadata-grid grid cols-2 gap-small mn-b-big\">\n <!-- Created Date -->\n <div class=\"metadata-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <IconCalendar class=\"i-medium t-primary\" />\n <div>\n <div class=\"t-small t-transp t-uppercase\">Created</div>\n <div class=\"t-medium \">{{ formatDate(playlist.createdAt) }}</div>\n </div>\n </div>\n\n <!-- Total Duration -->\n <div class=\"metadata-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <IconClock class=\"i-medium t-primary\" />\n <div>\n <div class=\"t-small t-transp t-uppercase\">Duration</div>\n <div class=\"t-medium \">{{ totalDuration }}</div>\n </div>\n </div>\n\n <!-- Updated Date -->\n <div class=\"metadata-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <IconRefresh class=\"i-medium t-primary\" />\n <div>\n <div class=\"t-small t-transp t-uppercase\">Updated</div>\n <div class=\"t-medium \">{{ formatDate(playlist.updatedAt) }}</div>\n </div>\n </div>\n\n <!-- Visibility -->\n <div class=\"metadata-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <IconEye class=\"i-medium t-primary\" />\n <div>\n <div class=\"t-small t-transp t-uppercase\">Visibility</div>\n <div class=\"t-medium \">{{ playlist.isPublic ? 'Public' : 'Private' }}</div>\n </div>\n </div>\n </div>\n\n <!-- Tags -->\n <div v-if=\"playlist.tags && playlist.tags.length\" class=\"tags-section mn-b-medium\">\n <h3 class=\"t-medium mn-b-small\">Tags</h3>\n <div class=\"flex gap-thin flex-wrap\">\n <span \n v-for=\"tag in playlist.tags\" \n :key=\"tag\"\n class=\"tag bg-light t-transp pd-thin-big radius-small t-small hover-bg-light cursor-pointer\"\n >\n #{{ tag }}\n </span>\n </div>\n </div>\n\n <!-- Description -->\n <div v-if=\"playlist.description\" class=\"description-section bg-light pd-medium radius-medium mn-b-medium\">\n <h3 class=\"t-medium mn-b-small\">About</h3>\n <p class=\"t-transp\">{{ playlist.description }}</p>\n </div>\n </div>\n </div>\n\n <!-- Playlist Tracks -->\n <section v-if=\"!isLoading && playlist && playlistTracks.length\" class=\"tracks-section mn-t-big\">\n <h2 class=\"h2 mn-b-medium\">Tracklist</h2>\n <Feed\n :store=\"{\n read: () => Promise.resolve(playlistTracks),\n state: { isLoading: false }\n }\"\n :external=\"true\"\n :items=\"playlistTracks\"\n :states=\"{\n empty: {\n title: 'No tracks in playlist',\n description: 'Add some tracks to get started',\n class: 'pd-medium t-center'\n }\n }\"\n >\n <template #default=\"{ items }\">\n <div class=\"bg-light radius-medium o-hidden\">\n <TrackListCard\n v-for=\"(track, index) in items\"\n :key=\"track._id\"\n :track=\"track\"\n :index=\"index + 1\"\n :showAlbum=\"true\"\n :showCover=\"true\"\n :canRemove=\"isOwner || isCollaborator\"\n @remove=\"() => removeTrack(track._id)\"\n />\n </div>\n </template>\n </Feed>\n </section>\n\n <!-- Empty State -->\n <section v-else-if=\"!isLoading && playlist && !playlistTracks.length\" class=\"empty-section mn-t-big\">\n <div class=\"empty-tracks t-center pd-big bg-light radius-medium\">\n <h3 class=\" mn-b-small\">This playlist is empty</h3>\n <p class=\"t-transp t-medium mn-b-medium\">Add some tracks to get started</p>\n \n <Button \n v-if=\"isOwner || isCollaborator\"\n @click=\"$router.push({ name: 'music-search' })\"\n color=\"primary\"\n size=\"medium\"\n >\n Find Tracks\n </Button>\n </div>\n </section>\n\n <!-- More Playlists -->\n <section v-if=\"!isLoading && playlist && morePlaylists.length\" class=\"more-playlists-section mn-t-big\">\n <div class=\"flex justify-between items-center mn-b-medium\">\n <h2 class=\"h2\">More Playlists</h2>\n <router-link \n v-if=\"playlist.creator\"\n :to=\"getOwnerProfileLink(playlist.creator)\" \n class=\"t-primary hover-opacity\"\n >\n See all\n </router-link>\n </div>\n <div class=\"flex flex-nowrap gap-small o-x-scroll overscroll-behavior-x-contain scroll-behavior-smooth scroll-snap-type-x-mandatory scroll-hide\">\n <li v-for=\"relatedPlaylist in morePlaylists\" :key=\"relatedPlaylist._id\" class=\"flex-none scroll-snap-align-start\">\n <PlaylistCard :playlist=\"relatedPlaylist\" class=\"w-min-15r transition-cubic-in-out\" />\n </li>\n </div>\n </section>\n\n <!-- Edit Playlist Modal -->\n <Popup \n :isPopupOpen=\"showEditModal && (isOwner || isCollaborator)\"\n @close-popup=\"showEditModal = false\" \n class=\"bg-dark pd-medium w-m-30r radius-medium\"\n >\n <PlaylistForm \n :editMode=\"true\"\n :url=\"playlist.url\"\n @cancel=\"showEditModal = false\"\n @updated=\"handlePlaylistUpdated\"\n />\n </Popup>\n\n <!-- Delete Confirmation Modal -->\n <Popup \n :isPopupOpen=\"showDeleteModal\"\n @close-popup=\"showDeleteModal = false\" \n class=\"bg-dark pd-medium w-m-25r radius-medium\"\n >\n <h3 class=\"mn-b-medium\">Delete Playlist</h3>\n <p class=\"t-transp mn-b-medium\">Are you sure you want to delete \"{{ playlist.title }}\"? This action cannot be undone.</p>\n \n <div class=\"flex justify-end gap-small\">\n <Button \n @click=\"showDeleteModal = false\"\n color=\"transp\"\n size=\"medium\"\n >\n Cancel\n </Button>\n \n <Button \n @click=\"confirmDelete\"\n color=\"danger\"\n size=\"medium\"\n >\n Delete Playlist\n </Button>\n </div>\n </Popup>\n </div>\n</template>\n\n<script setup>\nimport { ref, computed, onMounted, watch } from 'vue';\nimport { useRoute, useRouter } from 'vue-router';\nimport Button from '@martyrs/src/components/Button/Button.vue';\nimport Loader from '@martyrs/src/components/Loader/Loader.vue';\nimport Media from '@martyrs/src/components/Media/Media.vue';\nimport Dropdown from '@martyrs/src/components/Dropdown/Dropdown.vue';\nimport Feed from '@martyrs/src/components/Feed/Feed.vue';\nimport Popup from '@martyrs/src/components/Popup/Popup.vue';\n\n// Icons\nimport IconPlay from '@martyrs/src/modules/icons/navigation/IconPlay.vue';\nimport IconLike from '@martyrs/src/modules/icons/navigation/IconLike.vue';\nimport IconEllipsis from '@martyrs/src/modules/icons/navigation/IconEllipsis.vue';\nimport IconShuffle from '@martyrs/src/modules/icons/navigation/IconShuffle.vue';\nimport IconCalendar from '@martyrs/src/modules/icons/entities/IconCalendar.vue';\nimport IconClock from '@martyrs/src/modules/icons/entities/IconTime.vue';\nimport IconEye from '@martyrs/src/modules/icons/actions/IconShow.vue';\nimport IconRefresh from '@martyrs/src/modules/icons/navigation/IconRefresh.vue';\nimport IconVerified from '@martyrs/src/modules/icons/navigation/IconCheckmark.vue';\n\n// Components\nimport TrackListCard from '../cards/TrackListCard.vue';\nimport PlaylistCard from '../cards/PlaylistCard.vue';\nimport PlaylistForm from '../forms/PlaylistForm.vue';\n\n// Store\nimport { state as playlistsState, actions as playlistsActions } from '../../store/playlists.js';\nimport { state as tracksState, actions as tracksActions } from '../../store/tracks.js';\nimport { actions as playerActions } from '../../store/player.js';\nimport { state as authState } from '@martyrs/src/modules/auth/views/store/auth.js';\nimport * as globals from '@martyrs/src/modules/globals/views/store/globals.js';\n\nconst route = useRoute();\nconst router = useRouter();\n\n// Emits\nconst emits = defineEmits(['page-loading', 'page-loaded']);\n\n// State\nconst hasLoaded = ref(false);\nconst isFollowing = ref(false);\nconst showDropdown = ref(false);\nconst showEditModal = ref(false);\nconst showDeleteModal = ref(false);\nconst followedUsers = ref([]);\nconst morePlaylists = ref([]);\n\n// Clear state\nplaylistsState.currentPlaylist = null;\nplaylistsState.currentPlaylistTracks = [];\n\n// Computed\nconst playlist = computed(() => playlistsState.currentPlaylist);\nconst playlistTracks = computed(() => playlistsState.currentPlaylistTracks || []);\n\nconst isOwner = computed(() => {\n if (!playlist.value || !authState.user) return false;\n \n const ownerId = playlist.value.owner?.target?._id || playlist.value.owner?.target;\n return ownerId === authState.user._id;\n});\n\nconst isCollaborator = computed(() => {\n if (!playlist.value || !authState.user) return false;\n \n return playlist.value.collaborators?.some(collab => \n (collab._id || collab) === authState.user._id\n );\n});\n\nconst totalDuration = computed(() => {\n if (!playlistTracks.value.length) return '0:00';\n const totalSeconds = playlistTracks.value.reduce((sum, track) => sum + (track.duration || 0), 0);\n return formatDuration(totalSeconds);\n});\n\n// Helper functions\nconst getOwnerData = (playlist) => {\n if (!playlist) return null;\n const owner = playlist.creator?.target || playlist.owner?.target;\n return typeof owner === 'object' ? owner : null;\n};\n\nconst getOwnerId = (playlist) => {\n if (!playlist) return null;\n const owner = playlist.creator?.target || playlist.owner?.target;\n return typeof owner === 'object' ? owner._id : owner;\n};\n\nconst getPlaylistOwnerName = (playlist) => {\n if (!playlist) return 'Unknown';\n \n const owner = getOwnerData(playlist);\n if (owner) {\n return owner.profile?.name || owner.name || 'Unknown';\n }\n \n return 'Unknown';\n};\n\nconst getOwnerProfileLink = (owner) => {\n if (!owner || !owner.target) return { name: 'music-home' };\n \n const targetId = typeof owner.target === 'object' ? owner.target._id : owner.target;\n \n if (owner.type === 'user' || owner.type === 'User') {\n return { name: 'User Profile', params: { _id: targetId } };\n } else if (owner.type === 'organization' || owner.type === 'Organization') {\n return { name: 'Organizatio', params: { _id: targetId } };\n }\n \n return { name: 'music-home' };\n};\n\n// Format helpers\nconst formatDate = (dateString) => {\n if (!dateString) return 'Unknown';\n return new Date(dateString).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric'\n });\n};\n\nconst formatDuration = (seconds) => {\n if (!seconds) return '0:00';\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n \n if (h > 0) {\n return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;\n }\n return `${m}:${s.toString().padStart(2, '0')}`;\n};\n\nconst formatNumber = (num) => {\n if (!num) return '0';\n if (num >= 1000000) {\n return (num / 1000000).toFixed(1) + 'M';\n } else if (num >= 1000) {\n return (num / 1000).toFixed(1) + 'K';\n }\n return num.toString();\n};\n\n// Actions\nconst playPlaylist = () => {\n if (playlistTracks.value && playlistTracks.value.length > 0) {\n playerActions.setQueue(playlistTracks.value);\n }\n};\n\nconst shufflePlay = () => {\n if (playlistTracks.value && playlistTracks.value.length > 0) {\n const shuffled = [...playlistTracks.value].sort(() => Math.random() - 0.5);\n playerActions.setQueue(shuffled);\n }\n};\n\nconst toggleFollow = async () => {\n isFollowing.value = !isFollowing.value;\n // TODO: Implement actual following\n try {\n if (isFollowing.value) {\n await playlistsActions.followPlaylist(playlist.value._id);\n } else {\n await playlistsActions.unfollowPlaylist(playlist.value._id);\n }\n } catch (error) {\n console.error('Error toggling follow:', error);\n isFollowing.value = !isFollowing.value; // Revert on error\n }\n};\n\nconst toggleFollowUser = (userId) => {\n const index = followedUsers.value.indexOf(userId);\n if (index > -1) {\n followedUsers.value.splice(index, 1);\n } else {\n followedUsers.value.push(userId);\n }\n // TODO: Implement actual following\n};\n\nconst addToQueue = () => {\n if (playlistTracks.value && playlistTracks.value.length > 0) {\n playlistTracks.value.forEach(track => {\n playerActions.addToQueue(track);\n });\n showDropdown.value = false;\n }\n};\n\nconst editPlaylist = () => {\n showEditModal.value = true;\n showDropdown.value = false;\n};\n\nconst toggleCollaborative = async () => {\n try {\n const updatedData = {\n _id: playlist.value._id,\n isCollaborative: !playlist.value.isCollaborative\n };\n \n await playlistsActions.updatePlaylist(updatedData);\n showDropdown.value = false;\n } catch (error) {\n console.error('Error updating playlist:', error);\n }\n};\n\nconst deletePlaylist = () => {\n showDeleteModal.value = true;\n showDropdown.value = false;\n};\n\nconst confirmDelete = async () => {\n try {\n await playlistsActions.deletePlaylist(playlist.value._id);\n router.push({ name: 'music-library' });\n } catch (error) {\n console.error('Error deleting playlist:', error);\n globals.actions.setError({\n message: 'Failed to delete playlist'\n });\n }\n};\n\nconst removeTrack = async (trackId) => {\n try {\n await playlistsActions.removeTrackFromPlaylist(playlist.value._id, trackId);\n // Refresh playlist data\n await fetchPlaylistData();\n } catch (error) {\n console.error('Error removing track:', error);\n globals.actions.setError({\n message: 'Failed to remove track'\n });\n }\n};\n\nconst copyLink = () => {\n navigator.clipboard.writeText(window.location.href);\n showDropdown.value = false;\n};\n\nconst handlePlaylistUpdated = () => {\n showEditModal.value = false;\n fetchPlaylistData();\n};\n\n// Data fetching\nconst fetchPlaylistData = async () => {\n try {\n await playlistsActions.fetchPlaylistByUrl(route.params.url);\n \n // Check if following\n if (authState.user && playlist.value) {\n // TODO: Check if user is following this playlist\n }\n \n // Fetch more playlists from the same creator\n if (playlist.value?.creator?.target) {\n const creatorId = typeof playlist.value.creator.target === 'object' \n ? playlist.value.creator.target._id \n : playlist.value.creator.target;\n \n const playlists = await playlistsActions.fetchPlaylists({\n 'creator.target': creatorId,\n isPublic: true,\n limit: 6\n });\n \n // Filter out current playlist\n morePlaylists.value = playlists.filter(p => p._id !== playlist.value._id).slice(0, 5);\n }\n } catch (error) {\n console.error('Error fetching playlist data:', error);\n }\n};\n\n// Lifecycle\nonMounted(async () => {\n emits('page-loading');\n \n await fetchPlaylistData();\n \n hasLoaded.value = true;\n emits('page-loaded');\n});\n</script>"],"names":["playlistsState","authState","playlist","playerActions","playlistsActions","globals.actions"],"mappings":"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"}
1
+ {"version":3,"file":"Playlist.vue.js","sources":["../../../../../../../src/modules/music/components/pages/Playlist.vue"],"sourcesContent":["<template>\n <div class=\"playlist-page pd-small\">\n <!-- Not Found -->\n <div v-if=\"hasLoaded && !playlist\" class=\"t-center pd-big\">\n <h2 class=\"\">Playlist not found</h2>\n <p class=\"t-transp t-medium\">The playlist you're looking for doesn't exist or has been removed.</p>\n </div>\n \n <!-- Playlist Content -->\n <div v-if=\"playlist\" class=\"playlist-content cols-2-fit-content mobile:cols-1 gap-big\">\n <!-- Left Column - Cover & Stats -->\n <div class=\"pos-sticky pos-t-0 mobile:pos-relative playlist-cover-section\">\n <!-- Cover -->\n <div class=\"cover-container relative mn-b-medium radius-big overflow-hidden shadow-big\">\n <Media \n :url=\"playlist.coverUrl || '/assets/placeholder-playlist.jpg'\"\n :alt=\"playlist.title\"\n class=\"aspect-1x1 w-100 radius-medium o-hidden\"\n />\n </div>\n\n <!-- Quick Stats -->\n <div class=\"stats-grid grid cols-2 gap-small\">\n <div class=\"stat-card bg-light pd-medium radius-medium t-center\">\n <div class=\" mn-b-thin\">{{ playlistTracks.length }}</div>\n <div class=\"t-small t-transp t-uppercase\">Tracks</div>\n </div>\n <div class=\"stat-card bg-light pd-medium radius-medium t-center\">\n <div class=\" mn-b-thin\">{{ formatNumber(playlist.followers || 0) }}</div>\n <div class=\"t-small t-transp t-uppercase\">Followers</div>\n </div>\n </div>\n </div>\n\n <!-- Right Column - Playlist Details -->\n <div class=\"playlist-details-section\">\n <!-- Playlist Type Badge -->\n <div class=\"flex items-center gap-small mn-b-small\">\n <span class=\"badge bg-primary-transp-20 t-primary pd-thin-big radius-small t-small t-uppercase\">\n Playlist\n </span>\n <span v-if=\"playlist.isCollaborative\" class=\"badge bg-secondary-transp-20 t-secondary pd-thin-big radius-small t-small\">\n Collaborative\n </span>\n <span v-if=\"playlist.status === 'published'\" class=\"badge bg-success-transp-20 t-success pd-thin-big radius-small t-small\">\n Published\n </span>\n </div>\n\n <!-- Playlist Title -->\n <h1 class=\"h1 mn-b-medium\">{{ playlist.title }}</h1>\n\n <!-- Action Buttons -->\n <div class=\"flex gap-small mn-b-medium\">\n <Button\n @click=\"playPlaylist\"\n color=\"primary\"\n size=\"medium\"\n class=\"flex-1 t-white bg-black radius-thin flex-center gap-thin\"\n >\n <IconPlay fill=\"rgb(var(--white))\" class=\"i-medium\" />\n Play All\n </Button>\n\n <Button\n @click=\"shufflePlay\"\n color=\"primary\"\n size=\"medium\"\n class=\"flex-1 bg-light radius-thin flex-center gap-thin\"\n >\n <IconShuffle class=\"i-medium\" />\n Shuffle\n </Button>\n\n <Button\n @click=\"toggleFollow\"\n color=\"primary\"\n size=\"medium\"\n class=\"flex-1 bg-light radius-thin flex-center gap-thin\"\n >\n {{isFollowing ? 'Follow' : 'Unfollow'}}\n </Button>\n\n \n <Dropdown :label=\"{component: IconEllipsis, class: 'bg-light radius-thin pd-thin i-big' }\" v-model=\"showDropdown\" class=\"relative\">\n <template #trigger>\n <Button color=\"transp\" size=\"medium\" class=\"w-3r h-3r radius-full\">\n <IconEllipsis class=\"w-1-25r h-1-25r\" />\n </Button>\n </template>\n <template #default>\n <div class=\"dropdown-menu bg-white pd-small radius-medium shadow-big mn-t-thin\">\n <Button @click=\"addToQueue\" color=\"transp\" size=\"small\" class=\"w-100 justify-start\">\n Add to Queue\n </Button>\n <Button @click=\"copyLink\" color=\"transp\" size=\"small\" class=\"w-100 justify-start\">\n Copy Link\n </Button>\n <template v-if=\"isOwner || isCollaborator\">\n <hr class=\"mn-v-thin border-dark-transp-10\" />\n <Button @click=\"editPlaylist\" color=\"transp\" size=\"small\" class=\"w-100 justify-start\">\n Edit Playlist\n </Button>\n <Button v-if=\"isOwner\" @click=\"toggleCollaborative\" color=\"transp\" size=\"small\" class=\"w-100 justify-start\">\n {{ playlist.isCollaborative ? 'Make Private' : 'Make Collaborative' }}\n </Button>\n <Button v-if=\"isOwner\" @click=\"deletePlaylist\" color=\"danger\" size=\"small\" class=\"w-100 justify-start\">\n Delete Playlist\n </Button>\n </template>\n </div>\n </template>\n </Dropdown>\n </div>\n\n <!-- Owner/Creator Card -->\n <div class=\"owner-section mn-b-big\">\n <h3 class=\"t-medium mn-b-small\">Created by</h3>\n <div class=\"owner-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <router-link \n :to=\"getOwnerProfileLink(playlist.creator || playlist.owner)\"\n class=\"flex items-center gap-medium flex-1 hover-opacity\"\n >\n <div class=\"owner-avatar\">\n <Media \n v-if=\"getOwnerData(playlist)?.photoUrl\"\n :url=\"getOwnerData(playlist).photoUrl\"\n :alt=\"getOwnerData(playlist)?.name\"\n class=\"w-4r h-4r radius-full object-cover\"\n />\n <div v-else class=\"w-4r h-4r radius-full bg-primary flex-center \">\n {{ getPlaylistOwnerName(playlist).charAt(0) }}\n </div>\n </div>\n <div>\n <div class=\"flex items-center gap-thin\">\n <span class=\"t-large \">{{ getPlaylistOwnerName(playlist) }}</span>\n <IconVerified v-if=\"getOwnerData(playlist)?.isVerified\" class=\"w-1r h-1r t-primary\" />\n </div>\n <span class=\"t-small t-transp\">{{ playlist.creator?.type || 'User' }}</span>\n </div>\n </router-link>\n <Button \n v-if=\"!isOwner && authState.user\"\n @click=\"() => toggleFollowUser(getOwnerId(playlist))\"\n :color=\"followedUsers.includes(getOwnerId(playlist)) ? 'primary' : 'transp'\"\n size=\"small\"\n >\n {{ followedUsers.includes(getOwnerId(playlist)) ? 'Following' : 'Follow' }}\n </Button>\n </div>\n </div>\n\n <!-- Collaborators -->\n <div v-if=\"playlist.collaborators && playlist.collaborators.length > 0\" class=\"collaborators-section mn-b-big\">\n <h3 class=\"t-medium mn-b-small\">Collaborators</h3>\n <div class=\"flex flex-wrap gap-small\">\n <div \n v-for=\"collaborator in playlist.collaborators\"\n :key=\"collaborator._id || collaborator\"\n class=\"collaborator-chip bg-light pd-thin-big radius-full flex items-center gap-thin\"\n >\n <Media \n v-if=\"collaborator.photoUrl\"\n :url=\"collaborator.photoUrl\"\n class=\"i-regular radius-full object-cover\"\n />\n <span class=\"t-small\">{{ collaborator.name || collaborator.profile?.name || 'User' }}</span>\n </div>\n </div>\n </div>\n\n <!-- Metadata Cards -->\n <div class=\"metadata-grid grid cols-2 gap-small mn-b-big\">\n <!-- Created Date -->\n <div class=\"metadata-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <IconCalendar class=\"i-medium t-primary\" />\n <div>\n <div class=\"t-small t-transp t-uppercase\">Created</div>\n <div class=\"t-medium \">{{ formatDate(playlist.createdAt) }}</div>\n </div>\n </div>\n\n <!-- Total Duration -->\n <div class=\"metadata-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <IconClock class=\"i-medium t-primary\" />\n <div>\n <div class=\"t-small t-transp t-uppercase\">Duration</div>\n <div class=\"t-medium \">{{ totalDuration }}</div>\n </div>\n </div>\n\n <!-- Updated Date -->\n <div class=\"metadata-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <IconRefresh class=\"i-medium t-primary\" />\n <div>\n <div class=\"t-small t-transp t-uppercase\">Updated</div>\n <div class=\"t-medium \">{{ formatDate(playlist.updatedAt) }}</div>\n </div>\n </div>\n\n <!-- Visibility -->\n <div class=\"metadata-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <IconEye class=\"i-medium t-primary\" />\n <div>\n <div class=\"t-small t-transp t-uppercase\">Visibility</div>\n <div class=\"t-medium \">{{ playlist.isPublic ? 'Public' : 'Private' }}</div>\n </div>\n </div>\n </div>\n\n <!-- Tags -->\n <div v-if=\"playlist.tags && playlist.tags.length\" class=\"tags-section mn-b-medium\">\n <h3 class=\"t-medium mn-b-small\">Tags</h3>\n <div class=\"flex gap-thin flex-wrap\">\n <span \n v-for=\"tag in playlist.tags\" \n :key=\"tag\"\n class=\"tag bg-light t-transp pd-thin-big radius-small t-small hover-bg-light cursor-pointer\"\n >\n #{{ tag }}\n </span>\n </div>\n </div>\n\n <!-- Description -->\n <div v-if=\"playlist.description\" class=\"description-section bg-light pd-medium radius-medium mn-b-medium\">\n <h3 class=\"t-medium mn-b-small\">About</h3>\n <p class=\"t-transp\">{{ playlist.description }}</p>\n </div>\n </div>\n </div>\n\n <!-- Playlist Tracks -->\n <section v-if=\"!isLoading && playlist && playlistTracks.length\" class=\"tracks-section mn-t-big\">\n <h2 class=\"h2 mn-b-medium\">Tracklist</h2>\n <Feed\n :store=\"{\n read: () => Promise.resolve(playlistTracks),\n state: { isLoading: false }\n }\"\n :external=\"true\"\n :items=\"playlistTracks\"\n :states=\"{\n empty: {\n title: 'No tracks in playlist',\n description: 'Add some tracks to get started',\n class: 'pd-medium t-center'\n }\n }\"\n >\n <template #default=\"{ items }\">\n <div class=\"bg-light radius-medium o-hidden\">\n <TrackListCard\n v-for=\"(track, index) in items\"\n :key=\"track._id\"\n :track=\"track\"\n :index=\"index + 1\"\n :showAlbum=\"true\"\n :showCover=\"true\"\n :canRemove=\"isOwner || isCollaborator\"\n @remove=\"() => removeTrack(track._id)\"\n />\n </div>\n </template>\n </Feed>\n </section>\n\n <!-- Empty State -->\n <section v-else-if=\"!isLoading && playlist && !playlistTracks.length\" class=\"empty-section mn-t-big\">\n <div class=\"empty-tracks t-center pd-big bg-light radius-medium\">\n <h3 class=\" mn-b-small\">This playlist is empty</h3>\n <p class=\"t-transp t-medium mn-b-medium\">Add some tracks to get started</p>\n \n <Button \n v-if=\"isOwner || isCollaborator\"\n @click=\"$router.push({ name: 'music-search' })\"\n color=\"primary\"\n size=\"medium\"\n >\n Find Tracks\n </Button>\n </div>\n </section>\n\n <!-- More Playlists -->\n <section v-if=\"!isLoading && playlist && morePlaylists.length\" class=\"more-playlists-section mn-t-big\">\n <div class=\"flex justify-between items-center mn-b-medium\">\n <h2 class=\"h2\">More Playlists</h2>\n <router-link \n v-if=\"playlist.creator\"\n :to=\"getOwnerProfileLink(playlist.creator)\" \n class=\"t-primary hover-opacity\"\n >\n See all\n </router-link>\n </div>\n <div class=\"flex flex-nowrap gap-small o-x-scroll overscroll-behavior-x-contain scroll-behavior-smooth scroll-snap-type-x-mandatory scroll-hide\">\n <li v-for=\"relatedPlaylist in morePlaylists\" :key=\"relatedPlaylist._id\" class=\"flex-none scroll-snap-align-start\">\n <PlaylistCard :playlist=\"relatedPlaylist\" class=\"w-min-15r transition-cubic-in-out\" />\n </li>\n </div>\n </section>\n\n <!-- Edit Playlist Modal -->\n <Popup \n :isPopupOpen=\"showEditModal && (isOwner || isCollaborator)\"\n @close-popup=\"showEditModal = false\" \n class=\"bg-white pd-medium w-m-30r radius-medium\"\n >\n <PlaylistForm \n :editMode=\"true\"\n :url=\"playlist.url\"\n @cancel=\"showEditModal = false\"\n @updated=\"handlePlaylistUpdated\"\n />\n </Popup>\n\n <!-- Delete Confirmation Modal -->\n <Popup \n :isPopupOpen=\"showDeleteModal\"\n @close-popup=\"showDeleteModal = false\" \n class=\"bg-white pd-medium w-m-25r radius-medium\"\n >\n <h3 class=\"mn-b-medium\">Delete Playlist</h3>\n <p class=\"t-transp mn-b-medium\">Are you sure you want to delete \"{{ playlist.title }}\"? This action cannot be undone.</p>\n \n <div class=\"flex justify-end gap-small\">\n <Button \n @click=\"showDeleteModal = false\"\n color=\"transp\"\n size=\"medium\"\n >\n Cancel\n </Button>\n \n <Button \n @click=\"confirmDelete\"\n color=\"danger\"\n size=\"medium\"\n >\n Delete Playlist\n </Button>\n </div>\n </Popup>\n </div>\n</template>\n\n<script setup>\nimport { ref, computed, onMounted, watch } from 'vue';\nimport { useRoute, useRouter } from 'vue-router';\nimport Button from '@martyrs/src/components/Button/Button.vue';\nimport Loader from '@martyrs/src/components/Loader/Loader.vue';\nimport Media from '@martyrs/src/components/Media/Media.vue';\nimport Dropdown from '@martyrs/src/components/Dropdown/Dropdown.vue';\nimport Feed from '@martyrs/src/components/Feed/Feed.vue';\nimport Popup from '@martyrs/src/components/Popup/Popup.vue';\n\n// Icons\nimport IconPlay from '@martyrs/src/modules/icons/navigation/IconPlay.vue';\nimport IconLike from '@martyrs/src/modules/icons/navigation/IconLike.vue';\nimport IconEllipsis from '@martyrs/src/modules/icons/navigation/IconEllipsis.vue';\nimport IconShuffle from '@martyrs/src/modules/icons/navigation/IconShuffle.vue';\nimport IconCalendar from '@martyrs/src/modules/icons/entities/IconCalendar.vue';\nimport IconClock from '@martyrs/src/modules/icons/entities/IconTime.vue';\nimport IconEye from '@martyrs/src/modules/icons/actions/IconShow.vue';\nimport IconRefresh from '@martyrs/src/modules/icons/navigation/IconRefresh.vue';\nimport IconVerified from '@martyrs/src/modules/icons/navigation/IconCheckmark.vue';\n\n// Components\nimport TrackListCard from '../cards/TrackListCard.vue';\nimport PlaylistCard from '../cards/PlaylistCard.vue';\nimport PlaylistForm from '../forms/PlaylistForm.vue';\n\n// Store\nimport { state as playlistsState, actions as playlistsActions } from '../../store/playlists.js';\nimport { state as tracksState, actions as tracksActions } from '../../store/tracks.js';\nimport { actions as playerActions } from '../../store/player.js';\nimport { state as authState } from '@martyrs/src/modules/auth/views/store/auth.js';\nimport * as globals from '@martyrs/src/modules/globals/views/store/globals.js';\n\nconst route = useRoute();\nconst router = useRouter();\n\n// Emits\nconst emits = defineEmits(['page-loading', 'page-loaded']);\n\n// State\nconst hasLoaded = ref(false);\nconst isFollowing = ref(false);\nconst showDropdown = ref(false);\nconst showEditModal = ref(false);\nconst showDeleteModal = ref(false);\nconst followedUsers = ref([]);\nconst morePlaylists = ref([]);\n\n// Clear state\nplaylistsState.currentPlaylist = null;\nplaylistsState.currentPlaylistTracks = [];\n\n// Computed\nconst playlist = computed(() => playlistsState.currentPlaylist);\nconst playlistTracks = computed(() => playlistsState.currentPlaylistTracks || []);\n\nconst isOwner = computed(() => {\n if (!playlist.value || !authState.user) return false;\n \n const ownerId = playlist.value.owner?.target?._id || playlist.value.owner?.target;\n return ownerId === authState.user._id;\n});\n\nconst isCollaborator = computed(() => {\n if (!playlist.value || !authState.user) return false;\n \n return playlist.value.collaborators?.some(collab => \n (collab._id || collab) === authState.user._id\n );\n});\n\nconst totalDuration = computed(() => {\n if (!playlistTracks.value.length) return '0:00';\n const totalSeconds = playlistTracks.value.reduce((sum, track) => sum + (track.duration || 0), 0);\n return formatDuration(totalSeconds);\n});\n\n// Helper functions\nconst getOwnerData = (playlist) => {\n if (!playlist) return null;\n const owner = playlist.creator?.target || playlist.owner?.target;\n return typeof owner === 'object' ? owner : null;\n};\n\nconst getOwnerId = (playlist) => {\n if (!playlist) return null;\n const owner = playlist.creator?.target || playlist.owner?.target;\n return typeof owner === 'object' ? owner._id : owner;\n};\n\nconst getPlaylistOwnerName = (playlist) => {\n if (!playlist) return 'Unknown';\n \n const owner = getOwnerData(playlist);\n if (owner) {\n return owner.profile?.name || owner.name || 'Unknown';\n }\n \n return 'Unknown';\n};\n\nconst getOwnerProfileLink = (owner) => {\n if (!owner || !owner.target) return { name: 'music-home' };\n \n const targetId = typeof owner.target === 'object' ? owner.target._id : owner.target;\n \n if (owner.type === 'user' || owner.type === 'User') {\n return { name: 'User Profile', params: { _id: targetId } };\n } else if (owner.type === 'organization' || owner.type === 'Organization') {\n return { name: 'Organizatio', params: { _id: targetId } };\n }\n \n return { name: 'music-home' };\n};\n\n// Format helpers\nconst formatDate = (dateString) => {\n if (!dateString) return 'Unknown';\n return new Date(dateString).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric'\n });\n};\n\nconst formatDuration = (seconds) => {\n if (!seconds) return '0:00';\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n \n if (h > 0) {\n return `${h}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;\n }\n return `${m}:${s.toString().padStart(2, '0')}`;\n};\n\nconst formatNumber = (num) => {\n if (!num) return '0';\n if (num >= 1000000) {\n return (num / 1000000).toFixed(1) + 'M';\n } else if (num >= 1000) {\n return (num / 1000).toFixed(1) + 'K';\n }\n return num.toString();\n};\n\n// Actions\nconst playPlaylist = () => {\n if (playlistTracks.value && playlistTracks.value.length > 0) {\n playerActions.setQueue(playlistTracks.value);\n }\n};\n\nconst shufflePlay = () => {\n if (playlistTracks.value && playlistTracks.value.length > 0) {\n const shuffled = [...playlistTracks.value].sort(() => Math.random() - 0.5);\n playerActions.setQueue(shuffled);\n }\n};\n\nconst toggleFollow = async () => {\n isFollowing.value = !isFollowing.value;\n // TODO: Implement actual following\n try {\n if (isFollowing.value) {\n await playlistsActions.followPlaylist(playlist.value._id);\n } else {\n await playlistsActions.unfollowPlaylist(playlist.value._id);\n }\n } catch (error) {\n console.error('Error toggling follow:', error);\n isFollowing.value = !isFollowing.value; // Revert on error\n }\n};\n\nconst toggleFollowUser = (userId) => {\n const index = followedUsers.value.indexOf(userId);\n if (index > -1) {\n followedUsers.value.splice(index, 1);\n } else {\n followedUsers.value.push(userId);\n }\n // TODO: Implement actual following\n};\n\nconst addToQueue = () => {\n if (playlistTracks.value && playlistTracks.value.length > 0) {\n playlistTracks.value.forEach(track => {\n playerActions.addToQueue(track);\n });\n showDropdown.value = false;\n }\n};\n\nconst editPlaylist = () => {\n showEditModal.value = true;\n showDropdown.value = false;\n};\n\nconst toggleCollaborative = async () => {\n try {\n const updatedData = {\n _id: playlist.value._id,\n isCollaborative: !playlist.value.isCollaborative\n };\n \n await playlistsActions.updatePlaylist(updatedData);\n showDropdown.value = false;\n } catch (error) {\n console.error('Error updating playlist:', error);\n }\n};\n\nconst deletePlaylist = () => {\n showDeleteModal.value = true;\n showDropdown.value = false;\n};\n\nconst confirmDelete = async () => {\n try {\n await playlistsActions.deletePlaylist(playlist.value._id);\n router.push({ name: 'music-library' });\n } catch (error) {\n console.error('Error deleting playlist:', error);\n globals.actions.setError({\n message: 'Failed to delete playlist'\n });\n }\n};\n\nconst removeTrack = async (trackId) => {\n try {\n await playlistsActions.removeTrackFromPlaylist(playlist.value._id, trackId);\n // Refresh playlist data\n await fetchPlaylistData();\n } catch (error) {\n console.error('Error removing track:', error);\n globals.actions.setError({\n message: 'Failed to remove track'\n });\n }\n};\n\nconst copyLink = () => {\n navigator.clipboard.writeText(window.location.href);\n showDropdown.value = false;\n};\n\nconst handlePlaylistUpdated = () => {\n showEditModal.value = false;\n fetchPlaylistData();\n};\n\n// Data fetching\nconst fetchPlaylistData = async () => {\n try {\n await playlistsActions.fetchPlaylistByUrl(route.params.url);\n \n // Check if following\n if (authState.user && playlist.value) {\n // TODO: Check if user is following this playlist\n }\n \n // Fetch more playlists from the same creator\n if (playlist.value?.creator?.target) {\n const creatorId = typeof playlist.value.creator.target === 'object' \n ? playlist.value.creator.target._id \n : playlist.value.creator.target;\n \n const playlists = await playlistsActions.fetchPlaylists({\n 'creator.target': creatorId,\n isPublic: true,\n limit: 6\n });\n \n // Filter out current playlist\n morePlaylists.value = playlists.filter(p => p._id !== playlist.value._id).slice(0, 5);\n }\n } catch (error) {\n console.error('Error fetching playlist data:', error);\n }\n};\n\n// Lifecycle\nonMounted(async () => {\n emits('page-loading');\n \n await fetchPlaylistData();\n \n hasLoaded.value = true;\n emits('page-loaded');\n});\n</script>"],"names":["playlistsState","authState","playlist","playerActions","playlistsActions","globals.actions"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6XA,UAAM,QAAQ,SAAQ;AACtB,UAAM,SAAS,UAAS;AAGxB,UAAM,QAAQ;AAGd,UAAM,YAAY,IAAI,KAAK;AAC3B,UAAM,cAAc,IAAI,KAAK;AAC7B,UAAM,eAAe,IAAI,KAAK;AAC9B,UAAM,gBAAgB,IAAI,KAAK;AAC/B,UAAM,kBAAkB,IAAI,KAAK;AACjC,UAAM,gBAAgB,IAAI,EAAE;AAC5B,UAAM,gBAAgB,IAAI,EAAE;AAG5BA,UAAe,kBAAkB;AACjCA,UAAe,wBAAwB,CAAA;AAGvC,UAAM,WAAW,SAAS,MAAMA,MAAe,eAAe;AAC9D,UAAM,iBAAiB,SAAS,MAAMA,MAAe,yBAAyB,CAAA,CAAE;AAEhF,UAAM,UAAU,SAAS,MAAM;AAC7B,UAAI,CAAC,SAAS,SAAS,CAACC,QAAU,KAAM,QAAO;AAE/C,YAAM,UAAU,SAAS,MAAM,OAAO,QAAQ,OAAO,SAAS,MAAM,OAAO;AAC3E,aAAO,YAAYA,QAAU,KAAK;AAAA,IACpC,CAAC;AAED,UAAM,iBAAiB,SAAS,MAAM;AACpC,UAAI,CAAC,SAAS,SAAS,CAACA,QAAU,KAAM,QAAO;AAE/C,aAAO,SAAS,MAAM,eAAe;AAAA,QAAK,aACvC,OAAO,OAAO,YAAYA,QAAU,KAAK;AAAA,MAC9C;AAAA,IACA,CAAC;AAED,UAAM,gBAAgB,SAAS,MAAM;AACnC,UAAI,CAAC,eAAe,MAAM,OAAQ,QAAO;AACzC,YAAM,eAAe,eAAe,MAAM,OAAO,CAAC,KAAK,UAAU,OAAO,MAAM,YAAY,IAAI,CAAC;AAC/F,aAAO,eAAe,YAAY;AAAA,IACpC,CAAC;AAGD,UAAM,eAAe,CAACC,cAAa;AACjC,UAAI,CAACA,UAAU,QAAO;AACtB,YAAM,QAAQA,UAAS,SAAS,UAAUA,UAAS,OAAO;AAC1D,aAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,IAC7C;AAEA,UAAM,aAAa,CAACA,cAAa;AAC/B,UAAI,CAACA,UAAU,QAAO;AACtB,YAAM,QAAQA,UAAS,SAAS,UAAUA,UAAS,OAAO;AAC1D,aAAO,OAAO,UAAU,WAAW,MAAM,MAAM;AAAA,IACjD;AAEA,UAAM,uBAAuB,CAACA,cAAa;AACzC,UAAI,CAACA,UAAU,QAAO;AAEtB,YAAM,QAAQ,aAAaA,SAAQ;AACnC,UAAI,OAAO;AACT,eAAO,MAAM,SAAS,QAAQ,MAAM,QAAQ;AAAA,MAC9C;AAEA,aAAO;AAAA,IACT;AAEA,UAAM,sBAAsB,CAAC,UAAU;AACrC,UAAI,CAAC,SAAS,CAAC,MAAM,OAAQ,QAAO,EAAE,MAAM,aAAY;AAExD,YAAM,WAAW,OAAO,MAAM,WAAW,WAAW,MAAM,OAAO,MAAM,MAAM;AAE9E,UAAI,MAAM,SAAS,UAAU,MAAM,SAAS,QAAQ;AACjD,eAAO,EAAE,MAAM,gBAAgB,QAAQ,EAAE,KAAK,WAAU;AAAA,MAC1D,WAAW,MAAM,SAAS,kBAAkB,MAAM,SAAS,gBAAgB;AACzE,eAAO,EAAE,MAAM,eAAe,QAAQ,EAAE,KAAK,WAAU;AAAA,MACzD;AAEA,aAAO,EAAE,MAAM,aAAY;AAAA,IAC7B;AAGA,UAAM,aAAa,CAAC,eAAe;AACjC,UAAI,CAAC,WAAY,QAAO;AACxB,aAAO,IAAI,KAAK,UAAU,EAAE,mBAAmB,SAAS;AAAA,QACtD,MAAM;AAAA,QACN,OAAO;AAAA,QACP,KAAK;AAAA,MACT,CAAG;AAAA,IACH;AAEA,UAAM,iBAAiB,CAAC,YAAY;AAClC,UAAI,CAAC,QAAS,QAAO;AACrB,YAAM,IAAI,KAAK,MAAM,UAAU,IAAI;AACnC,YAAM,IAAI,KAAK,MAAO,UAAU,OAAQ,EAAE;AAC1C,YAAM,IAAI,KAAK,MAAM,UAAU,EAAE;AAEjC,UAAI,IAAI,GAAG;AACT,eAAO,GAAG,CAAC,IAAI,EAAE,SAAQ,EAAG,SAAS,GAAG,GAAG,CAAC,IAAI,EAAE,SAAQ,EAAG,SAAS,GAAG,GAAG,CAAC;AAAA,MAC/E;AACA,aAAO,GAAG,CAAC,IAAI,EAAE,SAAQ,EAAG,SAAS,GAAG,GAAG,CAAC;AAAA,IAC9C;AAEA,UAAM,eAAe,CAAC,QAAQ;AAC5B,UAAI,CAAC,IAAK,QAAO;AACjB,UAAI,OAAO,KAAS;AAClB,gBAAQ,MAAM,KAAS,QAAQ,CAAC,IAAI;AAAA,MACtC,WAAW,OAAO,KAAM;AACtB,gBAAQ,MAAM,KAAM,QAAQ,CAAC,IAAI;AAAA,MACnC;AACA,aAAO,IAAI,SAAQ;AAAA,IACrB;AAGA,UAAM,eAAe,MAAM;AACzB,UAAI,eAAe,SAAS,eAAe,MAAM,SAAS,GAAG;AAC3DC,kBAAc,SAAS,eAAe,KAAK;AAAA,MAC7C;AAAA,IACF;AAEA,UAAM,cAAc,MAAM;AACxB,UAAI,eAAe,SAAS,eAAe,MAAM,SAAS,GAAG;AAC3D,cAAM,WAAW,CAAC,GAAG,eAAe,KAAK,EAAE,KAAK,MAAM,KAAK,OAAM,IAAK,GAAG;AACzEA,kBAAc,SAAS,QAAQ;AAAA,MACjC;AAAA,IACF;AAEA,UAAM,eAAe,YAAY;AAC/B,kBAAY,QAAQ,CAAC,YAAY;AAEjC,UAAI;AACF,YAAI,YAAY,OAAO;AACrB,gBAAMC,QAAiB,eAAe,SAAS,MAAM,GAAG;AAAA,QAC1D,OAAO;AACL,gBAAMA,QAAiB,iBAAiB,SAAS,MAAM,GAAG;AAAA,QAC5D;AAAA,MACF,SAAS,OAAO;AACd,gBAAQ,MAAM,0BAA0B,KAAK;AAC7C,oBAAY,QAAQ,CAAC,YAAY;AAAA,MACnC;AAAA,IACF;AAEA,UAAM,mBAAmB,CAAC,WAAW;AACnC,YAAM,QAAQ,cAAc,MAAM,QAAQ,MAAM;AAChD,UAAI,QAAQ,IAAI;AACd,sBAAc,MAAM,OAAO,OAAO,CAAC;AAAA,MACrC,OAAO;AACL,sBAAc,MAAM,KAAK,MAAM;AAAA,MACjC;AAAA,IAEF;AAEA,UAAM,aAAa,MAAM;AACvB,UAAI,eAAe,SAAS,eAAe,MAAM,SAAS,GAAG;AAC3D,uBAAe,MAAM,QAAQ,WAAS;AACpCD,oBAAc,WAAW,KAAK;AAAA,QAChC,CAAC;AACD,qBAAa,QAAQ;AAAA,MACvB;AAAA,IACF;AAEA,UAAM,eAAe,MAAM;AACzB,oBAAc,QAAQ;AACtB,mBAAa,QAAQ;AAAA,IACvB;AAEA,UAAM,sBAAsB,YAAY;AACtC,UAAI;AACF,cAAM,cAAc;AAAA,UAClB,KAAK,SAAS,MAAM;AAAA,UACpB,iBAAiB,CAAC,SAAS,MAAM;AAAA,QACvC;AAEI,cAAMC,QAAiB,eAAe,WAAW;AACjD,qBAAa,QAAQ;AAAA,MACvB,SAAS,OAAO;AACd,gBAAQ,MAAM,4BAA4B,KAAK;AAAA,MACjD;AAAA,IACF;AAEA,UAAM,iBAAiB,MAAM;AAC3B,sBAAgB,QAAQ;AACxB,mBAAa,QAAQ;AAAA,IACvB;AAEA,UAAM,gBAAgB,YAAY;AAChC,UAAI;AACF,cAAMA,QAAiB,eAAe,SAAS,MAAM,GAAG;AACxD,eAAO,KAAK,EAAE,MAAM,gBAAe,CAAE;AAAA,MACvC,SAAS,OAAO;AACd,gBAAQ,MAAM,4BAA4B,KAAK;AAC/CC,kBAAgB,SAAS;AAAA,UACvB,SAAS;AAAA,QACf,CAAK;AAAA,MACH;AAAA,IACF;AAEA,UAAM,cAAc,OAAO,YAAY;AACrC,UAAI;AACF,cAAMD,QAAiB,wBAAwB,SAAS,MAAM,KAAK,OAAO;AAE1E,cAAM,kBAAiB;AAAA,MACzB,SAAS,OAAO;AACd,gBAAQ,MAAM,yBAAyB,KAAK;AAC5CC,kBAAgB,SAAS;AAAA,UACvB,SAAS;AAAA,QACf,CAAK;AAAA,MACH;AAAA,IACF;AAEA,UAAM,WAAW,MAAM;AACrB,gBAAU,UAAU,UAAU,OAAO,SAAS,IAAI;AAClD,mBAAa,QAAQ;AAAA,IACvB;AAEA,UAAM,wBAAwB,MAAM;AAClC,oBAAc,QAAQ;AACtB,wBAAiB;AAAA,IACnB;AAGA,UAAM,oBAAoB,YAAY;AACpC,UAAI;AACF,cAAMD,QAAiB,mBAAmB,MAAM,OAAO,GAAG;AAG1D,YAAIH,QAAU,QAAQ,SAAS,OAAO;AAAA,QAEtC;AAGA,YAAI,SAAS,OAAO,SAAS,QAAQ;AACnC,gBAAM,YAAY,OAAO,SAAS,MAAM,QAAQ,WAAW,WACvD,SAAS,MAAM,QAAQ,OAAO,MAC9B,SAAS,MAAM,QAAQ;AAE3B,gBAAM,YAAY,MAAMG,QAAiB,eAAe;AAAA,YACtD,kBAAkB;AAAA,YAClB,UAAU;AAAA,YACV,OAAO;AAAA,UACf,CAAO;AAGD,wBAAc,QAAQ,UAAU,OAAO,OAAK,EAAE,QAAQ,SAAS,MAAM,GAAG,EAAE,MAAM,GAAG,CAAC;AAAA,QACtF;AAAA,MACF,SAAS,OAAO;AACd,gBAAQ,MAAM,iCAAiC,KAAK;AAAA,MACtD;AAAA,IACF;AAGA,cAAU,YAAY;AACpB,YAAM,cAAc;AAEpB,YAAM,kBAAiB;AAEvB,gBAAU,QAAQ;AAClB,YAAM,aAAa;AAAA,IACrB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -161,7 +161,7 @@ const _sfc_main = {
161
161
  key: filter.id,
162
162
  onClick: ($event) => setActiveFilter(filter.id),
163
163
  class: vue.normalizeClass([[
164
- filter.id === activeFilter.value ? "bg-white t-black" : "bg-dark-transp-50 hover-bg-dark"
164
+ filter.id === activeFilter.value ? "bg-white t-black" : "bg-white-transp-50 hover-bg-white"
165
165
  ], "radius-extra pd-small"]),
166
166
  showLoader: false,
167
167
  showSucces: false
@@ -191,7 +191,7 @@ const _sfc_main = {
191
191
  trackResults.value.length > 5 && activeFilter.value === "all" ? (vue.openBlock(), vue.createBlock(Button.default, {
192
192
  key: 0,
193
193
  onClick: _cache[0] || (_cache[0] = ($event) => setActiveFilter("tracks")),
194
- class: "t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin",
194
+ class: "t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin",
195
195
  showLoader: false,
196
196
  showSucces: false
197
197
  }, {
@@ -219,7 +219,7 @@ const _sfc_main = {
219
219
  artistResults.value.length > 6 && activeFilter.value === "all" ? (vue.openBlock(), vue.createBlock(Button.default, {
220
220
  key: 0,
221
221
  onClick: _cache[1] || (_cache[1] = ($event) => setActiveFilter("artists")),
222
- class: "t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin",
222
+ class: "t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin",
223
223
  showLoader: false,
224
224
  showSucces: false
225
225
  }, {
@@ -245,7 +245,7 @@ const _sfc_main = {
245
245
  albumResults.value.length > 5 && activeFilter.value === "all" ? (vue.openBlock(), vue.createBlock(Button.default, {
246
246
  key: 0,
247
247
  onClick: _cache[2] || (_cache[2] = ($event) => setActiveFilter("albums")),
248
- class: "t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin",
248
+ class: "t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin",
249
249
  showLoader: false,
250
250
  showSucces: false
251
251
  }, {
@@ -271,7 +271,7 @@ const _sfc_main = {
271
271
  playlistResults.value.length > 5 && activeFilter.value === "all" ? (vue.openBlock(), vue.createBlock(Button.default, {
272
272
  key: 0,
273
273
  onClick: _cache[3] || (_cache[3] = ($event) => setActiveFilter("playlists")),
274
- class: "t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin",
274
+ class: "t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin",
275
275
  showLoader: false,
276
276
  showSucces: false
277
277
  }, {
@@ -297,7 +297,7 @@ const _sfc_main = {
297
297
  genreResults.value.length > 4 && activeFilter.value === "all" ? (vue.openBlock(), vue.createBlock(Button.default, {
298
298
  key: 0,
299
299
  onClick: _cache[4] || (_cache[4] = ($event) => setActiveFilter("genres")),
300
- class: "t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin",
300
+ class: "t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin",
301
301
  showLoader: false,
302
302
  showSucces: false
303
303
  }, {
@@ -330,6 +330,6 @@ const _sfc_main = {
330
330
  };
331
331
  }
332
332
  };
333
- const SearchResults = /* @__PURE__ */ _pluginVue_exportHelper.default(_sfc_main, [["__scopeId", "data-v-464383f0"]]);
333
+ const SearchResults = /* @__PURE__ */ _pluginVue_exportHelper.default(_sfc_main, [["__scopeId", "data-v-e47a0d68"]]);
334
334
  exports.default = SearchResults;
335
335
  //# sourceMappingURL=SearchResults.vue.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"SearchResults.vue.cjs","sources":["../../../../../../../src/modules/music/components/pages/SearchResults.vue"],"sourcesContent":["<!-- components/pages/SearchResults.vue -->\n<template>\n <div class=\"search-results-page pd-medium\">\n <div class=\"search-header mn-b-medium\">\n <h1 class=\"mn-b-small\">Search</h1>\n \n <BlockSearch \n :placeholder=\"'What do you want to listen to?'\"\n class=\"bg-light w-m-40r\"\n @search=\"handleSearch\"\n :autofocus=\"true\"\n />\n \n <div v-if=\"searchQuery\" class=\"search-filters flex gap-small mn-t-medium\">\n <Button \n v-for=\"filter in searchFilters\"\n :key=\"filter.id\"\n @click=\"setActiveFilter(filter.id)\"\n :class=\"[\n filter.id === activeFilter ? 'bg-white t-black' : 'bg-dark-transp-50 hover-bg-dark',\n ]\"\n class=\"radius-extra pd-small\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n {{ filter.label }}\n </Button>\n </div>\n </div>\n \n <div v-if=\"isLoading\" class=\"search-loading\">\n <Loader />\n </div>\n \n <div v-else-if=\"searchError\" class=\"search-error t-center pd-big\">\n <p class=\"t-fourth t-medium\">{{ searchError }}</p>\n </div>\n \n <div v-else-if=\"!searchQuery\" class=\"search-empty t-center pd-big\">\n <h2 class=\"mn-b-small\">Search for music</h2>\n <p class=\"t-transp t-medium\">Find your favorite songs, artists, albums, and playlists</p>\n </div>\n \n <div v-else-if=\"!hasResults\" class=\"search-no-results t-center pd-big\">\n <h2 class=\"mn-b-small\">No results found for \"{{ searchQuery }}\"</h2>\n <p class=\"t-transp t-medium\">Please try different keywords or check your spelling</p>\n </div>\n \n <div v-else class=\"search-results\">\n <!-- Songs Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'tracks') && trackResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Songs</h2>\n <Button \n v-if=\"trackResults.length > 5 && activeFilter === 'all'\"\n @click=\"setActiveFilter('tracks')\"\n class=\"t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"bg-light radius-medium o-hidden\">\n <TrackListCard\n v-for=\"(track, index) in (activeFilter === 'all' ? trackResults.slice(0, 5) : trackResults)\"\n :key=\"track._id\"\n :track=\"track\"\n :index=\"index\"\n :showAlbum=\"true\"\n :showCover=\"true\"\n />\n </div>\n </section>\n \n <!-- Artists Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'artists') && artistResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Artists</h2>\n <Button \n v-if=\"artistResults.length > 6 && activeFilter === 'all'\"\n @click=\"setActiveFilter('artists')\"\n class=\"t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"artists-grid cols-6 mobile:cols-3 gap-small\">\n <div v-for=\"artist in (activeFilter === 'all' ? artistResults.slice(0, 6) : artistResults)\" :key=\"artist._id\">\n <ArtistCard :artist=\"artist\" />\n </div>\n </div>\n </section>\n \n <!-- Albums Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'albums') && albumResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Albums</h2>\n <Button \n v-if=\"albumResults.length > 5 && activeFilter === 'all'\"\n @click=\"setActiveFilter('albums')\"\n class=\"t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"albums-grid cols-5 mobile:cols-2 gap-small\">\n <div v-for=\"album in (activeFilter === 'all' ? albumResults.slice(0, 5) : albumResults)\" :key=\"album._id\">\n <AlbumCard :album=\"album\" />\n </div>\n </div>\n </section>\n \n <!-- Playlists Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'playlists') && playlistResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Playlists</h2>\n <Button \n v-if=\"playlistResults.length > 5 && activeFilter === 'all'\"\n @click=\"setActiveFilter('playlists')\"\n class=\"t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"playlists-grid cols-5 mobile:cols-2 gap-small\">\n <div v-for=\"playlist in (activeFilter === 'all' ? playlistResults.slice(0, 5) : playlistResults)\" :key=\"playlist._id\">\n <PlaylistCard :playlist=\"playlist\" />\n </div>\n </div>\n </section>\n \n <!-- Genres Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'genres') && genreResults.length > 0\" class=\"search-section\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Genres</h2>\n <Button \n v-if=\"genreResults.length > 4 && activeFilter === 'all'\"\n @click=\"setActiveFilter('genres')\"\n class=\"t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"genres-grid cols-4 mobile:cols-2 gap-small\">\n <router-link \n v-for=\"genre in (activeFilter === 'all' ? genreResults.slice(0, 4) : genreResults)\" \n :key=\"genre._id\"\n :to=\"{ name: 'genre-detail', params: { url: genre.url } }\"\n class=\"genre-card bg-gradient-color pd-medium radius-medium t-center hover-scale-1 transition-cubic-in-out\"\n :style=\"{ \n '--gradient-color': getRandomGradient() \n }\"\n >\n <h3 class=\"\">{{ genre.name }}</h3>\n </router-link>\n </div>\n </section>\n </div>\n </div>\n</template>\n\n<script setup>\nimport { ref, computed, onMounted, watch } from 'vue';\nimport { useRoute, useRouter } from 'vue-router';\nimport BlockSearch from '@martyrs/src/modules/globals/views/components/blocks/BlockSearch.vue';\nimport TrackListCard from '../cards/TrackListCard.vue';\nimport AlbumCard from '../cards/AlbumCard.vue';\nimport PlaylistCard from '../cards/PlaylistCard.vue';\nimport ArtistCard from '../cards/ArtistCard.vue';\nimport Button from '@martyrs/src/components/Button/Button.vue';\nimport Loader from '@martyrs/src/components/Loader/Loader.vue';\n\n// Import search store\nimport { state as searchState, actions as searchActions } from '../../store/search.js';\n\nconst route = useRoute();\nconst router = useRouter();\n\n// State\nconst searchQuery = ref('');\nconst activeFilter = ref('all');\n\n// Array of search filters\nconst searchFilters = [\n { id: 'all', label: 'All' },\n { id: 'tracks', label: 'Songs' },\n { id: 'artists', label: 'Artists' },\n { id: 'albums', label: 'Albums' },\n { id: 'playlists', label: 'Playlists' },\n { id: 'genres', label: 'Genres' }\n];\n\n// Computed properties\nconst isLoading = computed(() => searchState.isLoading);\nconst searchError = computed(() => searchState.error);\nconst hasResults = computed(() => {\n return trackResults.value.length > 0 || \n artistResults.value.length > 0 || \n albumResults.value.length > 0 || \n playlistResults.value.length > 0 || \n genreResults.value.length > 0;\n});\n\nconst trackResults = computed(() => searchState.results.tracks || []);\nconst artistResults = computed(() => searchState.results.artists || []);\nconst albumResults = computed(() => searchState.results.albums || []);\nconst playlistResults = computed(() => searchState.results.playlists || []);\nconst genreResults = computed(() => searchState.results.genres || []);\n\n// Methods\nconst handleSearch = (query) => {\n searchQuery.value = query;\n \n if (query.trim()) {\n // Update URL without reloading the page\n router.push({ \n name: 'music-search', \n query: { q: query },\n replace: true\n });\n \n // Perform search\n searchActions.search(query);\n } else {\n // Clear search when query is empty\n router.push({ \n name: 'music-search',\n replace: true\n });\n searchActions.clearSearch();\n }\n};\n\nconst setActiveFilter = (filter) => {\n activeFilter.value = filter;\n searchActions.setFilter(filter);\n};\n\n// Generate random gradient for genre cards\nconst getRandomGradient = () => {\n const colors = [\n 'linear-gradient(135deg, #1DB954, #1ED760)',\n 'linear-gradient(135deg, #FF6B6B, #FFE66D)',\n 'linear-gradient(135deg, #4776E6, #8E54E9)',\n 'linear-gradient(135deg, #FF8008, #FFC837)',\n 'linear-gradient(135deg, #7F00FF, #E100FF)',\n 'linear-gradient(135deg, #11998E, #38EF7D)'\n ];\n \n return colors[Math.floor(Math.random() * colors.length)];\n};\n\n// Watch for URL query parameter changes\nonMounted(() => {\n const query = route.query.q;\n if (query) {\n searchQuery.value = query;\n searchActions.search(query);\n }\n});\n\nwatch(() => route.query.q, (newQuery) => {\n if (newQuery && newQuery !== searchQuery.value) {\n searchQuery.value = newQuery;\n searchActions.search(newQuery);\n } else if (!newQuery) {\n searchQuery.value = '';\n searchActions.clearSearch();\n }\n});\n</script>\n\n<style scoped>\n.bg-gradient-color {\n background: var(--gradient-color, linear-gradient(135deg, #1DB954, #1ED760));\n}\n</style>"],"names":["useRoute","useRouter","ref","computed","searchState","searchActions","onMounted","watch"],"mappings":"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"}
1
+ {"version":3,"file":"SearchResults.vue.cjs","sources":["../../../../../../../src/modules/music/components/pages/SearchResults.vue"],"sourcesContent":["<!-- components/pages/SearchResults.vue -->\n<template>\n <div class=\"search-results-page pd-medium\">\n <div class=\"search-header mn-b-medium\">\n <h1 class=\"mn-b-small\">Search</h1>\n \n <BlockSearch \n :placeholder=\"'What do you want to listen to?'\"\n class=\"bg-light w-m-40r\"\n @search=\"handleSearch\"\n :autofocus=\"true\"\n />\n \n <div v-if=\"searchQuery\" class=\"search-filters flex gap-small mn-t-medium\">\n <Button \n v-for=\"filter in searchFilters\"\n :key=\"filter.id\"\n @click=\"setActiveFilter(filter.id)\"\n :class=\"[\n filter.id === activeFilter ? 'bg-white t-black' : 'bg-white-transp-50 hover-bg-white',\n ]\"\n class=\"radius-extra pd-small\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n {{ filter.label }}\n </Button>\n </div>\n </div>\n \n <div v-if=\"isLoading\" class=\"search-loading\">\n <Loader />\n </div>\n \n <div v-else-if=\"searchError\" class=\"search-error t-center pd-big\">\n <p class=\"t-fourth t-medium\">{{ searchError }}</p>\n </div>\n \n <div v-else-if=\"!searchQuery\" class=\"search-empty t-center pd-big\">\n <h2 class=\"mn-b-small\">Search for music</h2>\n <p class=\"t-transp t-medium\">Find your favorite songs, artists, albums, and playlists</p>\n </div>\n \n <div v-else-if=\"!hasResults\" class=\"search-no-results t-center pd-big\">\n <h2 class=\"mn-b-small\">No results found for \"{{ searchQuery }}\"</h2>\n <p class=\"t-transp t-medium\">Please try different keywords or check your spelling</p>\n </div>\n \n <div v-else class=\"search-results\">\n <!-- Songs Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'tracks') && trackResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Songs</h2>\n <Button \n v-if=\"trackResults.length > 5 && activeFilter === 'all'\"\n @click=\"setActiveFilter('tracks')\"\n class=\"t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"bg-light radius-medium o-hidden\">\n <TrackListCard\n v-for=\"(track, index) in (activeFilter === 'all' ? trackResults.slice(0, 5) : trackResults)\"\n :key=\"track._id\"\n :track=\"track\"\n :index=\"index\"\n :showAlbum=\"true\"\n :showCover=\"true\"\n />\n </div>\n </section>\n \n <!-- Artists Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'artists') && artistResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Artists</h2>\n <Button \n v-if=\"artistResults.length > 6 && activeFilter === 'all'\"\n @click=\"setActiveFilter('artists')\"\n class=\"t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"artists-grid cols-6 mobile:cols-3 gap-small\">\n <div v-for=\"artist in (activeFilter === 'all' ? artistResults.slice(0, 6) : artistResults)\" :key=\"artist._id\">\n <ArtistCard :artist=\"artist\" />\n </div>\n </div>\n </section>\n \n <!-- Albums Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'albums') && albumResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Albums</h2>\n <Button \n v-if=\"albumResults.length > 5 && activeFilter === 'all'\"\n @click=\"setActiveFilter('albums')\"\n class=\"t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"albums-grid cols-5 mobile:cols-2 gap-small\">\n <div v-for=\"album in (activeFilter === 'all' ? albumResults.slice(0, 5) : albumResults)\" :key=\"album._id\">\n <AlbumCard :album=\"album\" />\n </div>\n </div>\n </section>\n \n <!-- Playlists Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'playlists') && playlistResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Playlists</h2>\n <Button \n v-if=\"playlistResults.length > 5 && activeFilter === 'all'\"\n @click=\"setActiveFilter('playlists')\"\n class=\"t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"playlists-grid cols-5 mobile:cols-2 gap-small\">\n <div v-for=\"playlist in (activeFilter === 'all' ? playlistResults.slice(0, 5) : playlistResults)\" :key=\"playlist._id\">\n <PlaylistCard :playlist=\"playlist\" />\n </div>\n </div>\n </section>\n \n <!-- Genres Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'genres') && genreResults.length > 0\" class=\"search-section\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Genres</h2>\n <Button \n v-if=\"genreResults.length > 4 && activeFilter === 'all'\"\n @click=\"setActiveFilter('genres')\"\n class=\"t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"genres-grid cols-4 mobile:cols-2 gap-small\">\n <router-link \n v-for=\"genre in (activeFilter === 'all' ? genreResults.slice(0, 4) : genreResults)\" \n :key=\"genre._id\"\n :to=\"{ name: 'genre-detail', params: { url: genre.url } }\"\n class=\"genre-card bg-gradient-color pd-medium radius-medium t-center hover-scale-1 transition-cubic-in-out\"\n :style=\"{ \n '--gradient-color': getRandomGradient() \n }\"\n >\n <h3 class=\"\">{{ genre.name }}</h3>\n </router-link>\n </div>\n </section>\n </div>\n </div>\n</template>\n\n<script setup>\nimport { ref, computed, onMounted, watch } from 'vue';\nimport { useRoute, useRouter } from 'vue-router';\nimport BlockSearch from '@martyrs/src/modules/globals/views/components/blocks/BlockSearch.vue';\nimport TrackListCard from '../cards/TrackListCard.vue';\nimport AlbumCard from '../cards/AlbumCard.vue';\nimport PlaylistCard from '../cards/PlaylistCard.vue';\nimport ArtistCard from '../cards/ArtistCard.vue';\nimport Button from '@martyrs/src/components/Button/Button.vue';\nimport Loader from '@martyrs/src/components/Loader/Loader.vue';\n\n// Import search store\nimport { state as searchState, actions as searchActions } from '../../store/search.js';\n\nconst route = useRoute();\nconst router = useRouter();\n\n// State\nconst searchQuery = ref('');\nconst activeFilter = ref('all');\n\n// Array of search filters\nconst searchFilters = [\n { id: 'all', label: 'All' },\n { id: 'tracks', label: 'Songs' },\n { id: 'artists', label: 'Artists' },\n { id: 'albums', label: 'Albums' },\n { id: 'playlists', label: 'Playlists' },\n { id: 'genres', label: 'Genres' }\n];\n\n// Computed properties\nconst isLoading = computed(() => searchState.isLoading);\nconst searchError = computed(() => searchState.error);\nconst hasResults = computed(() => {\n return trackResults.value.length > 0 || \n artistResults.value.length > 0 || \n albumResults.value.length > 0 || \n playlistResults.value.length > 0 || \n genreResults.value.length > 0;\n});\n\nconst trackResults = computed(() => searchState.results.tracks || []);\nconst artistResults = computed(() => searchState.results.artists || []);\nconst albumResults = computed(() => searchState.results.albums || []);\nconst playlistResults = computed(() => searchState.results.playlists || []);\nconst genreResults = computed(() => searchState.results.genres || []);\n\n// Methods\nconst handleSearch = (query) => {\n searchQuery.value = query;\n \n if (query.trim()) {\n // Update URL without reloading the page\n router.push({ \n name: 'music-search', \n query: { q: query },\n replace: true\n });\n \n // Perform search\n searchActions.search(query);\n } else {\n // Clear search when query is empty\n router.push({ \n name: 'music-search',\n replace: true\n });\n searchActions.clearSearch();\n }\n};\n\nconst setActiveFilter = (filter) => {\n activeFilter.value = filter;\n searchActions.setFilter(filter);\n};\n\n// Generate random gradient for genre cards\nconst getRandomGradient = () => {\n const colors = [\n 'linear-gradient(135deg, #1DB954, #1ED760)',\n 'linear-gradient(135deg, #FF6B6B, #FFE66D)',\n 'linear-gradient(135deg, #4776E6, #8E54E9)',\n 'linear-gradient(135deg, #FF8008, #FFC837)',\n 'linear-gradient(135deg, #7F00FF, #E100FF)',\n 'linear-gradient(135deg, #11998E, #38EF7D)'\n ];\n \n return colors[Math.floor(Math.random() * colors.length)];\n};\n\n// Watch for URL query parameter changes\nonMounted(() => {\n const query = route.query.q;\n if (query) {\n searchQuery.value = query;\n searchActions.search(query);\n }\n});\n\nwatch(() => route.query.q, (newQuery) => {\n if (newQuery && newQuery !== searchQuery.value) {\n searchQuery.value = newQuery;\n searchActions.search(newQuery);\n } else if (!newQuery) {\n searchQuery.value = '';\n searchActions.clearSearch();\n }\n});\n</script>\n\n<style scoped>\n.bg-gradient-color {\n background: var(--gradient-color, linear-gradient(135deg, #1DB954, #1ED760));\n}\n</style>"],"names":["useRoute","useRouter","ref","computed","searchState","searchActions","onMounted","watch"],"mappings":"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"}
@@ -159,7 +159,7 @@ const _sfc_main = {
159
159
  key: filter.id,
160
160
  onClick: ($event) => setActiveFilter(filter.id),
161
161
  class: normalizeClass([[
162
- filter.id === activeFilter.value ? "bg-white t-black" : "bg-dark-transp-50 hover-bg-dark"
162
+ filter.id === activeFilter.value ? "bg-white t-black" : "bg-white-transp-50 hover-bg-white"
163
163
  ], "radius-extra pd-small"]),
164
164
  showLoader: false,
165
165
  showSucces: false
@@ -189,7 +189,7 @@ const _sfc_main = {
189
189
  trackResults.value.length > 5 && activeFilter.value === "all" ? (openBlock(), createBlock(_sfc_main$2, {
190
190
  key: 0,
191
191
  onClick: _cache[0] || (_cache[0] = ($event) => setActiveFilter("tracks")),
192
- class: "t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin",
192
+ class: "t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin",
193
193
  showLoader: false,
194
194
  showSucces: false
195
195
  }, {
@@ -217,7 +217,7 @@ const _sfc_main = {
217
217
  artistResults.value.length > 6 && activeFilter.value === "all" ? (openBlock(), createBlock(_sfc_main$2, {
218
218
  key: 0,
219
219
  onClick: _cache[1] || (_cache[1] = ($event) => setActiveFilter("artists")),
220
- class: "t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin",
220
+ class: "t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin",
221
221
  showLoader: false,
222
222
  showSucces: false
223
223
  }, {
@@ -243,7 +243,7 @@ const _sfc_main = {
243
243
  albumResults.value.length > 5 && activeFilter.value === "all" ? (openBlock(), createBlock(_sfc_main$2, {
244
244
  key: 0,
245
245
  onClick: _cache[2] || (_cache[2] = ($event) => setActiveFilter("albums")),
246
- class: "t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin",
246
+ class: "t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin",
247
247
  showLoader: false,
248
248
  showSucces: false
249
249
  }, {
@@ -269,7 +269,7 @@ const _sfc_main = {
269
269
  playlistResults.value.length > 5 && activeFilter.value === "all" ? (openBlock(), createBlock(_sfc_main$2, {
270
270
  key: 0,
271
271
  onClick: _cache[3] || (_cache[3] = ($event) => setActiveFilter("playlists")),
272
- class: "t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin",
272
+ class: "t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin",
273
273
  showLoader: false,
274
274
  showSucces: false
275
275
  }, {
@@ -295,7 +295,7 @@ const _sfc_main = {
295
295
  genreResults.value.length > 4 && activeFilter.value === "all" ? (openBlock(), createBlock(_sfc_main$2, {
296
296
  key: 0,
297
297
  onClick: _cache[4] || (_cache[4] = ($event) => setActiveFilter("genres")),
298
- class: "t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin",
298
+ class: "t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin",
299
299
  showLoader: false,
300
300
  showSucces: false
301
301
  }, {
@@ -328,7 +328,7 @@ const _sfc_main = {
328
328
  };
329
329
  }
330
330
  };
331
- const SearchResults = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-464383f0"]]);
331
+ const SearchResults = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-e47a0d68"]]);
332
332
  export {
333
333
  SearchResults as default
334
334
  };
@@ -1 +1 @@
1
- {"version":3,"file":"SearchResults.vue.js","sources":["../../../../../../../src/modules/music/components/pages/SearchResults.vue"],"sourcesContent":["<!-- components/pages/SearchResults.vue -->\n<template>\n <div class=\"search-results-page pd-medium\">\n <div class=\"search-header mn-b-medium\">\n <h1 class=\"mn-b-small\">Search</h1>\n \n <BlockSearch \n :placeholder=\"'What do you want to listen to?'\"\n class=\"bg-light w-m-40r\"\n @search=\"handleSearch\"\n :autofocus=\"true\"\n />\n \n <div v-if=\"searchQuery\" class=\"search-filters flex gap-small mn-t-medium\">\n <Button \n v-for=\"filter in searchFilters\"\n :key=\"filter.id\"\n @click=\"setActiveFilter(filter.id)\"\n :class=\"[\n filter.id === activeFilter ? 'bg-white t-black' : 'bg-dark-transp-50 hover-bg-dark',\n ]\"\n class=\"radius-extra pd-small\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n {{ filter.label }}\n </Button>\n </div>\n </div>\n \n <div v-if=\"isLoading\" class=\"search-loading\">\n <Loader />\n </div>\n \n <div v-else-if=\"searchError\" class=\"search-error t-center pd-big\">\n <p class=\"t-fourth t-medium\">{{ searchError }}</p>\n </div>\n \n <div v-else-if=\"!searchQuery\" class=\"search-empty t-center pd-big\">\n <h2 class=\"mn-b-small\">Search for music</h2>\n <p class=\"t-transp t-medium\">Find your favorite songs, artists, albums, and playlists</p>\n </div>\n \n <div v-else-if=\"!hasResults\" class=\"search-no-results t-center pd-big\">\n <h2 class=\"mn-b-small\">No results found for \"{{ searchQuery }}\"</h2>\n <p class=\"t-transp t-medium\">Please try different keywords or check your spelling</p>\n </div>\n \n <div v-else class=\"search-results\">\n <!-- Songs Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'tracks') && trackResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Songs</h2>\n <Button \n v-if=\"trackResults.length > 5 && activeFilter === 'all'\"\n @click=\"setActiveFilter('tracks')\"\n class=\"t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"bg-light radius-medium o-hidden\">\n <TrackListCard\n v-for=\"(track, index) in (activeFilter === 'all' ? trackResults.slice(0, 5) : trackResults)\"\n :key=\"track._id\"\n :track=\"track\"\n :index=\"index\"\n :showAlbum=\"true\"\n :showCover=\"true\"\n />\n </div>\n </section>\n \n <!-- Artists Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'artists') && artistResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Artists</h2>\n <Button \n v-if=\"artistResults.length > 6 && activeFilter === 'all'\"\n @click=\"setActiveFilter('artists')\"\n class=\"t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"artists-grid cols-6 mobile:cols-3 gap-small\">\n <div v-for=\"artist in (activeFilter === 'all' ? artistResults.slice(0, 6) : artistResults)\" :key=\"artist._id\">\n <ArtistCard :artist=\"artist\" />\n </div>\n </div>\n </section>\n \n <!-- Albums Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'albums') && albumResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Albums</h2>\n <Button \n v-if=\"albumResults.length > 5 && activeFilter === 'all'\"\n @click=\"setActiveFilter('albums')\"\n class=\"t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"albums-grid cols-5 mobile:cols-2 gap-small\">\n <div v-for=\"album in (activeFilter === 'all' ? albumResults.slice(0, 5) : albumResults)\" :key=\"album._id\">\n <AlbumCard :album=\"album\" />\n </div>\n </div>\n </section>\n \n <!-- Playlists Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'playlists') && playlistResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Playlists</h2>\n <Button \n v-if=\"playlistResults.length > 5 && activeFilter === 'all'\"\n @click=\"setActiveFilter('playlists')\"\n class=\"t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"playlists-grid cols-5 mobile:cols-2 gap-small\">\n <div v-for=\"playlist in (activeFilter === 'all' ? playlistResults.slice(0, 5) : playlistResults)\" :key=\"playlist._id\">\n <PlaylistCard :playlist=\"playlist\" />\n </div>\n </div>\n </section>\n \n <!-- Genres Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'genres') && genreResults.length > 0\" class=\"search-section\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Genres</h2>\n <Button \n v-if=\"genreResults.length > 4 && activeFilter === 'all'\"\n @click=\"setActiveFilter('genres')\"\n class=\"t-main bg-transparent border-none hover-bg-dark-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"genres-grid cols-4 mobile:cols-2 gap-small\">\n <router-link \n v-for=\"genre in (activeFilter === 'all' ? genreResults.slice(0, 4) : genreResults)\" \n :key=\"genre._id\"\n :to=\"{ name: 'genre-detail', params: { url: genre.url } }\"\n class=\"genre-card bg-gradient-color pd-medium radius-medium t-center hover-scale-1 transition-cubic-in-out\"\n :style=\"{ \n '--gradient-color': getRandomGradient() \n }\"\n >\n <h3 class=\"\">{{ genre.name }}</h3>\n </router-link>\n </div>\n </section>\n </div>\n </div>\n</template>\n\n<script setup>\nimport { ref, computed, onMounted, watch } from 'vue';\nimport { useRoute, useRouter } from 'vue-router';\nimport BlockSearch from '@martyrs/src/modules/globals/views/components/blocks/BlockSearch.vue';\nimport TrackListCard from '../cards/TrackListCard.vue';\nimport AlbumCard from '../cards/AlbumCard.vue';\nimport PlaylistCard from '../cards/PlaylistCard.vue';\nimport ArtistCard from '../cards/ArtistCard.vue';\nimport Button from '@martyrs/src/components/Button/Button.vue';\nimport Loader from '@martyrs/src/components/Loader/Loader.vue';\n\n// Import search store\nimport { state as searchState, actions as searchActions } from '../../store/search.js';\n\nconst route = useRoute();\nconst router = useRouter();\n\n// State\nconst searchQuery = ref('');\nconst activeFilter = ref('all');\n\n// Array of search filters\nconst searchFilters = [\n { id: 'all', label: 'All' },\n { id: 'tracks', label: 'Songs' },\n { id: 'artists', label: 'Artists' },\n { id: 'albums', label: 'Albums' },\n { id: 'playlists', label: 'Playlists' },\n { id: 'genres', label: 'Genres' }\n];\n\n// Computed properties\nconst isLoading = computed(() => searchState.isLoading);\nconst searchError = computed(() => searchState.error);\nconst hasResults = computed(() => {\n return trackResults.value.length > 0 || \n artistResults.value.length > 0 || \n albumResults.value.length > 0 || \n playlistResults.value.length > 0 || \n genreResults.value.length > 0;\n});\n\nconst trackResults = computed(() => searchState.results.tracks || []);\nconst artistResults = computed(() => searchState.results.artists || []);\nconst albumResults = computed(() => searchState.results.albums || []);\nconst playlistResults = computed(() => searchState.results.playlists || []);\nconst genreResults = computed(() => searchState.results.genres || []);\n\n// Methods\nconst handleSearch = (query) => {\n searchQuery.value = query;\n \n if (query.trim()) {\n // Update URL without reloading the page\n router.push({ \n name: 'music-search', \n query: { q: query },\n replace: true\n });\n \n // Perform search\n searchActions.search(query);\n } else {\n // Clear search when query is empty\n router.push({ \n name: 'music-search',\n replace: true\n });\n searchActions.clearSearch();\n }\n};\n\nconst setActiveFilter = (filter) => {\n activeFilter.value = filter;\n searchActions.setFilter(filter);\n};\n\n// Generate random gradient for genre cards\nconst getRandomGradient = () => {\n const colors = [\n 'linear-gradient(135deg, #1DB954, #1ED760)',\n 'linear-gradient(135deg, #FF6B6B, #FFE66D)',\n 'linear-gradient(135deg, #4776E6, #8E54E9)',\n 'linear-gradient(135deg, #FF8008, #FFC837)',\n 'linear-gradient(135deg, #7F00FF, #E100FF)',\n 'linear-gradient(135deg, #11998E, #38EF7D)'\n ];\n \n return colors[Math.floor(Math.random() * colors.length)];\n};\n\n// Watch for URL query parameter changes\nonMounted(() => {\n const query = route.query.q;\n if (query) {\n searchQuery.value = query;\n searchActions.search(query);\n }\n});\n\nwatch(() => route.query.q, (newQuery) => {\n if (newQuery && newQuery !== searchQuery.value) {\n searchQuery.value = newQuery;\n searchActions.search(newQuery);\n } else if (!newQuery) {\n searchQuery.value = '';\n searchActions.clearSearch();\n }\n});\n</script>\n\n<style scoped>\n.bg-gradient-color {\n background: var(--gradient-color, linear-gradient(135deg, #1DB954, #1ED760));\n}\n</style>"],"names":["searchState","searchActions"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6LA,UAAM,QAAQ,SAAQ;AACtB,UAAM,SAAS,UAAS;AAGxB,UAAM,cAAc,IAAI,EAAE;AAC1B,UAAM,eAAe,IAAI,KAAK;AAG9B,UAAM,gBAAgB;AAAA,MACpB,EAAE,IAAI,OAAO,OAAO,MAAK;AAAA,MACzB,EAAE,IAAI,UAAU,OAAO,QAAO;AAAA,MAC9B,EAAE,IAAI,WAAW,OAAO,UAAS;AAAA,MACjC,EAAE,IAAI,UAAU,OAAO,SAAQ;AAAA,MAC/B,EAAE,IAAI,aAAa,OAAO,YAAW;AAAA,MACrC,EAAE,IAAI,UAAU,OAAO,SAAQ;AAAA,IACjC;AAGA,UAAM,YAAY,SAAS,MAAMA,MAAY,SAAS;AACtD,UAAM,cAAc,SAAS,MAAMA,MAAY,KAAK;AACpD,UAAM,aAAa,SAAS,MAAM;AAChC,aAAO,aAAa,MAAM,SAAS,KAC5B,cAAc,MAAM,SAAS,KAC7B,aAAa,MAAM,SAAS,KAC5B,gBAAgB,MAAM,SAAS,KAC/B,aAAa,MAAM,SAAS;AAAA,IACrC,CAAC;AAED,UAAM,eAAe,SAAS,MAAMA,MAAY,QAAQ,UAAU,CAAA,CAAE;AACpE,UAAM,gBAAgB,SAAS,MAAMA,MAAY,QAAQ,WAAW,CAAA,CAAE;AACtE,UAAM,eAAe,SAAS,MAAMA,MAAY,QAAQ,UAAU,CAAA,CAAE;AACpE,UAAM,kBAAkB,SAAS,MAAMA,MAAY,QAAQ,aAAa,CAAA,CAAE;AAC1E,UAAM,eAAe,SAAS,MAAMA,MAAY,QAAQ,UAAU,CAAA,CAAE;AAGpE,UAAM,eAAe,CAAC,UAAU;AAC9B,kBAAY,QAAQ;AAEpB,UAAI,MAAM,QAAQ;AAEhB,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,OAAO,EAAE,GAAG,MAAK;AAAA,UACjB,SAAS;AAAA,QACf,CAAK;AAGDC,gBAAc,OAAO,KAAK;AAAA,MAC5B,OAAO;AAEL,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,SAAS;AAAA,QACf,CAAK;AACDA,gBAAc,YAAW;AAAA,MAC3B;AAAA,IACF;AAEA,UAAM,kBAAkB,CAAC,WAAW;AAClC,mBAAa,QAAQ;AACrBA,cAAc,UAAU,MAAM;AAAA,IAChC;AAGA,UAAM,oBAAoB,MAAM;AAC9B,YAAM,SAAS;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACJ;AAEE,aAAO,OAAO,KAAK,MAAM,KAAK,WAAW,OAAO,MAAM,CAAC;AAAA,IACzD;AAGA,cAAU,MAAM;AACd,YAAM,QAAQ,MAAM,MAAM;AAC1B,UAAI,OAAO;AACT,oBAAY,QAAQ;AACpBA,gBAAc,OAAO,KAAK;AAAA,MAC5B;AAAA,IACF,CAAC;AAED,UAAM,MAAM,MAAM,MAAM,GAAG,CAAC,aAAa;AACvC,UAAI,YAAY,aAAa,YAAY,OAAO;AAC9C,oBAAY,QAAQ;AACpBA,gBAAc,OAAO,QAAQ;AAAA,MAC/B,WAAW,CAAC,UAAU;AACpB,oBAAY,QAAQ;AACpBA,gBAAc,YAAW;AAAA,MAC3B;AAAA,IACF,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"SearchResults.vue.js","sources":["../../../../../../../src/modules/music/components/pages/SearchResults.vue"],"sourcesContent":["<!-- components/pages/SearchResults.vue -->\n<template>\n <div class=\"search-results-page pd-medium\">\n <div class=\"search-header mn-b-medium\">\n <h1 class=\"mn-b-small\">Search</h1>\n \n <BlockSearch \n :placeholder=\"'What do you want to listen to?'\"\n class=\"bg-light w-m-40r\"\n @search=\"handleSearch\"\n :autofocus=\"true\"\n />\n \n <div v-if=\"searchQuery\" class=\"search-filters flex gap-small mn-t-medium\">\n <Button \n v-for=\"filter in searchFilters\"\n :key=\"filter.id\"\n @click=\"setActiveFilter(filter.id)\"\n :class=\"[\n filter.id === activeFilter ? 'bg-white t-black' : 'bg-white-transp-50 hover-bg-white',\n ]\"\n class=\"radius-extra pd-small\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n {{ filter.label }}\n </Button>\n </div>\n </div>\n \n <div v-if=\"isLoading\" class=\"search-loading\">\n <Loader />\n </div>\n \n <div v-else-if=\"searchError\" class=\"search-error t-center pd-big\">\n <p class=\"t-fourth t-medium\">{{ searchError }}</p>\n </div>\n \n <div v-else-if=\"!searchQuery\" class=\"search-empty t-center pd-big\">\n <h2 class=\"mn-b-small\">Search for music</h2>\n <p class=\"t-transp t-medium\">Find your favorite songs, artists, albums, and playlists</p>\n </div>\n \n <div v-else-if=\"!hasResults\" class=\"search-no-results t-center pd-big\">\n <h2 class=\"mn-b-small\">No results found for \"{{ searchQuery }}\"</h2>\n <p class=\"t-transp t-medium\">Please try different keywords or check your spelling</p>\n </div>\n \n <div v-else class=\"search-results\">\n <!-- Songs Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'tracks') && trackResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Songs</h2>\n <Button \n v-if=\"trackResults.length > 5 && activeFilter === 'all'\"\n @click=\"setActiveFilter('tracks')\"\n class=\"t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"bg-light radius-medium o-hidden\">\n <TrackListCard\n v-for=\"(track, index) in (activeFilter === 'all' ? trackResults.slice(0, 5) : trackResults)\"\n :key=\"track._id\"\n :track=\"track\"\n :index=\"index\"\n :showAlbum=\"true\"\n :showCover=\"true\"\n />\n </div>\n </section>\n \n <!-- Artists Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'artists') && artistResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Artists</h2>\n <Button \n v-if=\"artistResults.length > 6 && activeFilter === 'all'\"\n @click=\"setActiveFilter('artists')\"\n class=\"t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"artists-grid cols-6 mobile:cols-3 gap-small\">\n <div v-for=\"artist in (activeFilter === 'all' ? artistResults.slice(0, 6) : artistResults)\" :key=\"artist._id\">\n <ArtistCard :artist=\"artist\" />\n </div>\n </div>\n </section>\n \n <!-- Albums Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'albums') && albumResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Albums</h2>\n <Button \n v-if=\"albumResults.length > 5 && activeFilter === 'all'\"\n @click=\"setActiveFilter('albums')\"\n class=\"t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"albums-grid cols-5 mobile:cols-2 gap-small\">\n <div v-for=\"album in (activeFilter === 'all' ? albumResults.slice(0, 5) : albumResults)\" :key=\"album._id\">\n <AlbumCard :album=\"album\" />\n </div>\n </div>\n </section>\n \n <!-- Playlists Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'playlists') && playlistResults.length > 0\" class=\"search-section mn-b-medium\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Playlists</h2>\n <Button \n v-if=\"playlistResults.length > 5 && activeFilter === 'all'\"\n @click=\"setActiveFilter('playlists')\"\n class=\"t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"playlists-grid cols-5 mobile:cols-2 gap-small\">\n <div v-for=\"playlist in (activeFilter === 'all' ? playlistResults.slice(0, 5) : playlistResults)\" :key=\"playlist._id\">\n <PlaylistCard :playlist=\"playlist\" />\n </div>\n </div>\n </section>\n \n <!-- Genres Results -->\n <section v-if=\"(activeFilter === 'all' || activeFilter === 'genres') && genreResults.length > 0\" class=\"search-section\">\n <div class=\"flex-between flex mn-b-small\">\n <h2 class=\"\">Genres</h2>\n <Button \n v-if=\"genreResults.length > 4 && activeFilter === 'all'\"\n @click=\"setActiveFilter('genres')\"\n class=\"t-main bg-transparent border-none hover-bg-white-transp-10 pd-thin\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n See all\n </Button>\n </div>\n \n <div class=\"genres-grid cols-4 mobile:cols-2 gap-small\">\n <router-link \n v-for=\"genre in (activeFilter === 'all' ? genreResults.slice(0, 4) : genreResults)\" \n :key=\"genre._id\"\n :to=\"{ name: 'genre-detail', params: { url: genre.url } }\"\n class=\"genre-card bg-gradient-color pd-medium radius-medium t-center hover-scale-1 transition-cubic-in-out\"\n :style=\"{ \n '--gradient-color': getRandomGradient() \n }\"\n >\n <h3 class=\"\">{{ genre.name }}</h3>\n </router-link>\n </div>\n </section>\n </div>\n </div>\n</template>\n\n<script setup>\nimport { ref, computed, onMounted, watch } from 'vue';\nimport { useRoute, useRouter } from 'vue-router';\nimport BlockSearch from '@martyrs/src/modules/globals/views/components/blocks/BlockSearch.vue';\nimport TrackListCard from '../cards/TrackListCard.vue';\nimport AlbumCard from '../cards/AlbumCard.vue';\nimport PlaylistCard from '../cards/PlaylistCard.vue';\nimport ArtistCard from '../cards/ArtistCard.vue';\nimport Button from '@martyrs/src/components/Button/Button.vue';\nimport Loader from '@martyrs/src/components/Loader/Loader.vue';\n\n// Import search store\nimport { state as searchState, actions as searchActions } from '../../store/search.js';\n\nconst route = useRoute();\nconst router = useRouter();\n\n// State\nconst searchQuery = ref('');\nconst activeFilter = ref('all');\n\n// Array of search filters\nconst searchFilters = [\n { id: 'all', label: 'All' },\n { id: 'tracks', label: 'Songs' },\n { id: 'artists', label: 'Artists' },\n { id: 'albums', label: 'Albums' },\n { id: 'playlists', label: 'Playlists' },\n { id: 'genres', label: 'Genres' }\n];\n\n// Computed properties\nconst isLoading = computed(() => searchState.isLoading);\nconst searchError = computed(() => searchState.error);\nconst hasResults = computed(() => {\n return trackResults.value.length > 0 || \n artistResults.value.length > 0 || \n albumResults.value.length > 0 || \n playlistResults.value.length > 0 || \n genreResults.value.length > 0;\n});\n\nconst trackResults = computed(() => searchState.results.tracks || []);\nconst artistResults = computed(() => searchState.results.artists || []);\nconst albumResults = computed(() => searchState.results.albums || []);\nconst playlistResults = computed(() => searchState.results.playlists || []);\nconst genreResults = computed(() => searchState.results.genres || []);\n\n// Methods\nconst handleSearch = (query) => {\n searchQuery.value = query;\n \n if (query.trim()) {\n // Update URL without reloading the page\n router.push({ \n name: 'music-search', \n query: { q: query },\n replace: true\n });\n \n // Perform search\n searchActions.search(query);\n } else {\n // Clear search when query is empty\n router.push({ \n name: 'music-search',\n replace: true\n });\n searchActions.clearSearch();\n }\n};\n\nconst setActiveFilter = (filter) => {\n activeFilter.value = filter;\n searchActions.setFilter(filter);\n};\n\n// Generate random gradient for genre cards\nconst getRandomGradient = () => {\n const colors = [\n 'linear-gradient(135deg, #1DB954, #1ED760)',\n 'linear-gradient(135deg, #FF6B6B, #FFE66D)',\n 'linear-gradient(135deg, #4776E6, #8E54E9)',\n 'linear-gradient(135deg, #FF8008, #FFC837)',\n 'linear-gradient(135deg, #7F00FF, #E100FF)',\n 'linear-gradient(135deg, #11998E, #38EF7D)'\n ];\n \n return colors[Math.floor(Math.random() * colors.length)];\n};\n\n// Watch for URL query parameter changes\nonMounted(() => {\n const query = route.query.q;\n if (query) {\n searchQuery.value = query;\n searchActions.search(query);\n }\n});\n\nwatch(() => route.query.q, (newQuery) => {\n if (newQuery && newQuery !== searchQuery.value) {\n searchQuery.value = newQuery;\n searchActions.search(newQuery);\n } else if (!newQuery) {\n searchQuery.value = '';\n searchActions.clearSearch();\n }\n});\n</script>\n\n<style scoped>\n.bg-gradient-color {\n background: var(--gradient-color, linear-gradient(135deg, #1DB954, #1ED760));\n}\n</style>"],"names":["searchState","searchActions"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6LA,UAAM,QAAQ,SAAQ;AACtB,UAAM,SAAS,UAAS;AAGxB,UAAM,cAAc,IAAI,EAAE;AAC1B,UAAM,eAAe,IAAI,KAAK;AAG9B,UAAM,gBAAgB;AAAA,MACpB,EAAE,IAAI,OAAO,OAAO,MAAK;AAAA,MACzB,EAAE,IAAI,UAAU,OAAO,QAAO;AAAA,MAC9B,EAAE,IAAI,WAAW,OAAO,UAAS;AAAA,MACjC,EAAE,IAAI,UAAU,OAAO,SAAQ;AAAA,MAC/B,EAAE,IAAI,aAAa,OAAO,YAAW;AAAA,MACrC,EAAE,IAAI,UAAU,OAAO,SAAQ;AAAA,IACjC;AAGA,UAAM,YAAY,SAAS,MAAMA,MAAY,SAAS;AACtD,UAAM,cAAc,SAAS,MAAMA,MAAY,KAAK;AACpD,UAAM,aAAa,SAAS,MAAM;AAChC,aAAO,aAAa,MAAM,SAAS,KAC5B,cAAc,MAAM,SAAS,KAC7B,aAAa,MAAM,SAAS,KAC5B,gBAAgB,MAAM,SAAS,KAC/B,aAAa,MAAM,SAAS;AAAA,IACrC,CAAC;AAED,UAAM,eAAe,SAAS,MAAMA,MAAY,QAAQ,UAAU,CAAA,CAAE;AACpE,UAAM,gBAAgB,SAAS,MAAMA,MAAY,QAAQ,WAAW,CAAA,CAAE;AACtE,UAAM,eAAe,SAAS,MAAMA,MAAY,QAAQ,UAAU,CAAA,CAAE;AACpE,UAAM,kBAAkB,SAAS,MAAMA,MAAY,QAAQ,aAAa,CAAA,CAAE;AAC1E,UAAM,eAAe,SAAS,MAAMA,MAAY,QAAQ,UAAU,CAAA,CAAE;AAGpE,UAAM,eAAe,CAAC,UAAU;AAC9B,kBAAY,QAAQ;AAEpB,UAAI,MAAM,QAAQ;AAEhB,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,OAAO,EAAE,GAAG,MAAK;AAAA,UACjB,SAAS;AAAA,QACf,CAAK;AAGDC,gBAAc,OAAO,KAAK;AAAA,MAC5B,OAAO;AAEL,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,SAAS;AAAA,QACf,CAAK;AACDA,gBAAc,YAAW;AAAA,MAC3B;AAAA,IACF;AAEA,UAAM,kBAAkB,CAAC,WAAW;AAClC,mBAAa,QAAQ;AACrBA,cAAc,UAAU,MAAM;AAAA,IAChC;AAGA,UAAM,oBAAoB,MAAM;AAC9B,YAAM,SAAS;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACJ;AAEE,aAAO,OAAO,KAAK,MAAM,KAAK,WAAW,OAAO,MAAM,CAAC;AAAA,IACzD;AAGA,cAAU,MAAM;AACd,YAAM,QAAQ,MAAM,MAAM;AAC1B,UAAI,OAAO;AACT,oBAAY,QAAQ;AACpBA,gBAAc,OAAO,KAAK;AAAA,MAC5B;AAAA,IACF,CAAC;AAED,UAAM,MAAM,MAAM,MAAM,GAAG,CAAC,aAAa;AACvC,UAAI,YAAY,aAAa,YAAY,OAAO;AAC9C,oBAAY,QAAQ;AACpBA,gBAAc,OAAO,QAAQ;AAAA,MAC/B,WAAW,CAAC,UAAU;AACpB,oBAAY,QAAQ;AACpBA,gBAAc,YAAW;AAAA,MAC3B;AAAA,IACF,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}