@ozdao/martyrs 0.2.494 → 0.2.496

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 (170) 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 +41 -42
  6. package/dist/builder.js +43 -44
  7. package/dist/globals.server.cjs +13 -2
  8. package/dist/globals.server.js +13 -2
  9. package/dist/martyrs/src/components/Block/Block.vue.cjs +1 -1
  10. package/dist/martyrs/src/components/Block/Block.vue.js +1 -1
  11. package/dist/martyrs/src/components/Chips/{Chips.vue.cjs → Chips.vue2.cjs} +2 -2
  12. package/dist/martyrs/src/components/Chips/Chips.vue2.cjs.map +1 -0
  13. package/dist/martyrs/src/components/Chips/{Chips.vue.js → Chips.vue2.js} +2 -2
  14. package/dist/martyrs/src/components/Chips/Chips.vue2.js.map +1 -0
  15. package/dist/martyrs/src/components/Dropdown/{Dropdown.vue.cjs → Dropdown.vue2.cjs} +2 -2
  16. package/dist/martyrs/src/components/Dropdown/Dropdown.vue2.cjs.map +1 -0
  17. package/dist/martyrs/src/components/Dropdown/{Dropdown.vue.js → Dropdown.vue2.js} +2 -2
  18. package/dist/martyrs/src/components/Dropdown/{Dropdown.vue.cjs.map → Dropdown.vue2.js.map} +1 -1
  19. package/dist/martyrs/src/components/Feed/Feed.vue.cjs +1 -1
  20. package/dist/martyrs/src/components/Feed/Feed.vue.js +1 -1
  21. package/dist/martyrs/src/components/FieldTags/FieldTags.vue.cjs +1 -1
  22. package/dist/martyrs/src/components/FieldTags/FieldTags.vue.js +1 -1
  23. package/dist/martyrs/src/components/Menu/{Menu.vue2.cjs → Menu.vue.cjs} +2 -2
  24. package/dist/martyrs/src/components/Menu/Menu.vue.cjs.map +1 -0
  25. package/dist/martyrs/src/components/Menu/{Menu.vue2.js → Menu.vue.js} +2 -2
  26. package/dist/martyrs/src/components/Menu/Menu.vue.js.map +1 -0
  27. package/dist/martyrs/src/components/Tooltip/{Tooltip.vue2.cjs → Tooltip.vue.cjs} +2 -2
  28. package/dist/martyrs/src/components/Tooltip/{Tooltip.vue2.js.map → Tooltip.vue.cjs.map} +1 -1
  29. package/dist/martyrs/src/components/Tooltip/{Tooltip.vue2.js → Tooltip.vue.js} +2 -2
  30. package/dist/martyrs/src/components/Tooltip/Tooltip.vue.js.map +1 -0
  31. package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.cjs +2 -2
  32. package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js +2 -2
  33. package/dist/martyrs/src/modules/community/components/blocks/CardBlogpost.vue.cjs +1 -1
  34. package/dist/martyrs/src/modules/community/components/blocks/CardBlogpost.vue.js +1 -1
  35. package/dist/martyrs/src/modules/community/components/pages/BlogPost.vue.cjs +1 -1
  36. package/dist/martyrs/src/modules/community/components/pages/BlogPost.vue.js +1 -1
  37. package/dist/martyrs/src/modules/community/components/pages/CreateBlogPost.vue.cjs +1 -1
  38. package/dist/martyrs/src/modules/community/components/pages/CreateBlogPost.vue.js +1 -1
  39. package/dist/martyrs/src/modules/events/components/blocks/CardEvent.vue.cjs +1 -1
  40. package/dist/martyrs/src/modules/events/components/blocks/CardEvent.vue.js +1 -1
  41. package/dist/martyrs/src/modules/events/components/pages/Event.vue.cjs +2 -2
  42. package/dist/martyrs/src/modules/events/components/pages/Event.vue.js +2 -2
  43. package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.cjs +1 -1
  44. package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.js +1 -1
  45. package/dist/martyrs/src/modules/globals/globals.client.cjs +1 -1
  46. package/dist/martyrs/src/modules/globals/globals.client.cjs.map +1 -1
  47. package/dist/martyrs/src/modules/globals/globals.client.js +1 -1
  48. package/dist/martyrs/src/modules/globals/globals.client.js.map +1 -1
  49. package/dist/martyrs/src/modules/globals/views/classes/globals.i18n.cjs +1 -1
  50. package/dist/martyrs/src/modules/globals/views/classes/globals.i18n.js +1 -1
  51. package/dist/martyrs/src/modules/globals/views/components/blocks/CardHeader.vue.cjs +2 -2
  52. package/dist/martyrs/src/modules/globals/views/components/blocks/CardHeader.vue.js +2 -2
  53. package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.cjs +28 -13
  54. package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.cjs.map +1 -1
  55. package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.js +28 -13
  56. package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.js.map +1 -1
  57. package/dist/martyrs/src/modules/globals/views/components/partials/Navigation.vue.cjs +1 -1
  58. package/dist/martyrs/src/modules/globals/views/components/partials/Navigation.vue.js +1 -1
  59. package/dist/martyrs/src/modules/globals/views/router/scrollBehavior.cjs +1 -1
  60. package/dist/martyrs/src/modules/globals/views/router/scrollBehavior.cjs.map +1 -1
  61. package/dist/martyrs/src/modules/globals/views/router/scrollBehavior.js +1 -1
  62. package/dist/martyrs/src/modules/globals/views/router/scrollBehavior.js.map +1 -1
  63. package/dist/martyrs/src/modules/inventory/components/pages/Inventory.vue.cjs +2 -2
  64. package/dist/martyrs/src/modules/inventory/components/pages/Inventory.vue.js +1 -1
  65. package/dist/martyrs/src/modules/inventory/components/pages/InventoryEdit.vue.cjs +1 -1
  66. package/dist/martyrs/src/modules/inventory/components/pages/InventoryEdit.vue.js +1 -1
  67. package/dist/martyrs/src/modules/music/components/cards/ArtistCardSmall.vue.cjs +95 -0
  68. package/dist/martyrs/src/modules/music/components/cards/ArtistCardSmall.vue.cjs.map +1 -0
  69. package/dist/martyrs/src/modules/music/components/cards/ArtistCardSmall.vue.js +95 -0
  70. package/dist/martyrs/src/modules/music/components/cards/ArtistCardSmall.vue.js.map +1 -0
  71. package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.cjs +1 -1
  72. package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.cjs.map +1 -1
  73. package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.js +1 -1
  74. package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.js.map +1 -1
  75. package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.cjs +2 -2
  76. package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.cjs.map +1 -1
  77. package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.js +2 -2
  78. package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.js.map +1 -1
  79. package/dist/martyrs/src/modules/music/components/pages/Album.vue.cjs +127 -175
  80. package/dist/martyrs/src/modules/music/components/pages/Album.vue.cjs.map +1 -1
  81. package/dist/martyrs/src/modules/music/components/pages/Album.vue.js +136 -184
  82. package/dist/martyrs/src/modules/music/components/pages/Album.vue.js.map +1 -1
  83. package/dist/martyrs/src/modules/music/components/pages/Artist.vue.cjs +5 -5
  84. package/dist/martyrs/src/modules/music/components/pages/Artist.vue.cjs.map +1 -1
  85. package/dist/martyrs/src/modules/music/components/pages/Artist.vue.js +5 -5
  86. package/dist/martyrs/src/modules/music/components/pages/Artist.vue.js.map +1 -1
  87. package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.cjs +5 -5
  88. package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.cjs.map +1 -1
  89. package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.js +5 -5
  90. package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.js.map +1 -1
  91. package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.cjs +97 -144
  92. package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.cjs.map +1 -1
  93. package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.js +113 -160
  94. package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.js.map +1 -1
  95. package/dist/martyrs/src/modules/music/components/pages/SearchResults.vue.cjs +7 -7
  96. package/dist/martyrs/src/modules/music/components/pages/SearchResults.vue.cjs.map +1 -1
  97. package/dist/martyrs/src/modules/music/components/pages/SearchResults.vue.js +7 -7
  98. package/dist/martyrs/src/modules/music/components/pages/SearchResults.vue.js.map +1 -1
  99. package/dist/martyrs/src/modules/music/components/pages/Track.vue.cjs +164 -170
  100. package/dist/martyrs/src/modules/music/components/pages/Track.vue.cjs.map +1 -1
  101. package/dist/martyrs/src/modules/music/components/pages/Track.vue.js +185 -191
  102. package/dist/martyrs/src/modules/music/components/pages/Track.vue.js.map +1 -1
  103. package/dist/martyrs/src/modules/music/music.client.cjs.map +1 -1
  104. package/dist/martyrs/src/modules/music/music.client.js.map +1 -1
  105. package/dist/martyrs/src/modules/music/router/music.cjs +2 -2
  106. package/dist/martyrs/src/modules/music/router/music.js +2 -2
  107. package/dist/martyrs/src/modules/notifications/notifications.client.cjs +1 -1
  108. package/dist/martyrs/src/modules/notifications/notifications.client.cjs.map +1 -1
  109. package/dist/martyrs/src/modules/notifications/notifications.client.js +1 -1
  110. package/dist/martyrs/src/modules/notifications/notifications.client.js.map +1 -1
  111. package/dist/martyrs/src/modules/orders/components/blocks/CardOrderUser.vue.cjs +1 -1
  112. package/dist/martyrs/src/modules/orders/components/blocks/CardOrderUser.vue.js +1 -1
  113. package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.cjs +1 -1
  114. package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js +1 -1
  115. package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.cjs +1 -1
  116. package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.js +1 -1
  117. package/dist/martyrs/src/modules/organizations/components/blocks/CardOrganization.vue.cjs +1 -1
  118. package/dist/martyrs/src/modules/organizations/components/blocks/CardOrganization.vue.js +1 -1
  119. package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.cjs +2 -2
  120. package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.js +2 -2
  121. package/dist/martyrs/src/modules/organizations/components/pages/Organization.vue.cjs +1 -1
  122. package/dist/martyrs/src/modules/organizations/components/pages/Organization.vue.js +1 -1
  123. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationBackoffice.vue.cjs +1 -1
  124. package/dist/martyrs/src/modules/organizations/components/pages/OrganizationBackoffice.vue.js +1 -1
  125. package/dist/martyrs/src/modules/organizations/components/sections/DetailsTabSection.vue.cjs +2 -2
  126. package/dist/martyrs/src/modules/organizations/components/sections/DetailsTabSection.vue.js +2 -2
  127. package/dist/martyrs/src/modules/organizations/router/organizations.cjs +1 -1
  128. package/dist/martyrs/src/modules/organizations/router/organizations.js +1 -1
  129. package/dist/martyrs/src/modules/pages/views/components/pages/PageEdit.vue.cjs +1 -1
  130. package/dist/martyrs/src/modules/pages/views/components/pages/PageEdit.vue.js +1 -1
  131. package/dist/martyrs/src/modules/products/components/blocks/ProductDiscounts.vue.cjs +2 -2
  132. package/dist/martyrs/src/modules/products/components/blocks/ProductDiscounts.vue.js +2 -2
  133. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.cjs +1 -1
  134. package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js +1 -1
  135. package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttToolbar.vue.cjs +1 -1
  136. package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttToolbar.vue.js +1 -1
  137. package/dist/martyrs/src/modules/spots/components/blocks/CardSpot.vue.cjs +1 -1
  138. package/dist/martyrs/src/modules/spots/components/blocks/CardSpot.vue.js +1 -1
  139. package/dist/martyrs/src/modules/spots/components/layouts/Spots.vue.cjs +1 -1
  140. package/dist/martyrs/src/modules/spots/components/layouts/Spots.vue.js +1 -1
  141. package/dist/martyrs/src/modules/wallet/views/components/pages/Wallet.vue.cjs +3 -3
  142. package/dist/martyrs/src/modules/wallet/views/components/pages/Wallet.vue.js +3 -3
  143. package/dist/martyrs.css +1 -1
  144. package/dist/style.css +18 -5
  145. package/package.json +1 -1
  146. package/src/builder/rspack/rspack.config.ssr.client.js +40 -40
  147. package/src/modules/globals/controllers/classes/globals.websocket.js +11 -2
  148. package/src/modules/globals/globals.client.js +1 -2
  149. package/src/modules/globals/views/components/layouts/Client.vue +13 -11
  150. package/src/modules/globals/views/router/scrollBehavior.js +1 -1
  151. package/src/modules/music/README.md +2 -0
  152. package/src/modules/music/components/SidebarMusic.vue +7 -7
  153. package/src/modules/music/components/cards/ArtistCardSmall.vue +92 -0
  154. package/src/modules/music/components/cards/TrackListCard.vue +1 -1
  155. package/src/modules/music/components/forms/SearchForm.vue +1 -1
  156. package/src/modules/music/components/pages/Album.vue +44 -83
  157. package/src/modules/music/components/pages/Artist.vue +5 -5
  158. package/src/modules/music/components/pages/MusicLibrary.vue +5 -5
  159. package/src/modules/music/components/pages/Playlist.vue +35 -53
  160. package/src/modules/music/components/pages/SearchResults.vue +6 -6
  161. package/src/modules/music/components/pages/Track.vue +66 -87
  162. package/src/modules/music/music.client.js +1 -1
  163. package/src/modules/notifications/notifications.client.js +1 -1
  164. package/src/styles/base/all.scss +1 -0
  165. package/dist/martyrs/src/components/Chips/Chips.vue.cjs.map +0 -1
  166. package/dist/martyrs/src/components/Chips/Chips.vue.js.map +0 -1
  167. package/dist/martyrs/src/components/Dropdown/Dropdown.vue.js.map +0 -1
  168. package/dist/martyrs/src/components/Menu/Menu.vue2.cjs.map +0 -1
  169. package/dist/martyrs/src/components/Menu/Menu.vue2.js.map +0 -1
  170. package/dist/martyrs/src/components/Tooltip/Tooltip.vue2.cjs.map +0 -1
@@ -5,7 +5,7 @@ const vueRouter = require("vue-router");
5
5
  const Button = require("../../../../components/Button/Button.vue.cjs");
6
6
  const Loader = require("../../../../components/Loader/Loader.vue2.cjs");
7
7
  const Media = require("../../../../components/Media/Media.vue.cjs");
8
- const Dropdown = require("../../../../components/Dropdown/Dropdown.vue.cjs");
8
+ const Dropdown = require("../../../../components/Dropdown/Dropdown.vue2.cjs");
9
9
  const Feed = require("../../../../components/Feed/Feed.vue.cjs");
10
10
  const IconPlay = require("../../../icons/navigation/IconPlay.vue.cjs");
11
11
  const IconLike = require("../../../icons/navigation/IconLike.vue.cjs");
@@ -15,9 +15,9 @@ const IconCalendar = require("../../../icons/entities/IconCalendar.vue.cjs");
15
15
  const IconTime = require("../../../icons/entities/IconTime.vue.cjs");
16
16
  const IconShow = require("../../../icons/actions/IconShow.vue.cjs");
17
17
  const IconMusic = require("../../../icons/entities/IconMusic.vue.cjs");
18
- const IconCheckmark = require("../../../icons/navigation/IconCheckmark.vue.cjs");
19
18
  const TrackListCard = require("../cards/TrackListCard.vue.cjs");
20
19
  const AlbumCard = require("../cards/AlbumCard.vue.cjs");
20
+ const ArtistCardSmall = require("../cards/ArtistCardSmall.vue.cjs");
21
21
  const albums = require("../../store/albums.cjs");
22
22
  const player = require("../../store/player.cjs");
23
23
  const auth = require("../../../auth/views/store/auth.cjs");
@@ -35,72 +35,55 @@ const _hoisted_4 = {
35
35
  class: "album-content cols-2-fit-content mobile:cols-1 gap-big"
36
36
  };
37
37
  const _hoisted_5 = { class: "pos-sticky pos-t-0 mobile:pos-relative album-cover-section" };
38
- const _hoisted_6 = { class: "cover-container relative mn-b-medium radius-big overflow-hidden shadow-big" };
39
- const _hoisted_7 = { class: "stats-grid grid cols-2 gap-small" };
40
- const _hoisted_8 = { class: "stat-card bg-light pd-medium radius-medium t-center" };
41
- const _hoisted_9 = { class: "mn-b-thin" };
42
- const _hoisted_10 = { class: "stat-card bg-light pd-medium radius-medium t-center" };
43
- const _hoisted_11 = { class: "mn-b-thin" };
44
- const _hoisted_12 = { class: "album-details-section" };
45
- const _hoisted_13 = { class: "flex items-center gap-small mn-b-small" };
46
- const _hoisted_14 = { class: "badge bg-primary-transp-20 t-primary pd-thin-big radius-small t-small t-uppercase" };
47
- const _hoisted_15 = {
38
+ const _hoisted_6 = { class: "stats-grid grid cols-2 gap-small" };
39
+ const _hoisted_7 = { class: "stat-card bg-light pd-medium radius-medium t-center" };
40
+ const _hoisted_8 = { class: "mn-b-thin" };
41
+ const _hoisted_9 = { class: "stat-card bg-light pd-medium radius-medium t-center" };
42
+ const _hoisted_10 = { class: "mn-b-thin" };
43
+ const _hoisted_11 = { class: "album-details-section" };
44
+ const _hoisted_12 = { class: "flex items-center gap-small mn-b-small" };
45
+ const _hoisted_13 = { class: "bg-light t-medium pd-thin radius-thin uppercase t-small t-uppercase" };
46
+ const _hoisted_14 = {
48
47
  key: 0,
49
- class: "badge bg-success-transp-20 t-success pd-thin-big radius-small t-small"
48
+ class: "bg-light t-medium pd-thin radius-thin uppercase t-small t-uppercase"
50
49
  };
51
- const _hoisted_16 = { class: "h1 mn-b-medium" };
52
- const _hoisted_17 = { class: "flex gap-small mn-b-medium" };
53
- const _hoisted_18 = { class: "dropdown-menu bg-dark pd-small radius-medium shadow-big mn-t-thin" };
54
- const _hoisted_19 = { class: "artists-section mn-b-big" };
55
- const _hoisted_20 = {
50
+ const _hoisted_15 = { class: "h1 mn-b-medium" };
51
+ const _hoisted_16 = { class: "flex gap-small mn-b-medium" };
52
+ const _hoisted_17 = { class: "dropdown-menu bg-white pd-small radius-medium shadow-big mn-t-thin" };
53
+ const _hoisted_18 = { class: "artists-section mn-b-medium" };
54
+ const _hoisted_19 = {
56
55
  key: 0,
57
56
  class: "t-medium mn-b-small"
58
57
  };
59
- const _hoisted_21 = { class: "flex flex-col gap-small" };
60
- const _hoisted_22 = { class: "artist-avatar" };
61
- const _hoisted_23 = {
62
- key: 1,
63
- class: "w-4r h-4r radius-full bg-primary flex-center"
64
- };
65
- const _hoisted_24 = { class: "flex items-center gap-thin" };
66
- const _hoisted_25 = { class: "t-large" };
67
- const _hoisted_26 = { class: "metadata-grid grid cols-2 gap-small mn-b-big" };
68
- const _hoisted_27 = { class: "metadata-card bg-light pd-medium radius-medium flex items-center gap-medium" };
69
- const _hoisted_28 = { class: "icon-wrapper bg-primary-transp-20 w-3r h-3r radius-small flex-center" };
70
- const _hoisted_29 = { class: "t-medium" };
71
- const _hoisted_30 = { class: "metadata-card bg-light pd-medium radius-medium flex items-center gap-medium" };
72
- const _hoisted_31 = { class: "icon-wrapper bg-primary-transp-20 w-3r h-3r radius-small flex-center" };
73
- const _hoisted_32 = { class: "t-medium" };
74
- const _hoisted_33 = {
58
+ const _hoisted_20 = { class: "flex flex-col gap-small" };
59
+ const _hoisted_21 = { class: "metadata-grid grid cols-2 gap-small mn-b-medium" };
60
+ const _hoisted_22 = { class: "metadata-card bg-light pd-medium radius-medium flex items-center gap-medium" };
61
+ const _hoisted_23 = { class: "t-medium" };
62
+ const _hoisted_24 = { class: "metadata-card bg-light pd-medium radius-medium flex items-center gap-medium" };
63
+ const _hoisted_25 = { class: "t-medium" };
64
+ const _hoisted_26 = {
75
65
  key: 0,
76
66
  class: "metadata-card bg-light pd-medium radius-medium flex items-center gap-medium"
77
67
  };
78
- const _hoisted_34 = { class: "icon-wrapper bg-primary-transp-20 w-3r h-3r radius-small flex-center" };
79
- const _hoisted_35 = { class: "t-medium" };
80
- const _hoisted_36 = { class: "metadata-card bg-light pd-medium radius-medium flex items-center gap-medium" };
81
- const _hoisted_37 = { class: "icon-wrapper bg-primary-transp-20 w-3r h-3r radius-small flex-center" };
82
- const _hoisted_38 = { class: "t-medium" };
83
- const _hoisted_39 = {
68
+ const _hoisted_27 = { class: "t-medium" };
69
+ const _hoisted_28 = { class: "metadata-card bg-light pd-medium radius-medium flex items-center gap-medium" };
70
+ const _hoisted_29 = { class: "t-medium" };
71
+ const _hoisted_30 = {
84
72
  key: 0,
85
73
  class: "tags-section mn-b-medium"
86
74
  };
87
- const _hoisted_40 = { class: "flex gap-thin flex-wrap" };
88
- const _hoisted_41 = {
89
- key: 1,
90
- class: "description-section bg-light pd-medium radius-medium mn-b-medium"
91
- };
92
- const _hoisted_42 = { class: "t-transp" };
93
- const _hoisted_43 = {
75
+ const _hoisted_31 = { class: "flex gap-thin flex-wrap" };
76
+ const _hoisted_32 = {
94
77
  key: 3,
95
78
  class: "tracks-section mn-t-big"
96
79
  };
97
- const _hoisted_44 = { class: "bg-light radius-medium o-hidden" };
98
- const _hoisted_45 = {
80
+ const _hoisted_33 = { class: "bg-light radius-medium o-hidden" };
81
+ const _hoisted_34 = {
99
82
  key: 4,
100
83
  class: "more-albums-section mn-t-big"
101
84
  };
102
- const _hoisted_46 = { class: "flex justify-between items-center mn-b-medium" };
103
- const _hoisted_47 = { class: "flex flex-nowrap gap-small o-x-scroll overscroll-behavior-x-contain scroll-behavior-smooth scroll-snap-type-x-mandatory scroll-hide" };
85
+ const _hoisted_35 = { class: "flex justify-between items-center mn-b-medium" };
86
+ const _hoisted_36 = { class: "flex flex-nowrap gap-small o-x-scroll overscroll-behavior-x-contain scroll-behavior-smooth scroll-snap-type-x-mandatory scroll-hide" };
104
87
  const _sfc_main = {
105
88
  __name: "Album",
106
89
  emits: ["page-loading", "page-loaded"],
@@ -234,69 +217,73 @@ const _sfc_main = {
234
217
  ]))) : vue.createCommentVNode("", true),
235
218
  album.value ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_4, [
236
219
  vue.createElementVNode("div", _hoisted_5, [
220
+ vue.createVNode(Media.default, {
221
+ url: album.value.coverArt || "/logo/logo-placeholder.jpg",
222
+ alt: album.value.title,
223
+ class: "aspect-1x1 w-100 w-max-30r mn-b-small radius-medium o-hidden"
224
+ }, null, 8, ["url", "alt"]),
237
225
  vue.createElementVNode("div", _hoisted_6, [
238
- vue.createVNode(Media.default, {
239
- url: album.value.coverArt || "/logo/logo-placeholder.jpg",
240
- alt: album.value.title,
241
- class: "aspect-1x1 w-100 radius-medium o-hidden"
242
- }, null, 8, ["url", "alt"])
243
- ]),
244
- vue.createElementVNode("div", _hoisted_7, [
245
- vue.createElementVNode("div", _hoisted_8, [
246
- vue.createElementVNode("div", _hoisted_9, vue.toDisplayString(album.value.totalTracks || 0), 1),
226
+ vue.createElementVNode("div", _hoisted_7, [
227
+ vue.createElementVNode("div", _hoisted_8, vue.toDisplayString(album.value.totalTracks || 0), 1),
247
228
  _cache[2] || (_cache[2] = vue.createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Tracks", -1))
248
229
  ]),
249
- vue.createElementVNode("div", _hoisted_10, [
250
- vue.createElementVNode("div", _hoisted_11, vue.toDisplayString(formatNumber(album.value.views)), 1),
230
+ vue.createElementVNode("div", _hoisted_9, [
231
+ vue.createElementVNode("div", _hoisted_10, vue.toDisplayString(formatNumber(album.value.views)), 1),
251
232
  _cache[3] || (_cache[3] = vue.createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Views", -1))
252
233
  ])
253
234
  ])
254
235
  ]),
255
- vue.createElementVNode("div", _hoisted_12, [
256
- vue.createElementVNode("div", _hoisted_13, [
257
- vue.createElementVNode("span", _hoisted_14, vue.toDisplayString(album.value.type), 1),
258
- album.value.status === "published" ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_15, " Published ")) : vue.createCommentVNode("", true)
236
+ vue.createElementVNode("div", _hoisted_11, [
237
+ vue.createElementVNode("div", _hoisted_12, [
238
+ vue.createElementVNode("span", _hoisted_13, vue.toDisplayString(album.value.type), 1),
239
+ album.value.status === "published" ? (vue.openBlock(), vue.createElementBlock("span", _hoisted_14, " Published ")) : vue.createCommentVNode("", true)
259
240
  ]),
260
- vue.createElementVNode("h1", _hoisted_16, vue.toDisplayString(album.value.title), 1),
261
- vue.createElementVNode("div", _hoisted_17, [
241
+ vue.createElementVNode("h1", _hoisted_15, vue.toDisplayString(album.value.title), 1),
242
+ vue.createElementVNode("div", _hoisted_16, [
262
243
  vue.createVNode(Button.default, {
263
244
  onClick: playAlbum,
264
245
  color: "primary",
265
246
  size: "medium",
266
- class: "flex-1 flex-center gap-thin"
247
+ class: "flex-1 t-white bg-black radius-thin flex-center gap-thin"
267
248
  }, {
268
249
  default: vue.withCtx(() => [
269
- vue.createVNode(IconPlay.default, { class: "w-1r h-1r" }),
250
+ vue.createVNode(IconPlay.default, {
251
+ fill: "rgb(var(--white))",
252
+ class: "i-medium"
253
+ }),
270
254
  _cache[4] || (_cache[4] = vue.createTextVNode(" Play All "))
271
255
  ]),
272
256
  _: 1
273
257
  }),
274
258
  vue.createVNode(Button.default, {
275
- onClick: toggleFavorite,
276
- color: isFavorite.value ? "danger" : "transp",
259
+ onClick: shufflePlay,
260
+ color: "primary",
277
261
  size: "medium",
278
- class: "w-3r h-3r radius-full"
262
+ class: "flex-1 bg-light radius-thin flex-center gap-thin"
279
263
  }, {
280
264
  default: vue.withCtx(() => [
281
- vue.createVNode(IconLike.default, {
282
- class: "w-1-25r h-1-25r",
283
- fill: isFavorite.value
284
- }, null, 8, ["fill"])
265
+ vue.createVNode(IconShuffle.default, { class: "i-medium" }),
266
+ _cache[5] || (_cache[5] = vue.createTextVNode(" Shuffle "))
285
267
  ]),
286
268
  _: 1
287
- }, 8, ["color"]),
269
+ }),
288
270
  vue.createVNode(Button.default, {
289
- onClick: shufflePlay,
290
- color: "transp",
271
+ onClick: toggleFavorite,
272
+ color: "primary",
291
273
  size: "medium",
292
- class: "w-3r h-3r radius-full"
274
+ class: "flex-1 bg-light radius-thin flex-center gap-thin"
293
275
  }, {
294
276
  default: vue.withCtx(() => [
295
- vue.createVNode(IconShuffle.default, { class: "w-1-25r h-1-25r" })
277
+ vue.createVNode(IconLike.default, {
278
+ class: "i-medium",
279
+ fill: isFavorite.value ? "rgb(var(--main)" : "rgb(var(--black)"
280
+ }, null, 8, ["fill"]),
281
+ vue.createTextVNode(" " + vue.toDisplayString(isFavorite.value ? "Liked" : "Like"), 1)
296
282
  ]),
297
283
  _: 1
298
284
  }),
299
285
  vue.createVNode(Dropdown.default, {
286
+ label: { component: IconEllipsis.default, class: "bg-light radius-thin pd-thin i-big" },
300
287
  modelValue: showDropdown.value,
301
288
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => showDropdown.value = $event),
302
289
  class: "relative"
@@ -314,14 +301,14 @@ const _sfc_main = {
314
301
  })
315
302
  ]),
316
303
  default: vue.withCtx(() => [
317
- vue.createElementVNode("div", _hoisted_18, [
304
+ vue.createElementVNode("div", _hoisted_17, [
318
305
  vue.createVNode(Button.default, {
319
306
  onClick: addToQueue,
320
307
  color: "transp",
321
308
  size: "small",
322
309
  class: "w-100 justify-start"
323
310
  }, {
324
- default: vue.withCtx(() => _cache[5] || (_cache[5] = [
311
+ default: vue.withCtx(() => _cache[6] || (_cache[6] = [
325
312
  vue.createTextVNode(" Add to Queue ")
326
313
  ])),
327
314
  _: 1
@@ -332,20 +319,31 @@ const _sfc_main = {
332
319
  size: "small",
333
320
  class: "w-100 justify-start"
334
321
  }, {
335
- default: vue.withCtx(() => _cache[6] || (_cache[6] = [
322
+ default: vue.withCtx(() => _cache[7] || (_cache[7] = [
336
323
  vue.createTextVNode(" Copy Link ")
337
324
  ])),
338
325
  _: 1
339
326
  }),
327
+ vue.createVNode(Button.default, {
328
+ onClick: _ctx.addToPlaylist,
329
+ color: "transp",
330
+ size: "small",
331
+ class: "w-100 justify-start"
332
+ }, {
333
+ default: vue.withCtx(() => _cache[8] || (_cache[8] = [
334
+ vue.createTextVNode(" Add to Playlist ")
335
+ ])),
336
+ _: 1
337
+ }, 8, ["onClick"]),
340
338
  isOwner.value ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
341
- _cache[9] || (_cache[9] = vue.createElementVNode("hr", { class: "mn-v-thin border-dark-transp-10" }, null, -1)),
339
+ _cache[11] || (_cache[11] = vue.createElementVNode("hr", { class: "mn-v-thin border-dark-transp-10" }, null, -1)),
342
340
  vue.createVNode(Button.default, {
343
341
  onClick: editAlbum,
344
342
  color: "transp",
345
343
  size: "small",
346
344
  class: "w-100 justify-start"
347
345
  }, {
348
- default: vue.withCtx(() => _cache[7] || (_cache[7] = [
346
+ default: vue.withCtx(() => _cache[9] || (_cache[9] = [
349
347
  vue.createTextVNode(" Edit Album ")
350
348
  ])),
351
349
  _: 1
@@ -356,7 +354,7 @@ const _sfc_main = {
356
354
  size: "small",
357
355
  class: "w-100 justify-start"
358
356
  }, {
359
- default: vue.withCtx(() => _cache[8] || (_cache[8] = [
357
+ default: vue.withCtx(() => _cache[10] || (_cache[10] = [
360
358
  vue.createTextVNode(" Delete Album ")
361
359
  ])),
362
360
  _: 1
@@ -365,102 +363,60 @@ const _sfc_main = {
365
363
  ])
366
364
  ]),
367
365
  _: 1
368
- }, 8, ["modelValue"])
366
+ }, 8, ["label", "modelValue"])
369
367
  ]),
370
- vue.createElementVNode("div", _hoisted_19, [
371
- album.value.artists && album.value.artists.length > 1 ? (vue.openBlock(), vue.createElementBlock("h3", _hoisted_20, "Artists")) : vue.createCommentVNode("", true),
372
- vue.createElementVNode("div", _hoisted_21, [
368
+ vue.createElementVNode("div", _hoisted_18, [
369
+ album.value.artists ? (vue.openBlock(), vue.createElementBlock("h3", _hoisted_19, "Artists")) : vue.createCommentVNode("", true),
370
+ vue.createElementVNode("div", _hoisted_20, [
373
371
  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(album.value.artists, (artist) => {
374
- return vue.openBlock(), vue.createElementBlock("div", {
372
+ return vue.openBlock(), vue.createBlock(ArtistCardSmall.default, {
375
373
  key: artist._id,
376
- class: "artist-card bg-light pd-medium radius-medium flex items-center gap-medium"
377
- }, [
378
- vue.createVNode(_component_router_link, {
379
- to: `/artist/${artist.url}`,
380
- class: "flex items-center gap-medium flex-1 hover-opacity"
381
- }, {
382
- default: vue.withCtx(() => [
383
- vue.createElementVNode("div", _hoisted_22, [
384
- artist.photoUrl ? (vue.openBlock(), vue.createBlock(Media.default, {
385
- key: 0,
386
- url: artist.photoUrl,
387
- alt: artist.name,
388
- class: "w-4r h-4r radius-full object-cover"
389
- }, null, 8, ["url", "alt"])) : (vue.openBlock(), vue.createElementBlock("div", _hoisted_23, vue.toDisplayString(artist.name.charAt(0)), 1))
390
- ]),
391
- vue.createElementVNode("div", null, [
392
- vue.createElementVNode("div", _hoisted_24, [
393
- vue.createElementVNode("span", _hoisted_25, vue.toDisplayString(artist.name), 1),
394
- artist.isVerified ? (vue.openBlock(), vue.createBlock(IconCheckmark.default, {
395
- key: 0,
396
- class: "w-1r h-1r t-primary"
397
- })) : vue.createCommentVNode("", true)
398
- ]),
399
- _cache[10] || (_cache[10] = vue.createElementVNode("span", { class: "t-small t-transp" }, "Artist", -1))
400
- ])
401
- ]),
402
- _: 2
403
- }, 1032, ["to"]),
404
- !isOwner.value ? (vue.openBlock(), vue.createBlock(Button.default, {
405
- key: 0,
406
- onClick: () => toggleFollowArtist(artist._id),
407
- color: followedArtists.value.includes(artist._id) ? "primary" : "transp",
408
- size: "small"
409
- }, {
410
- default: vue.withCtx(() => [
411
- vue.createTextVNode(vue.toDisplayString(followedArtists.value.includes(artist._id) ? "Following" : "Follow"), 1)
412
- ]),
413
- _: 2
414
- }, 1032, ["onClick", "color"])) : vue.createCommentVNode("", true)
415
- ]);
374
+ artist,
375
+ "is-following": followedArtists.value.includes(artist._id),
376
+ "show-follow-button": !isOwner.value,
377
+ onToggleFollow: toggleFollowArtist
378
+ }, null, 8, ["artist", "is-following", "show-follow-button"]);
416
379
  }), 128))
417
380
  ])
418
381
  ]),
419
- vue.createElementVNode("div", _hoisted_26, [
420
- vue.createElementVNode("div", _hoisted_27, [
421
- vue.createElementVNode("div", _hoisted_28, [
422
- vue.createVNode(IconCalendar.default, { class: "w-1-5r h-1-5r t-primary" })
423
- ]),
382
+ _cache[17] || (_cache[17] = vue.createElementVNode("h3", { class: "t-medium mn-b-small" }, "Metadata", -1)),
383
+ vue.createElementVNode("div", _hoisted_21, [
384
+ vue.createElementVNode("div", _hoisted_22, [
385
+ vue.createVNode(IconCalendar.default, { class: "i-regular t-primary" }),
424
386
  vue.createElementVNode("div", null, [
425
- _cache[11] || (_cache[11] = vue.createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Released", -1)),
426
- vue.createElementVNode("div", _hoisted_29, vue.toDisplayString(formatDate(album.value.releaseDate)), 1)
387
+ _cache[12] || (_cache[12] = vue.createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Released", -1)),
388
+ vue.createElementVNode("div", _hoisted_23, vue.toDisplayString(formatDate(album.value.releaseDate)), 1)
427
389
  ])
428
390
  ]),
429
- vue.createElementVNode("div", _hoisted_30, [
430
- vue.createElementVNode("div", _hoisted_31, [
431
- vue.createVNode(IconTime.default, { class: "w-1-5r h-1-5r t-primary" })
432
- ]),
391
+ vue.createElementVNode("div", _hoisted_24, [
392
+ vue.createVNode(IconTime.default, { class: "i-regular t-primary" }),
433
393
  vue.createElementVNode("div", null, [
434
- _cache[12] || (_cache[12] = vue.createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Duration", -1)),
435
- vue.createElementVNode("div", _hoisted_32, vue.toDisplayString(totalDuration.value), 1)
394
+ _cache[13] || (_cache[13] = vue.createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Duration", -1)),
395
+ vue.createElementVNode("div", _hoisted_25, vue.toDisplayString(totalDuration.value), 1)
436
396
  ])
437
397
  ]),
438
- album.value.label ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_33, [
439
- vue.createElementVNode("div", _hoisted_34, [
440
- vue.createVNode(IconMusic.default, { class: "w-1-5r h-1-5r t-primary" })
441
- ]),
398
+ album.value.label ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_26, [
399
+ vue.createVNode(IconMusic.default, { class: "i-regular t-primary" }),
442
400
  vue.createElementVNode("div", null, [
443
- _cache[13] || (_cache[13] = vue.createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Label", -1)),
444
- vue.createElementVNode("div", _hoisted_35, vue.toDisplayString(album.value.label), 1)
401
+ _cache[14] || (_cache[14] = vue.createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Label", -1)),
402
+ vue.createElementVNode("div", _hoisted_27, vue.toDisplayString(album.value.label), 1)
445
403
  ])
446
404
  ])) : vue.createCommentVNode("", true),
447
- vue.createElementVNode("div", _hoisted_36, [
448
- vue.createElementVNode("div", _hoisted_37, [
449
- vue.createVNode(IconShow.default, { class: "w-1-5r h-1-5r t-primary" })
450
- ]),
405
+ vue.createElementVNode("div", _hoisted_28, [
406
+ vue.createVNode(IconShow.default, { class: "i-regular t-primary" }),
451
407
  vue.createElementVNode("div", null, [
452
- _cache[14] || (_cache[14] = vue.createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Visibility", -1)),
453
- vue.createElementVNode("div", _hoisted_38, vue.toDisplayString(album.value.isPublic ? "Public" : "Private"), 1)
408
+ _cache[15] || (_cache[15] = vue.createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Visibility", -1)),
409
+ vue.createElementVNode("div", _hoisted_29, vue.toDisplayString(album.value.isPublic ? "Public" : "Private"), 1)
454
410
  ])
455
411
  ])
456
412
  ]),
457
- album.value.genres && album.value.genres.length || album.value.tags && album.value.tags.length ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_39, [
458
- _cache[15] || (_cache[15] = vue.createElementVNode("h3", { class: "t-medium mn-b-small" }, "Genres & Tags", -1)),
459
- vue.createElementVNode("div", _hoisted_40, [
413
+ album.value.genres && album.value.genres.length || album.value.tags && album.value.tags.length ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_30, [
414
+ _cache[16] || (_cache[16] = vue.createElementVNode("h3", { class: "t-medium mn-b-small" }, "Genres & Tags", -1)),
415
+ vue.createElementVNode("div", _hoisted_31, [
460
416
  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(album.value.genres, (genre) => {
461
417
  return vue.openBlock(), vue.createElementBlock("span", {
462
418
  key: genre,
463
- class: "tag bg-primary-transp-20 t-primary pd-thin-big radius-small t-small hover-bg-primary-transp-30 cursor-pointer"
419
+ class: "tag bg-main t-medium pd-thin radius-thin t-small cursor-pointer"
464
420
  }, vue.toDisplayString(genre), 1);
465
421
  }), 128)),
466
422
  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(album.value.tags, (tag) => {
@@ -470,15 +426,11 @@ const _sfc_main = {
470
426
  }, " #" + vue.toDisplayString(tag), 1);
471
427
  }), 128))
472
428
  ])
473
- ])) : vue.createCommentVNode("", true),
474
- album.value.description ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_41, [
475
- _cache[16] || (_cache[16] = vue.createElementVNode("h3", { class: "t-medium mn-b-small" }, "About", -1)),
476
- vue.createElementVNode("p", _hoisted_42, vue.toDisplayString(album.value.description), 1)
477
429
  ])) : vue.createCommentVNode("", true)
478
430
  ])
479
431
  ])) : vue.createCommentVNode("", true),
480
- !_ctx.isLoading && album.value && albumTracks.value.length ? (vue.openBlock(), vue.createElementBlock("section", _hoisted_43, [
481
- _cache[17] || (_cache[17] = vue.createElementVNode("h2", { class: "h2 mn-b-medium" }, "Tracklist", -1)),
432
+ !_ctx.isLoading && album.value && albumTracks.value.length ? (vue.openBlock(), vue.createElementBlock("section", _hoisted_32, [
433
+ _cache[18] || (_cache[18] = vue.createElementVNode("h2", { class: "h2 mn-b-medium" }, "Tracklist", -1)),
482
434
  vue.createVNode(Feed.default, {
483
435
  store: {
484
436
  read: () => _ctx.Promise.resolve(albumTracks.value),
@@ -495,7 +447,7 @@ const _sfc_main = {
495
447
  }
496
448
  }, {
497
449
  default: vue.withCtx(({ items }) => [
498
- vue.createElementVNode("div", _hoisted_44, [
450
+ vue.createElementVNode("div", _hoisted_33, [
499
451
  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(items, (track, index) => {
500
452
  return vue.openBlock(), vue.createBlock(TrackListCard.default, {
501
453
  key: track._id,
@@ -510,21 +462,21 @@ const _sfc_main = {
510
462
  _: 1
511
463
  }, 8, ["store", "items"])
512
464
  ])) : vue.createCommentVNode("", true),
513
- !_ctx.isLoading && album.value && moreAlbums.value.length ? (vue.openBlock(), vue.createElementBlock("section", _hoisted_45, [
514
- vue.createElementVNode("div", _hoisted_46, [
515
- _cache[19] || (_cache[19] = vue.createElementVNode("h2", { class: "h2" }, "More Albums", -1)),
465
+ !_ctx.isLoading && album.value && moreAlbums.value.length ? (vue.openBlock(), vue.createElementBlock("section", _hoisted_34, [
466
+ vue.createElementVNode("div", _hoisted_35, [
467
+ _cache[20] || (_cache[20] = vue.createElementVNode("h2", { class: "h2" }, "More Albums", -1)),
516
468
  album.value.artists && album.value.artists[0] ? (vue.openBlock(), vue.createBlock(_component_router_link, {
517
469
  key: 0,
518
- to: `/artist/${album.value.artists[0].url}`,
470
+ to: { name: "artist", params: { url: album.value.artists[0].url } },
519
471
  class: "t-primary hover-opacity"
520
472
  }, {
521
- default: vue.withCtx(() => _cache[18] || (_cache[18] = [
473
+ default: vue.withCtx(() => _cache[19] || (_cache[19] = [
522
474
  vue.createTextVNode(" See all ")
523
475
  ])),
524
476
  _: 1
525
477
  }, 8, ["to"])) : vue.createCommentVNode("", true)
526
478
  ]),
527
- vue.createElementVNode("div", _hoisted_47, [
479
+ vue.createElementVNode("div", _hoisted_36, [
528
480
  (vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(moreAlbums.value, (relatedAlbum) => {
529
481
  return vue.openBlock(), vue.createElementBlock("li", {
530
482
  key: album.value._id,
@@ -1 +1 @@
1
- {"version":3,"file":"Album.vue.cjs","sources":["../../../../../../../src/modules/music/components/pages/Album.vue"],"sourcesContent":["<!-- components/pages/Album.vue -->\n<template>\n <div class=\"album-page pd-small\">\n <!-- Loading -->\n <div v-if=\"isLoading\" class=\"w-100 h-25r flex-center flex\">\n <Loader />\n </div>\n \n <!-- Not Found -->\n <div v-if=\"hasLoaded && !album\" class=\"t-center pd-big\">\n <h2 class=\"\">Album not found</h2>\n <p class=\"t-transp t-medium\">The album you're looking for doesn't exist or has been removed.</p>\n </div>\n \n <!-- Album Content -->\n <div v-if=\"album\" class=\"album-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 album-cover-section\">\n <!-- Cover -->\n <div class=\"cover-container relative mn-b-medium radius-big overflow-hidden shadow-big\">\n <Media \n :url=\"album.coverArt || '/logo/logo-placeholder.jpg'\"\n :alt=\"album.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\">{{ album.totalTracks || 0 }}</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(album.views) }}</div>\n <div class=\"t-small t-transp t-uppercase\">Views</div>\n </div>\n </div>\n </div>\n\n <!-- Right Column - Album Details -->\n <div class=\"album-details-section\">\n <!-- Album 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 {{ album.type }}\n </span>\n <span v-if=\"album.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 <!-- Album Title -->\n <h1 class=\"h1 mn-b-medium\">{{ album.title }}</h1>\n\n <!-- Action Buttons -->\n <div class=\"flex gap-small mn-b-medium\">\n <Button\n @click=\"playAlbum\"\n color=\"primary\"\n size=\"medium\"\n class=\"flex-1 flex-center gap-thin\"\n >\n <IconPlay class=\"w-1r h-1r\" />\n Play All\n </Button>\n \n <Button\n @click=\"toggleFavorite\"\n :color=\"isFavorite ? 'danger' : 'transp'\"\n size=\"medium\"\n class=\"w-3r h-3r radius-full\"\n >\n <IconLike class=\"w-1-25r h-1-25r\" :fill=\"isFavorite\" />\n </Button>\n \n <Button\n @click=\"shufflePlay\"\n color=\"transp\"\n size=\"medium\"\n class=\"w-3r h-3r radius-full\"\n >\n <IconShuffle class=\"w-1-25r h-1-25r\" />\n </Button>\n \n <Dropdown 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\">\n <hr class=\"mn-v-thin border-dark-transp-10\" />\n <Button @click=\"editAlbum\" color=\"transp\" size=\"small\" class=\"w-100 justify-start\">\n Edit Album\n </Button>\n <Button @click=\"deleteAlbum\" color=\"danger\" size=\"small\" class=\"w-100 justify-start\">\n Delete Album\n </Button>\n </template>\n </div>\n </template>\n </Dropdown>\n </div>\n\n <!-- Artists Cards -->\n <div class=\"artists-section mn-b-big\">\n <h3 class=\"t-medium mn-b-small\" v-if=\"album.artists && album.artists.length > 1\">Artists</h3>\n <div class=\"flex flex-col gap-small\">\n <div \n v-for=\"artist in album.artists\" \n :key=\"artist._id\"\n class=\"artist-card bg-light pd-medium radius-medium flex items-center gap-medium\"\n >\n <router-link \n :to=\"`/artist/${artist.url}`\"\n class=\"flex items-center gap-medium flex-1 hover-opacity\"\n >\n <div class=\"artist-avatar\">\n <Media \n v-if=\"artist.photoUrl\"\n :url=\"artist.photoUrl\"\n :alt=\"artist.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 {{ artist.name.charAt(0) }}\n </div>\n </div>\n <div>\n <div class=\"flex items-center gap-thin\">\n <span class=\"t-large \">{{ artist.name }}</span>\n <IconVerified v-if=\"artist.isVerified\" class=\"w-1r h-1r t-primary\" />\n </div>\n <span class=\"t-small t-transp\">Artist</span>\n </div>\n </router-link>\n <Button \n v-if=\"!isOwner\"\n @click=\"() => toggleFollowArtist(artist._id)\"\n :color=\"followedArtists.includes(artist._id) ? 'primary' : 'transp'\"\n size=\"small\"\n >\n {{ followedArtists.includes(artist._id) ? 'Following' : 'Follow' }}\n </Button>\n </div>\n </div>\n </div>\n\n <!-- Metadata Cards -->\n <div class=\"metadata-grid grid cols-2 gap-small mn-b-big\">\n <!-- Release Date -->\n <div class=\"metadata-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <div class=\"icon-wrapper bg-primary-transp-20 w-3r h-3r radius-small flex-center\">\n <IconCalendar class=\"w-1-5r h-1-5r t-primary\" />\n </div>\n <div>\n <div class=\"t-small t-transp t-uppercase\">Released</div>\n <div class=\"t-medium \">{{ formatDate(album.releaseDate) }}</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 <div class=\"icon-wrapper bg-primary-transp-20 w-3r h-3r radius-small flex-center\">\n <IconClock class=\"w-1-5r h-1-5r t-primary\" />\n </div>\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 <!-- Label -->\n <div v-if=\"album.label\" class=\"metadata-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <div class=\"icon-wrapper bg-primary-transp-20 w-3r h-3r radius-small flex-center\">\n <IconDisc class=\"w-1-5r h-1-5r t-primary\" />\n </div>\n <div>\n <div class=\"t-small t-transp t-uppercase\">Label</div>\n <div class=\"t-medium \">{{ album.label }}</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 <div class=\"icon-wrapper bg-primary-transp-20 w-3r h-3r radius-small flex-center\">\n <IconEye class=\"w-1-5r h-1-5r t-primary\" />\n </div>\n <div>\n <div class=\"t-small t-transp t-uppercase\">Visibility</div>\n <div class=\"t-medium \">{{ album.isPublic ? 'Public' : 'Private' }}</div>\n </div>\n </div>\n </div>\n\n <!-- Genres & Tags -->\n <div v-if=\"(album.genres && album.genres.length) || (album.tags && album.tags.length)\" class=\"tags-section mn-b-medium\">\n <h3 class=\"t-medium mn-b-small\">Genres & Tags</h3>\n <div class=\"flex gap-thin flex-wrap\">\n <span \n v-for=\"genre in album.genres\" \n :key=\"genre\"\n class=\"tag bg-primary-transp-20 t-primary pd-thin-big radius-small t-small hover-bg-primary-transp-30 cursor-pointer\"\n >\n {{ genre }}\n </span>\n <span \n v-for=\"tag in album.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=\"album.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\">{{ album.description }}</p>\n </div>\n </div>\n </div>\n\n <!-- Album Tracks -->\n <section v-if=\"!isLoading && album && albumTracks.length\" class=\"tracks-section mn-t-big\">\n <h2 class=\"h2 mn-b-medium\">Tracklist</h2>\n <Feed\n :store=\"{\n read: () => Promise.resolve(albumTracks),\n state: { isLoading: false }\n }\"\n :external=\"true\"\n :items=\"albumTracks\"\n :states=\"{\n empty: {\n title: 'No tracks in album',\n description: 'This album appears to be empty',\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=\"false\"\n :showCover=\"false\"\n />\n </div>\n </template>\n </Feed>\n </section>\n\n <!-- More from Artists -->\n <section v-if=\"!isLoading && album && moreAlbums.length\" class=\"more-albums-section mn-t-big\">\n <div class=\"flex justify-between items-center mn-b-medium\">\n <h2 class=\"h2\">More Albums</h2>\n <router-link \n v-if=\"album.artists && album.artists[0]\"\n :to=\"`/artist/${album.artists[0].url}`\" \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 >\n <li v-for=\"relatedAlbum in moreAlbums\" :key=\"album._id\" class=\"flex-none scroll-snap-align-start\">\n <AlbumCard :album=\"relatedAlbum\" class=\"w-min-15r transition-cubic-in-out\" />\n </li>\n </div>\n </section>\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';\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 IconDisc from '@martyrs/src/modules/icons/entities/IconMusic.vue';\nimport IconVerified from '@martyrs/src/modules/icons/navigation/IconCheckmark.vue';\n\n// Components\nimport TrackListCard from '../cards/TrackListCard.vue';\nimport AlbumCard from '../cards/AlbumCard.vue';\n\n// Store\nimport { state as albumsState, actions as albumsActions } from '../../store/albums.js';\nimport { actions as playerActions } from '../../store/player.js';\nimport { state as authState } from '@martyrs/src/modules/auth/views/store/auth.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 isFavorite = ref(false);\nconst showDropdown = ref(false);\nconst followedArtists = ref([]);\nconst moreAlbums = ref([]);\n\n// Clear state\nalbumsState.currentAlbum = null;\nalbumsState.currentAlbumTracks = [];\n\n// Computed\nconst album = computed(() => albumsState.currentAlbum);\nconst albumTracks = computed(() => albumsState.currentAlbumTracks || []);\n\nconst isOwner = computed(() => {\n return album.value?.owner?.target === authState.user?._id;\n});\n\nconst totalDuration = computed(() => {\n if (!albumTracks.value.length) return '0:00';\n const totalSeconds = albumTracks.value.reduce((sum, track) => sum + (track.duration || 0), 0);\n return formatDuration(totalSeconds);\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 playAlbum = () => {\n if (albumTracks.value && albumTracks.value.length > 0) {\n playerActions.setQueue(albumTracks.value);\n }\n};\n\nconst shufflePlay = () => {\n if (albumTracks.value && albumTracks.value.length > 0) {\n const shuffled = [...albumTracks.value].sort(() => Math.random() - 0.5);\n playerActions.setQueue(shuffled);\n }\n};\n\nconst toggleFavorite = () => {\n isFavorite.value = !isFavorite.value;\n // TODO: Implement actual saving\n};\n\nconst toggleFollowArtist = (artistId) => {\n const index = followedArtists.value.indexOf(artistId);\n if (index > -1) {\n followedArtists.value.splice(index, 1);\n } else {\n followedArtists.value.push(artistId);\n }\n // TODO: Implement actual following\n};\n\nconst addToQueue = () => {\n if (albumTracks.value.length > 0) {\n albumTracks.value.forEach(track => {\n playerActions.addToQueue(track);\n });\n showDropdown.value = false;\n }\n};\n\nconst editAlbum = () => {\n router.push({ name: 'album-edit', params: { url: album.value.url } });\n};\n\nconst deleteAlbum = async () => {\n if (confirm('Are you sure you want to delete this album?')) {\n try {\n await albumsActions.deleteAlbum(album.value._id);\n router.push({ name: 'music-library' });\n } catch (error) {\n console.error('Failed to delete album:', error);\n }\n }\n};\n\nconst copyLink = () => {\n navigator.clipboard.writeText(window.location.href);\n showDropdown.value = false;\n};\n\n// Data fetching\nconst fetchAlbumData = async () => {\n try {\n await albumsActions.fetchAlbumByUrl(route.params.url);\n \n // Fetch more albums from the same artists\n if (album.value?.artists?.length) {\n const artistIds = album.value.artists.map(a => a._id);\n const albums = await albumsActions.fetchAlbums({\n artist: { $in: artistIds },\n status: 'published',\n isPublic: true,\n limit: 6\n });\n \n // Filter out current album\n moreAlbums.value = albums.filter(a => a._id !== album.value._id).slice(0, 5);\n }\n } catch (error) {\n console.error('Error fetching album data:', error);\n }\n};\n\n// Lifecycle\nonMounted(async () => {\n emits('page-loading');\n \n await fetchAlbumData();\n \n hasLoaded.value = true;\n emits('page-loaded');\n});\n</script>\n\n<style scoped>\n</style>"],"names":["useRoute","useRouter","ref","albumsState","computed","authState","playerActions","albumsActions","albums","onMounted"],"mappings":"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"}
1
+ {"version":3,"file":"Album.vue.cjs","sources":["../../../../../../../src/modules/music/components/pages/Album.vue"],"sourcesContent":["<!-- components/pages/Album.vue -->\n<template>\n <div class=\"album-page pd-small\">\n <!-- Loading -->\n <div v-if=\"isLoading\" class=\"w-100 h-25r flex-center flex\">\n <Loader />\n </div>\n \n <!-- Not Found -->\n <div v-if=\"hasLoaded && !album\" class=\"t-center pd-big\">\n <h2 class=\"\">Album not found</h2>\n <p class=\"t-transp t-medium\">The album you're looking for doesn't exist or has been removed.</p>\n </div>\n \n <!-- Album Content -->\n <div v-if=\"album\" class=\"album-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 album-cover-section\">\n <!-- Cover -->\n <Media \n :url=\"album.coverArt || '/logo/logo-placeholder.jpg'\"\n :alt=\"album.title\"\n class=\"aspect-1x1 w-100 w-max-30r mn-b-small radius-medium o-hidden\"\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\">{{ album.totalTracks || 0 }}</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(album.views) }}</div>\n <div class=\"t-small t-transp t-uppercase\">Views</div>\n </div>\n </div>\n </div>\n\n <!-- Right Column - Album Details -->\n <div class=\"album-details-section\">\n <!-- Album Type Badge -->\n <div class=\"flex items-center gap-small mn-b-small\">\n <span class=\"bg-light t-medium pd-thin radius-thin uppercase t-small t-uppercase\">\n {{ album.type }}\n </span>\n <span v-if=\"album.status === 'published'\" class=\"bg-light t-medium pd-thin radius-thin uppercase t-small t-uppercase\">\n Published\n </span>\n </div>\n\n <!-- Album Title -->\n <h1 class=\"h1 mn-b-medium\">{{ album.title }}</h1>\n\n <!-- Action Buttons -->\n <div class=\"flex gap-small mn-b-medium\">\n <Button\n @click=\"playAlbum\"\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=\"toggleFavorite\"\n color=\"primary\"\n size=\"medium\"\n class=\"flex-1 bg-light radius-thin flex-center gap-thin\"\n >\n <IconLike class=\"i-medium\" :fill=\"isFavorite ? 'rgb(var(--main)':'rgb(var(--black)'\" />\n {{isFavorite ? 'Liked' : 'Like'}}\n </Button>\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 <Button @click=\"addToPlaylist\" color=\"transp\" size=\"small\" class=\"w-100 justify-start\">\n Add to Playlist\n </Button>\n <template v-if=\"isOwner\">\n <hr class=\"mn-v-thin border-dark-transp-10\" />\n <Button @click=\"editAlbum\" color=\"transp\" size=\"small\" class=\"w-100 justify-start\">\n Edit Album\n </Button>\n <Button @click=\"deleteAlbum\" color=\"danger\" size=\"small\" class=\"w-100 justify-start\">\n Delete Album\n </Button>\n </template>\n </div>\n </template>\n </Dropdown>\n </div>\n\n <!-- Artists Cards -->\n <div class=\"artists-section mn-b-medium\">\n <h3 class=\"t-medium mn-b-small\" v-if=\"album.artists\">Artists</h3>\n <div class=\"flex flex-col gap-small\">\n <ArtistCardSmall \n v-for=\"artist in album.artists\" \n :key=\"artist._id\"\n :artist=\"artist\"\n :is-following=\"followedArtists.includes(artist._id)\"\n :show-follow-button=\"!isOwner\"\n @toggle-follow=\"toggleFollowArtist\"\n />\n </div>\n </div>\n\n <!-- Metadata Cards -->\n <h3 class=\"t-medium mn-b-small\">Metadata</h3>\n <div class=\"metadata-grid grid cols-2 gap-small mn-b-medium\">\n <!-- Release Date -->\n <div class=\"metadata-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <IconCalendar class=\"i-regular t-primary\" />\n <div>\n <div class=\"t-small t-transp t-uppercase\">Released</div>\n <div class=\"t-medium \">{{ formatDate(album.releaseDate) }}</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-regular 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 <!-- Label -->\n <div v-if=\"album.label\" class=\"metadata-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <IconDisc class=\"i-regular t-primary\" />\n <div>\n <div class=\"t-small t-transp t-uppercase\">Label</div>\n <div class=\"t-medium \">{{ album.label }}</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-regular t-primary\" />\n <div>\n <div class=\"t-small t-transp t-uppercase\">Visibility</div>\n <div class=\"t-medium \">{{ album.isPublic ? 'Public' : 'Private' }}</div>\n </div>\n </div>\n </div>\n\n <!-- Genres & Tags -->\n <div v-if=\"(album.genres && album.genres.length) || (album.tags && album.tags.length)\" class=\"tags-section mn-b-medium\">\n <h3 class=\"t-medium mn-b-small\">Genres & Tags</h3>\n <div class=\"flex gap-thin flex-wrap\">\n <span \n v-for=\"genre in album.genres\" \n :key=\"genre\"\n class=\"tag bg-main t-medium pd-thin radius-thin t-small cursor-pointer\"\n >\n {{ genre }}\n </span>\n <span \n v-for=\"tag in album.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 </div>\n </div>\n\n <!-- Album Tracks -->\n <section v-if=\"!isLoading && album && albumTracks.length\" class=\"tracks-section mn-t-big\">\n <h2 class=\"h2 mn-b-medium\">Tracklist</h2>\n <Feed\n :store=\"{\n read: () => Promise.resolve(albumTracks),\n state: { isLoading: false }\n }\"\n :external=\"true\"\n :items=\"albumTracks\"\n :states=\"{\n empty: {\n title: 'No tracks in album',\n description: 'This album appears to be empty',\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=\"false\"\n :showCover=\"false\"\n />\n </div>\n </template>\n </Feed>\n </section>\n\n <!-- More from Artists -->\n <section v-if=\"!isLoading && album && moreAlbums.length\" class=\"more-albums-section mn-t-big\">\n <div class=\"flex justify-between items-center mn-b-medium\">\n <h2 class=\"h2\">More Albums</h2>\n <router-link \n v-if=\"album.artists && album.artists[0]\"\n :to=\"{ name: 'artist', params: { url: album.artists[0].url } }\" \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 >\n <li v-for=\"relatedAlbum in moreAlbums\" :key=\"album._id\" class=\"flex-none scroll-snap-align-start\">\n <AlbumCard :album=\"relatedAlbum\" class=\"w-min-15r transition-cubic-in-out\" />\n </li>\n </div>\n </section>\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';\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 IconDisc from '@martyrs/src/modules/icons/entities/IconMusic.vue';\nimport IconVerified from '@martyrs/src/modules/icons/navigation/IconCheckmark.vue';\n\n// Components\nimport TrackListCard from '../cards/TrackListCard.vue';\nimport AlbumCard from '../cards/AlbumCard.vue';\nimport ArtistCardSmall from '../cards/ArtistCardSmall.vue';\n\n// Store\nimport { state as albumsState, actions as albumsActions } from '../../store/albums.js';\nimport { actions as playerActions } from '../../store/player.js';\nimport { state as authState } from '@martyrs/src/modules/auth/views/store/auth.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 isFavorite = ref(false);\nconst showDropdown = ref(false);\nconst followedArtists = ref([]);\nconst moreAlbums = ref([]);\n\n// Clear state\nalbumsState.currentAlbum = null;\nalbumsState.currentAlbumTracks = [];\n\n// Computed\nconst album = computed(() => albumsState.currentAlbum);\nconst albumTracks = computed(() => albumsState.currentAlbumTracks || []);\n\nconst isOwner = computed(() => {\n return album.value?.owner?.target === authState.user?._id;\n});\n\nconst totalDuration = computed(() => {\n if (!albumTracks.value.length) return '0:00';\n const totalSeconds = albumTracks.value.reduce((sum, track) => sum + (track.duration || 0), 0);\n return formatDuration(totalSeconds);\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 playAlbum = () => {\n if (albumTracks.value && albumTracks.value.length > 0) {\n playerActions.setQueue(albumTracks.value);\n }\n};\n\nconst shufflePlay = () => {\n if (albumTracks.value && albumTracks.value.length > 0) {\n const shuffled = [...albumTracks.value].sort(() => Math.random() - 0.5);\n playerActions.setQueue(shuffled);\n }\n};\n\nconst toggleFavorite = () => {\n isFavorite.value = !isFavorite.value;\n // TODO: Implement actual saving\n};\n\nconst toggleFollowArtist = (artistId) => {\n const index = followedArtists.value.indexOf(artistId);\n if (index > -1) {\n followedArtists.value.splice(index, 1);\n } else {\n followedArtists.value.push(artistId);\n }\n // TODO: Implement actual following\n};\n\nconst addToQueue = () => {\n if (albumTracks.value.length > 0) {\n albumTracks.value.forEach(track => {\n playerActions.addToQueue(track);\n });\n showDropdown.value = false;\n }\n};\n\nconst editAlbum = () => {\n router.push({ name: 'album-edit', params: { url: album.value.url } });\n};\n\nconst deleteAlbum = async () => {\n if (confirm('Are you sure you want to delete this album?')) {\n try {\n await albumsActions.deleteAlbum(album.value._id);\n router.push({ name: 'music-library' });\n } catch (error) {\n console.error('Failed to delete album:', error);\n }\n }\n};\n\nconst copyLink = () => {\n navigator.clipboard.writeText(window.location.href);\n showDropdown.value = false;\n};\n\n// Data fetching\nconst fetchAlbumData = async () => {\n try {\n await albumsActions.fetchAlbumByUrl(route.params.url);\n \n // Fetch more albums from the same artists\n if (album.value?.artists?.length) {\n const artistIds = album.value.artists.map(a => a._id);\n const albums = await albumsActions.fetchAlbums({\n artist: { $in: artistIds },\n status: 'published',\n isPublic: true,\n limit: 6\n });\n \n // Filter out current album\n moreAlbums.value = albums.filter(a => a._id !== album.value._id).slice(0, 5);\n }\n } catch (error) {\n console.error('Error fetching album data:', error);\n }\n};\n\n// Lifecycle\nonMounted(async () => {\n emits('page-loading');\n \n await fetchAlbumData();\n \n hasLoaded.value = true;\n emits('page-loaded');\n});\n</script>\n\n<style scoped>\n</style>"],"names":["useRoute","useRouter","ref","albumsState","computed","authState","playerActions","albumsActions","albums","onMounted"],"mappings":"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"}