@ozdao/martyrs 0.2.494 → 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.
- package/dist/_virtual/index.cjs +4 -4
- package/dist/_virtual/index.js +4 -4
- package/dist/_virtual/index2.cjs +4 -4
- package/dist/_virtual/index2.js +4 -4
- package/dist/builder.cjs +42 -43
- package/dist/builder.js +44 -45
- package/dist/martyrs/src/components/FieldTags/FieldTags.vue.cjs +1 -1
- package/dist/martyrs/src/components/FieldTags/FieldTags.vue.js +1 -1
- package/dist/martyrs/src/modules/community/components/pages/CreateBlogPost.vue.cjs +1 -1
- package/dist/martyrs/src/modules/community/components/pages/CreateBlogPost.vue.js +1 -1
- package/dist/martyrs/src/modules/globals/globals.client.cjs +1 -1
- package/dist/martyrs/src/modules/globals/globals.client.cjs.map +1 -1
- package/dist/martyrs/src/modules/globals/globals.client.js +1 -1
- package/dist/martyrs/src/modules/globals/globals.client.js.map +1 -1
- package/dist/martyrs/src/modules/globals/views/classes/globals.i18n.cjs +1 -1
- package/dist/martyrs/src/modules/globals/views/classes/globals.i18n.js +1 -1
- package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.cjs +28 -13
- package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.js +28 -13
- package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.js.map +1 -1
- package/dist/martyrs/src/modules/globals/views/router/scrollBehavior.cjs +1 -1
- package/dist/martyrs/src/modules/globals/views/router/scrollBehavior.cjs.map +1 -1
- package/dist/martyrs/src/modules/globals/views/router/scrollBehavior.js +1 -1
- package/dist/martyrs/src/modules/globals/views/router/scrollBehavior.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.cjs +1 -1
- package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.cjs +2 -2
- package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.js +2 -2
- package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/Album.vue.cjs +86 -81
- package/dist/martyrs/src/modules/music/components/pages/Album.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/Album.vue.js +88 -83
- package/dist/martyrs/src/modules/music/components/pages/Album.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/Artist.vue.cjs +4 -4
- package/dist/martyrs/src/modules/music/components/pages/Artist.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/Artist.vue.js +4 -4
- package/dist/martyrs/src/modules/music/components/pages/Artist.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.cjs +5 -5
- package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.js +5 -5
- package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.cjs +12 -9
- package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.js +12 -9
- package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/SearchResults.vue.cjs +7 -7
- package/dist/martyrs/src/modules/music/components/pages/SearchResults.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/SearchResults.vue.js +7 -7
- package/dist/martyrs/src/modules/music/components/pages/SearchResults.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/Track.vue.cjs +43 -37
- package/dist/martyrs/src/modules/music/components/pages/Track.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/Track.vue.js +45 -39
- package/dist/martyrs/src/modules/music/components/pages/Track.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/music.client.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/music.client.js.map +1 -1
- package/dist/martyrs/src/modules/notifications/notifications.client.cjs +1 -1
- package/dist/martyrs/src/modules/notifications/notifications.client.cjs.map +1 -1
- package/dist/martyrs/src/modules/notifications/notifications.client.js +1 -1
- package/dist/martyrs/src/modules/notifications/notifications.client.js.map +1 -1
- package/dist/style.css +5 -5
- package/package.json +1 -1
- package/src/builder/rspack/rspack.config.ssr.client.js +41 -41
- package/src/modules/globals/globals.client.js +1 -2
- package/src/modules/globals/views/components/layouts/Client.vue +13 -11
- package/src/modules/globals/views/router/scrollBehavior.js +1 -1
- package/src/modules/music/components/SidebarMusic.vue +7 -7
- package/src/modules/music/components/cards/TrackListCard.vue +1 -1
- package/src/modules/music/components/forms/SearchForm.vue +1 -1
- package/src/modules/music/components/pages/Album.vue +26 -29
- package/src/modules/music/components/pages/Artist.vue +4 -4
- package/src/modules/music/components/pages/MusicLibrary.vue +5 -5
- package/src/modules/music/components/pages/Playlist.vue +9 -9
- package/src/modules/music/components/pages/SearchResults.vue +6 -6
- package/src/modules/music/components/pages/Track.vue +22 -20
- package/src/modules/music/music.client.js +1 -1
- package/src/modules/notifications/notifications.client.js +1 -1
|
@@ -229,40 +229,46 @@ const _sfc_main = {
|
|
|
229
229
|
onClick: playTrack,
|
|
230
230
|
color: "primary",
|
|
231
231
|
size: "medium",
|
|
232
|
-
class: "flex-1 flex-center gap-thin"
|
|
232
|
+
class: "flex-1 t-white bg-black radius-thin flex-center gap-thin"
|
|
233
233
|
}, {
|
|
234
234
|
default: vue.withCtx(() => [
|
|
235
|
-
vue.createVNode(IconPlay.default, {
|
|
235
|
+
vue.createVNode(IconPlay.default, {
|
|
236
|
+
fill: "rgb(var(--white))",
|
|
237
|
+
class: "i-medium"
|
|
238
|
+
}),
|
|
236
239
|
_cache[7] || (_cache[7] = vue.createTextVNode(" Play "))
|
|
237
240
|
]),
|
|
238
241
|
_: 1
|
|
239
242
|
}),
|
|
240
243
|
vue.createVNode(Button.default, {
|
|
241
|
-
onClick:
|
|
242
|
-
color:
|
|
244
|
+
onClick: addToQueue,
|
|
245
|
+
color: "primary",
|
|
243
246
|
size: "medium",
|
|
244
|
-
class: "
|
|
247
|
+
class: "flex-1 bg-light radius-thin flex-center gap-thin"
|
|
245
248
|
}, {
|
|
246
249
|
default: vue.withCtx(() => [
|
|
247
|
-
vue.createVNode(
|
|
248
|
-
|
|
249
|
-
fill: isFavorite.value
|
|
250
|
-
}, null, 8, ["fill"])
|
|
250
|
+
vue.createVNode(IconAdd.default, { class: "i-medium" }),
|
|
251
|
+
_cache[8] || (_cache[8] = vue.createTextVNode(" Add to Queue "))
|
|
251
252
|
]),
|
|
252
253
|
_: 1
|
|
253
|
-
}
|
|
254
|
+
}),
|
|
254
255
|
vue.createVNode(Button.default, {
|
|
255
|
-
onClick:
|
|
256
|
-
color: "
|
|
256
|
+
onClick: toggleFavorite,
|
|
257
|
+
color: "primary",
|
|
257
258
|
size: "medium",
|
|
258
|
-
class: "
|
|
259
|
+
class: "flex-1 bg-light radius-thin flex-center gap-thin"
|
|
259
260
|
}, {
|
|
260
261
|
default: vue.withCtx(() => [
|
|
261
|
-
vue.createVNode(
|
|
262
|
+
vue.createVNode(IconLike.default, {
|
|
263
|
+
class: "i-medium",
|
|
264
|
+
fill: isFavorite.value
|
|
265
|
+
}, null, 8, ["fill"]),
|
|
266
|
+
vue.createTextVNode(" " + vue.toDisplayString(isFavorite.value ? "Liked" : "Like"), 1)
|
|
262
267
|
]),
|
|
263
268
|
_: 1
|
|
264
269
|
}),
|
|
265
270
|
vue.createVNode(Dropdown.default, {
|
|
271
|
+
label: { component: IconEllipsis.default, class: "bg-light radius-thin pd-thin i-big" },
|
|
266
272
|
modelValue: showDropdown.value,
|
|
267
273
|
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => showDropdown.value = $event),
|
|
268
274
|
class: "relative"
|
|
@@ -287,7 +293,7 @@ const _sfc_main = {
|
|
|
287
293
|
size: "small",
|
|
288
294
|
class: "w-100 justify-start"
|
|
289
295
|
}, {
|
|
290
|
-
default: vue.withCtx(() => _cache[
|
|
296
|
+
default: vue.withCtx(() => _cache[9] || (_cache[9] = [
|
|
291
297
|
vue.createTextVNode(" Add to Playlist ")
|
|
292
298
|
])),
|
|
293
299
|
_: 1
|
|
@@ -298,20 +304,20 @@ const _sfc_main = {
|
|
|
298
304
|
size: "small",
|
|
299
305
|
class: "w-100 justify-start"
|
|
300
306
|
}, {
|
|
301
|
-
default: vue.withCtx(() => _cache[
|
|
307
|
+
default: vue.withCtx(() => _cache[10] || (_cache[10] = [
|
|
302
308
|
vue.createTextVNode(" Copy Link ")
|
|
303
309
|
])),
|
|
304
310
|
_: 1
|
|
305
311
|
}),
|
|
306
312
|
isOwner.value ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
|
|
307
|
-
_cache[
|
|
313
|
+
_cache[13] || (_cache[13] = vue.createElementVNode("hr", { class: "mn-v-thin border-dark-transp-10" }, null, -1)),
|
|
308
314
|
vue.createVNode(Button.default, {
|
|
309
315
|
onClick: editTrack,
|
|
310
316
|
color: "transp",
|
|
311
317
|
size: "small",
|
|
312
318
|
class: "w-100 justify-start"
|
|
313
319
|
}, {
|
|
314
|
-
default: vue.withCtx(() => _cache[
|
|
320
|
+
default: vue.withCtx(() => _cache[11] || (_cache[11] = [
|
|
315
321
|
vue.createTextVNode(" Edit Track ")
|
|
316
322
|
])),
|
|
317
323
|
_: 1
|
|
@@ -322,7 +328,7 @@ const _sfc_main = {
|
|
|
322
328
|
size: "small",
|
|
323
329
|
class: "w-100 justify-start"
|
|
324
330
|
}, {
|
|
325
|
-
default: vue.withCtx(() => _cache[
|
|
331
|
+
default: vue.withCtx(() => _cache[12] || (_cache[12] = [
|
|
326
332
|
vue.createTextVNode(" Delete Track ")
|
|
327
333
|
])),
|
|
328
334
|
_: 1
|
|
@@ -331,11 +337,11 @@ const _sfc_main = {
|
|
|
331
337
|
])
|
|
332
338
|
]),
|
|
333
339
|
_: 1
|
|
334
|
-
}, 8, ["modelValue"])
|
|
340
|
+
}, 8, ["label", "modelValue"])
|
|
335
341
|
]),
|
|
336
342
|
vue.createElementVNode("div", _hoisted_18, [
|
|
337
343
|
vue.createVNode(_component_router_link, {
|
|
338
|
-
to:
|
|
344
|
+
to: { name: "artist", params: { url: track.value.artist.url } },
|
|
339
345
|
class: "flex items-center gap-medium flex-1 hover-opacity"
|
|
340
346
|
}, {
|
|
341
347
|
default: vue.withCtx(() => [
|
|
@@ -355,7 +361,7 @@ const _sfc_main = {
|
|
|
355
361
|
class: "w-1r h-1r t-primary"
|
|
356
362
|
})) : vue.createCommentVNode("", true)
|
|
357
363
|
]),
|
|
358
|
-
_cache[
|
|
364
|
+
_cache[14] || (_cache[14] = vue.createElementVNode("span", { class: "t-small t-transp" }, "Artist", -1))
|
|
359
365
|
])
|
|
360
366
|
]),
|
|
361
367
|
_: 1
|
|
@@ -375,43 +381,43 @@ const _sfc_main = {
|
|
|
375
381
|
vue.createElementVNode("div", _hoisted_23, [
|
|
376
382
|
vue.createElementVNode("div", _hoisted_24, [
|
|
377
383
|
vue.createElementVNode("div", _hoisted_25, [
|
|
378
|
-
vue.createVNode(IconTime.default, { class: "
|
|
384
|
+
vue.createVNode(IconTime.default, { class: "i-regular t-primary" })
|
|
379
385
|
]),
|
|
380
386
|
vue.createElementVNode("div", null, [
|
|
381
|
-
_cache[
|
|
387
|
+
_cache[15] || (_cache[15] = vue.createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Duration", -1)),
|
|
382
388
|
vue.createElementVNode("div", _hoisted_26, vue.toDisplayString(formatDuration(track.value.duration)), 1)
|
|
383
389
|
])
|
|
384
390
|
]),
|
|
385
391
|
vue.createElementVNode("div", _hoisted_27, [
|
|
386
392
|
vue.createElementVNode("div", _hoisted_28, [
|
|
387
|
-
vue.createVNode(IconCalendar.default, { class: "
|
|
393
|
+
vue.createVNode(IconCalendar.default, { class: "i-regular t-primary" })
|
|
388
394
|
]),
|
|
389
395
|
vue.createElementVNode("div", null, [
|
|
390
|
-
_cache[
|
|
396
|
+
_cache[16] || (_cache[16] = vue.createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Released", -1)),
|
|
391
397
|
vue.createElementVNode("div", _hoisted_29, vue.toDisplayString(formatDate(track.value.releaseDate)), 1)
|
|
392
398
|
])
|
|
393
399
|
]),
|
|
394
400
|
vue.createElementVNode("div", _hoisted_30, [
|
|
395
401
|
vue.createElementVNode("div", _hoisted_31, [
|
|
396
|
-
vue.createVNode(IconCheckmark.default, { class: "
|
|
402
|
+
vue.createVNode(IconCheckmark.default, { class: "i-regular t-success" })
|
|
397
403
|
]),
|
|
398
404
|
vue.createElementVNode("div", null, [
|
|
399
|
-
_cache[
|
|
405
|
+
_cache[17] || (_cache[17] = vue.createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Status", -1)),
|
|
400
406
|
vue.createElementVNode("div", _hoisted_32, vue.toDisplayString(track.value.status), 1)
|
|
401
407
|
])
|
|
402
408
|
]),
|
|
403
409
|
vue.createElementVNode("div", _hoisted_33, [
|
|
404
410
|
vue.createElementVNode("div", _hoisted_34, [
|
|
405
|
-
vue.createVNode(IconShow.default, { class: "
|
|
411
|
+
vue.createVNode(IconShow.default, { class: "i-regular t-primary" })
|
|
406
412
|
]),
|
|
407
413
|
vue.createElementVNode("div", null, [
|
|
408
|
-
_cache[
|
|
414
|
+
_cache[18] || (_cache[18] = vue.createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Visibility", -1)),
|
|
409
415
|
vue.createElementVNode("div", _hoisted_35, vue.toDisplayString(track.value.isPublic ? "Public" : "Private"), 1)
|
|
410
416
|
])
|
|
411
417
|
])
|
|
412
418
|
]),
|
|
413
419
|
track.value.album ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_36, [
|
|
414
|
-
_cache[
|
|
420
|
+
_cache[19] || (_cache[19] = vue.createElementVNode("div", { class: "t-small t-transp t-uppercase mn-b-thin" }, "From Album", -1)),
|
|
415
421
|
vue.createVNode(_component_router_link, {
|
|
416
422
|
to: `/album/${track.value.album.url}`,
|
|
417
423
|
class: "flex items-center gap-medium hover-opacity"
|
|
@@ -429,7 +435,7 @@ const _sfc_main = {
|
|
|
429
435
|
}, 8, ["to"])
|
|
430
436
|
])) : vue.createCommentVNode("", true),
|
|
431
437
|
track.value.genre && track.value.genre.length || track.value.tags && track.value.tags.length ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_38, [
|
|
432
|
-
_cache[
|
|
438
|
+
_cache[20] || (_cache[20] = vue.createElementVNode("h3", { class: "t-medium mn-b-small" }, "Genres & Tags", -1)),
|
|
433
439
|
vue.createElementVNode("div", _hoisted_39, [
|
|
434
440
|
(vue.openBlock(true), vue.createElementBlock(vue.Fragment, null, vue.renderList(track.value.genre, (genre) => {
|
|
435
441
|
return vue.openBlock(), vue.createElementBlock("span", {
|
|
@@ -446,17 +452,17 @@ const _sfc_main = {
|
|
|
446
452
|
])
|
|
447
453
|
])) : vue.createCommentVNode("", true),
|
|
448
454
|
track.value.description ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_40, [
|
|
449
|
-
_cache[
|
|
455
|
+
_cache[21] || (_cache[21] = vue.createElementVNode("h3", { class: "t-medium mn-b-small" }, "About", -1)),
|
|
450
456
|
vue.createElementVNode("p", _hoisted_41, vue.toDisplayString(track.value.description), 1)
|
|
451
457
|
])) : vue.createCommentVNode("", true),
|
|
452
458
|
track.value.lyrics ? (vue.openBlock(), vue.createElementBlock("div", _hoisted_42, [
|
|
453
|
-
_cache[
|
|
459
|
+
_cache[22] || (_cache[22] = vue.createElementVNode("h3", { class: "t-medium mn-b-small" }, "Lyrics", -1)),
|
|
454
460
|
vue.createElementVNode("pre", _hoisted_43, vue.toDisplayString(track.value.lyrics), 1)
|
|
455
461
|
])) : vue.createCommentVNode("", true)
|
|
456
462
|
])
|
|
457
463
|
])) : vue.createCommentVNode("", true),
|
|
458
464
|
track.value && relatedTracks.value && relatedTracks.value.length ? (vue.openBlock(), vue.createElementBlock("section", _hoisted_44, [
|
|
459
|
-
_cache[
|
|
465
|
+
_cache[23] || (_cache[23] = vue.createElementVNode("h2", { class: "h2 mn-b-medium" }, "Related Tracks", -1)),
|
|
460
466
|
vue.createVNode(Feed.default, {
|
|
461
467
|
store: {
|
|
462
468
|
read: () => new _ctx.Promise((resolve) => resolve(relatedTracks.value || [])),
|
|
@@ -492,9 +498,9 @@ const _sfc_main = {
|
|
|
492
498
|
showAddToPlaylistModal.value ? (vue.openBlock(), vue.createBlock(Popup.default, {
|
|
493
499
|
key: 4,
|
|
494
500
|
onClosePopup: _cache[2] || (_cache[2] = ($event) => showAddToPlaylistModal.value = false),
|
|
495
|
-
class: "bg-
|
|
501
|
+
class: "bg-white pd-medium w-m-25r radius-medium"
|
|
496
502
|
}, {
|
|
497
|
-
default: vue.withCtx(() => _cache[
|
|
503
|
+
default: vue.withCtx(() => _cache[24] || (_cache[24] = [
|
|
498
504
|
vue.createElementVNode("h3", { class: "h3 mn-b-medium" }, "Add to Playlist", -1),
|
|
499
505
|
vue.createElementVNode("p", { class: "t-transp" }, "Playlist selector coming soon...", -1)
|
|
500
506
|
])),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Track.vue.cjs","sources":["../../../../../../../src/modules/music/components/pages/Track.vue"],"sourcesContent":["<!-- components/pages/Track.vue -->\n<template>\n <div class=\"track-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 && !track\" class=\"t-center pd-big\">\n <h2 class=\"\">Track not found</h2>\n <p class=\"t-transp t-medium\">The track you're looking for doesn't exist or has been removed.</p>\n </div>\n\n <!-- Track Content -->\n <div v-if=\"track\" class=\"track-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 track-cover-section\">\n <!-- Cover with Play Overlay -->\n <div class=\"cover-container relative mn-b-medium radius-big overflow-hidden shadow-big\">\n <Media \n :url=\"track.coverUrl || (track.album && track.album.coverUrl) || '/logo/logo-placeholder.jpg'\" \n :alt=\"track.title\"\n class=\"aspect-1x1 w-100 radius-medium o-hidden\"\n />\n <!-- <div class=\"cover-overlay absolute inset-0 bg-black-transp-40 flex-center opacity-0 hover-opacity-100 transition\">\n <Button\n @click=\"playTrack\"\n color=\"white\"\n size=\"big\"\n class=\"w-5r h-5r radius-full shadow-big hover-scale-110\"\n >\n <IconPlay class=\"w-2r h-2r\" />\n </Button>\n </div> -->\n </div>\n\n \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\">{{ formatNumber(track.playCount) }}</div>\n <div class=\"t-small t-transp t-uppercase\">Plays</div>\n </div>\n <div class=\"stat-card bg-light pd-medium radius-medium t-center\">\n <div class=\" mn-b-thin\">{{ formatNumber(track.views) }}</div>\n <div class=\"t-small t-transp t-uppercase\">Views</div>\n </div>\n </div>\n </div>\n\n <!-- Right Column - Track Details -->\n <div class=\"track-details-section\">\n <!-- Track 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\">Single</span>\n <span v-if=\"track.isExplicit\" class=\"badge bg-danger-transp-20 t-danger pd-thin-big radius-small t-small\">Explicit</span>\n </div>\n\n <!-- Track Title -->\n <h1 class=\"h1 mn-b-medium\">{{ track.title }}</h1>\n <!-- Action Buttons -->\n <div class=\"flex gap-small mn-b-medium\">\n <Button\n @click=\"playTrack\"\n color=\"primary\"\n size=\"medium\"\n class=\"flex-1 flex-center gap-thin\"\n >\n <IconPlay class=\"w-1r h-1r\" />\n Play\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=\"addToQueue\"\n color=\"transp\"\n size=\"medium\"\n class=\"w-3r h-3r radius-full\"\n >\n <IconAdd 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=\"showAddToPlaylistModal = true\" color=\"transp\" size=\"small\" class=\"w-100 justify-start\">\n Add to Playlist\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=\"editTrack\" color=\"transp\" size=\"small\" class=\"w-100 justify-start\">\n Edit Track\n </Button>\n <Button @click=\"deleteTrack\" color=\"danger\" size=\"small\" class=\"w-100 justify-start\">\n Delete Track\n </Button>\n </template>\n </div>\n </template>\n </Dropdown>\n </div>\n\n <!-- Artist Card -->\n <div class=\"artist-card bg-light pd-medium radius-medium flex items-center gap-medium mn-b-big\">\n <router-link \n :to=\"`/artist/${track.artist.url}`\"\n class=\"flex items-center gap-medium flex-1 hover-opacity\"\n >\n <div class=\"artist-avatar\">\n <Media \n v-if=\"track.artist.photoUrl\"\n :src=\"track.artist.photoUrl\"\n :alt=\"track.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 {{ track.artist.name.charAt(0) }}\n </div>\n </div>\n <div>\n <div class=\"flex items-center gap-thin\">\n <span class=\"t-large \">{{ track.artist.name }}</span>\n <IconVerified v-if=\"track.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\"\n :color=\"isFollowingArtist ? 'primary' : 'transp'\"\n size=\"small\"\n >\n {{ isFollowingArtist ? 'Following' : 'Follow' }}\n </Button>\n </div>\n\n\n\n <!-- Metadata Cards -->\n <div class=\"metadata-grid grid cols-2 gap-small mn-b-big\">\n <!-- 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 \">{{ formatDuration(track.duration) }}</div>\n </div>\n </div>\n\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(track.releaseDate) }}</div>\n </div>\n </div>\n\n <!-- Status -->\n <div class=\"metadata-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <div class=\"icon-wrapper bg-success-transp-20 w-3r h-3r radius-small flex-center\">\n <IconCheck class=\"w-1-5r h-1-5r t-success\" />\n </div>\n <div>\n <div class=\"t-small t-transp t-uppercase\">Status</div>\n <div class=\"t-medium t-success\">{{ track.status }}</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 \">{{ track.isPublic ? 'Public' : 'Private' }}</div>\n </div>\n </div>\n </div>\n\n <!-- Album Info -->\n <div v-if=\"track.album\" class=\"album-card bg-light pd-medium radius-medium mn-b-medium\">\n <div class=\"t-small t-transp t-uppercase mn-b-thin\">From Album</div>\n <router-link \n :to=\"`/album/${track.album.url}`\"\n class=\"flex items-center gap-medium hover-opacity\"\n >\n <Media \n v-if=\"track.album.coverUrl\"\n :src=\"track.album.coverUrl\"\n :alt=\"track.album.title\"\n class=\"w-3r h-3r radius-small object-cover\"\n />\n <span class=\"t-medium \">{{ track.album.title }}</span>\n </router-link>\n </div>\n\n <!-- Genres & Tags -->\n <div v-if=\"(track.genre && track.genre.length) || (track.tags && track.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 track.genre\" \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 track.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=\"track.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\">{{ track.description }}</p>\n </div>\n\n <!-- Lyrics -->\n <div v-if=\"track.lyrics\" class=\"lyrics-section bg-light pd-medium radius-medium\">\n <h3 class=\"t-medium mn-b-small\">Lyrics</h3>\n <pre class=\"t-transp t-small\">{{ track.lyrics }}</pre>\n </div>\n </div>\n </div>\n\n <!-- Related Tracks -->\n <section v-if=\"track && relatedTracks && relatedTracks.length\" class=\"related-section mn-t-big\">\n <h2 class=\"h2 mn-b-medium\">Related Tracks</h2>\n <Feed\n :store=\"{\n read: () => new Promise(resolve => resolve(relatedTracks || [])),\n state: { isLoading: false }\n }\"\n :external=\"true\"\n :items=\"relatedTracks\"\n :states=\"{\n empty: {\n title: 'No related tracks',\n description: 'Check back later for recommendations',\n class: 'pd-medium bg-light radius-medium'\n }\n }\"\n class=\"grid cols-2 cols-m-3 cols-l-4 gap-medium\"\n >\n <template #default=\"{ items }\">\n <div class=\"bg-light radius-medium o-hidden\">\n <TrackListCard\n v-for=\"(relatedTrack, index) in items\"\n :key=\"relatedTrack._id\"\n :track=\"relatedTrack\"\n :index=\"index\"\n :showAlbum=\"true\"\n :showCover=\"true\"\n />\n </div>\n </template>\n </Feed>\n </section>\n\n <!-- Add to Playlist Modal -->\n <Popup \n v-if=\"showAddToPlaylistModal\" \n @close-popup=\"showAddToPlaylistModal = false\" \n class=\"bg-dark pd-medium w-m-25r radius-medium\"\n >\n <h3 class=\"h3 mn-b-medium\">Add to Playlist</h3>\n <!-- <PlaylistSelector \n :trackId=\"track._id\" \n @added=\"showAddToPlaylistModal = false\"\n /> -->\n <p class=\"t-transp\">Playlist selector coming soon...</p>\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 Popup from '@martyrs/src/components/Popup/Popup.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 IconAdd from '@martyrs/src/modules/icons/navigation/IconAdd.vue';\nimport IconClock from '@martyrs/src/modules/icons/entities/IconTime.vue';\nimport IconCalendar from '@martyrs/src/modules/icons/entities/IconCalendar.vue';\nimport IconCheck from '@martyrs/src/modules/icons/navigation/IconCheckmark.vue';\nimport IconEye from '@martyrs/src/modules/icons/actions/IconShow.vue';\nimport IconVerified from '@martyrs/src/modules/icons/navigation/IconCheckmark.vue';\n\n// Components\nimport TrackListCard from '../cards/TrackListCard.vue';\n// import PlaylistSelector from '../forms/PlaylistSelector.vue';\n\n// Store\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';\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 showDropdown = ref(false);\nconst showAddToPlaylistModal = ref(false);\nconst isFavorite = ref(false);\nconst isFollowingArtist = ref(false);\n\n// Clear state\ntracksState.currentTrack = null;\ntracksState.relatedTracks = [];\n\n// Computed\nconst track = computed(() => tracksState.currentTrack);\nconst relatedTracks = computed(() => tracksState.relatedTracks || []);\n\nconst isOwner = computed(() => {\n return track.value?.owner?.target === authState.user?._id;\n});\n\n// Format helpers\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 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 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 playTrack = () => {\n if (track.value) {\n playerActions.setQueue([track.value]);\n }\n};\n\nconst toggleFavorite = () => {\n isFavorite.value = !isFavorite.value;\n // TODO: Implement actual saving\n};\n\nconst toggleFollowArtist = () => {\n isFollowingArtist.value = !isFollowingArtist.value;\n // TODO: Implement actual following\n};\n\nconst addToQueue = () => {\n if (track.value) {\n playerActions.addToQueue(track.value);\n }\n};\n\nconst editTrack = () => {\n router.push({ name: 'track-edit', params: { url: track.value.url } });\n};\n\nconst deleteTrack = async () => {\n if (confirm('Are you sure you want to delete this track?')) {\n try {\n await tracksActions.deleteTrack(track.value._id);\n router.push({ name: 'music-library' });\n } catch (error) {\n console.error('Failed to delete track:', error);\n }\n }\n};\n\nconst copyLink = () => {\n navigator.clipboard.writeText(window.location.href);\n showDropdown.value = false;\n};\n\n// Data fetching\nconst fetchTrackData = async () => {\n try {\n await tracksActions.fetchTrackByUrl(route.params.url);\n await tracksActions.fetchRelatedTracks(route.params.url);\n } catch (error) {\n console.error('Error loading track:', error);\n }\n};\n\n// Lifecycle\nonMounted(async () => {\n emits('page-loading');\n \n await fetchTrackData();\n \n hasLoaded.value = true;\n emits('page-loaded');\n});\n</script>\n\n<style scoped>\n</style>"],"names":["useRoute","useRouter","ref","tracksState","computed","authState","playerActions","tracksActions","onMounted"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Track.vue.cjs","sources":["../../../../../../../src/modules/music/components/pages/Track.vue"],"sourcesContent":["<!-- components/pages/Track.vue -->\n<template>\n <div class=\"track-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 && !track\" class=\"t-center pd-big\">\n <h2 class=\"\">Track not found</h2>\n <p class=\"t-transp t-medium\">The track you're looking for doesn't exist or has been removed.</p>\n </div>\n\n <!-- Track Content -->\n <div v-if=\"track\" class=\"track-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 track-cover-section\">\n <!-- Cover with Play Overlay -->\n <div class=\"cover-container relative mn-b-medium radius-big overflow-hidden shadow-big\">\n <Media \n :url=\"track.coverUrl || (track.album && track.album.coverUrl) || '/logo/logo-placeholder.jpg'\" \n :alt=\"track.title\"\n class=\"aspect-1x1 w-100 radius-medium o-hidden\"\n />\n <!-- <div class=\"cover-overlay absolute inset-0 bg-black-transp-40 flex-center opacity-0 hover-opacity-100 transition\">\n <Button\n @click=\"playTrack\"\n color=\"white\"\n size=\"big\"\n class=\"w-5r h-5r radius-full shadow-big hover-scale-110\"\n >\n <IconPlay class=\"w-2r h-2r\" />\n </Button>\n </div> -->\n </div>\n\n \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\">{{ formatNumber(track.playCount) }}</div>\n <div class=\"t-small t-transp t-uppercase\">Plays</div>\n </div>\n <div class=\"stat-card bg-light pd-medium radius-medium t-center\">\n <div class=\" mn-b-thin\">{{ formatNumber(track.views) }}</div>\n <div class=\"t-small t-transp t-uppercase\">Views</div>\n </div>\n </div>\n </div>\n\n <!-- Right Column - Track Details -->\n <div class=\"track-details-section\">\n <!-- Track 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\">Single</span>\n <span v-if=\"track.isExplicit\" class=\"badge bg-danger-transp-20 t-danger pd-thin-big radius-small t-small\">Explicit</span>\n </div>\n\n <!-- Track Title -->\n <h1 class=\"h1 mn-b-medium\">{{ track.title }}</h1>\n <!-- Action Buttons -->\n <div class=\"flex gap-small mn-b-medium\">\n <Button\n @click=\"playTrack\"\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\n </Button>\n\n <Button\n @click=\"addToQueue\"\n color=\"primary\"\n size=\"medium\"\n class=\"flex-1 bg-light radius-thin flex-center gap-thin\"\n >\n <IconAdd class=\"i-medium\" />\n Add to Queue\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\" />\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-dark pd-small radius-medium shadow-big mn-t-thin\">\n <Button @click=\"showAddToPlaylistModal = true\" color=\"transp\" size=\"small\" class=\"w-100 justify-start\">\n Add to Playlist\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=\"editTrack\" color=\"transp\" size=\"small\" class=\"w-100 justify-start\">\n Edit Track\n </Button>\n <Button @click=\"deleteTrack\" color=\"danger\" size=\"small\" class=\"w-100 justify-start\">\n Delete Track\n </Button>\n </template>\n </div>\n </template>\n </Dropdown>\n </div>\n\n <!-- Artist Card -->\n <div class=\"artist-card bg-light pd-medium radius-medium flex items-center gap-medium mn-b-big\">\n <router-link \n :to=\"{ name: 'artist', params: { url: track.artist.url } }\"\n class=\"flex items-center gap-medium flex-1 hover-opacity\"\n >\n <div class=\"artist-avatar\">\n <Media \n v-if=\"track.artist.photoUrl\"\n :src=\"track.artist.photoUrl\"\n :alt=\"track.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 {{ track.artist.name.charAt(0) }}\n </div>\n </div>\n <div>\n <div class=\"flex items-center gap-thin\">\n <span class=\"t-large \">{{ track.artist.name }}</span>\n <IconVerified v-if=\"track.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\"\n :color=\"isFollowingArtist ? 'primary' : 'transp'\"\n size=\"small\"\n >\n {{ isFollowingArtist ? 'Following' : 'Follow' }}\n </Button>\n </div>\n\n\n\n <!-- Metadata Cards -->\n <div class=\"metadata-grid grid cols-2 gap-small mn-b-big\">\n <!-- 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=\"i-regular t-primary\" />\n </div>\n <div>\n <div class=\"t-small t-transp t-uppercase\">Duration</div>\n <div class=\"t-medium \">{{ formatDuration(track.duration) }}</div>\n </div>\n </div>\n\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=\"i-regular t-primary\" />\n </div>\n <div>\n <div class=\"t-small t-transp t-uppercase\">Released</div>\n <div class=\"t-medium \">{{ formatDate(track.releaseDate) }}</div>\n </div>\n </div>\n\n <!-- Status -->\n <div class=\"metadata-card bg-light pd-medium radius-medium flex items-center gap-medium\">\n <div class=\"icon-wrapper bg-success-transp-20 w-3r h-3r radius-small flex-center\">\n <IconCheck class=\"i-regular t-success\" />\n </div>\n <div>\n <div class=\"t-small t-transp t-uppercase\">Status</div>\n <div class=\"t-medium t-success\">{{ track.status }}</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=\"i-regular t-primary\" />\n </div>\n <div>\n <div class=\"t-small t-transp t-uppercase\">Visibility</div>\n <div class=\"t-medium \">{{ track.isPublic ? 'Public' : 'Private' }}</div>\n </div>\n </div>\n </div>\n\n <!-- Album Info -->\n <div v-if=\"track.album\" class=\"album-card bg-light pd-medium radius-medium mn-b-medium\">\n <div class=\"t-small t-transp t-uppercase mn-b-thin\">From Album</div>\n <router-link \n :to=\"`/album/${track.album.url}`\"\n class=\"flex items-center gap-medium hover-opacity\"\n >\n <Media \n v-if=\"track.album.coverUrl\"\n :src=\"track.album.coverUrl\"\n :alt=\"track.album.title\"\n class=\"w-3r h-3r radius-small object-cover\"\n />\n <span class=\"t-medium \">{{ track.album.title }}</span>\n </router-link>\n </div>\n\n <!-- Genres & Tags -->\n <div v-if=\"(track.genre && track.genre.length) || (track.tags && track.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 track.genre\" \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 track.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=\"track.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\">{{ track.description }}</p>\n </div>\n\n <!-- Lyrics -->\n <div v-if=\"track.lyrics\" class=\"lyrics-section bg-light pd-medium radius-medium\">\n <h3 class=\"t-medium mn-b-small\">Lyrics</h3>\n <pre class=\"t-transp t-small\">{{ track.lyrics }}</pre>\n </div>\n </div>\n </div>\n\n <!-- Related Tracks -->\n <section v-if=\"track && relatedTracks && relatedTracks.length\" class=\"related-section mn-t-big\">\n <h2 class=\"h2 mn-b-medium\">Related Tracks</h2>\n <Feed\n :store=\"{\n read: () => new Promise(resolve => resolve(relatedTracks || [])),\n state: { isLoading: false }\n }\"\n :external=\"true\"\n :items=\"relatedTracks\"\n :states=\"{\n empty: {\n title: 'No related tracks',\n description: 'Check back later for recommendations',\n class: 'pd-medium bg-light radius-medium'\n }\n }\"\n class=\"grid cols-2 cols-m-3 cols-l-4 gap-medium\"\n >\n <template #default=\"{ items }\">\n <div class=\"bg-light radius-medium o-hidden\">\n <TrackListCard\n v-for=\"(relatedTrack, index) in items\"\n :key=\"relatedTrack._id\"\n :track=\"relatedTrack\"\n :index=\"index\"\n :showAlbum=\"true\"\n :showCover=\"true\"\n />\n </div>\n </template>\n </Feed>\n </section>\n\n <!-- Add to Playlist Modal -->\n <Popup \n v-if=\"showAddToPlaylistModal\" \n @close-popup=\"showAddToPlaylistModal = false\" \n class=\"bg-white pd-medium w-m-25r radius-medium\"\n >\n <h3 class=\"h3 mn-b-medium\">Add to Playlist</h3>\n <!-- <PlaylistSelector \n :trackId=\"track._id\" \n @added=\"showAddToPlaylistModal = false\"\n /> -->\n <p class=\"t-transp\">Playlist selector coming soon...</p>\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 Popup from '@martyrs/src/components/Popup/Popup.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 IconAdd from '@martyrs/src/modules/icons/navigation/IconAdd.vue';\nimport IconClock from '@martyrs/src/modules/icons/entities/IconTime.vue';\nimport IconCalendar from '@martyrs/src/modules/icons/entities/IconCalendar.vue';\nimport IconCheck from '@martyrs/src/modules/icons/navigation/IconCheckmark.vue';\nimport IconEye from '@martyrs/src/modules/icons/actions/IconShow.vue';\nimport IconVerified from '@martyrs/src/modules/icons/navigation/IconCheckmark.vue';\n\n// Components\nimport TrackListCard from '../cards/TrackListCard.vue';\n// import PlaylistSelector from '../forms/PlaylistSelector.vue';\n\n// Store\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';\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 showDropdown = ref(false);\nconst showAddToPlaylistModal = ref(false);\nconst isFavorite = ref(false);\nconst isFollowingArtist = ref(false);\n\n// Clear state\ntracksState.currentTrack = null;\ntracksState.relatedTracks = [];\n\n// Computed\nconst track = computed(() => tracksState.currentTrack);\nconst relatedTracks = computed(() => tracksState.relatedTracks || []);\n\nconst isOwner = computed(() => {\n return track.value?.owner?.target === authState.user?._id;\n});\n\n// Format helpers\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 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 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 playTrack = () => {\n if (track.value) {\n playerActions.setQueue([track.value]);\n }\n};\n\nconst toggleFavorite = () => {\n isFavorite.value = !isFavorite.value;\n // TODO: Implement actual saving\n};\n\nconst toggleFollowArtist = () => {\n isFollowingArtist.value = !isFollowingArtist.value;\n // TODO: Implement actual following\n};\n\nconst addToQueue = () => {\n if (track.value) {\n playerActions.addToQueue(track.value);\n }\n};\n\nconst editTrack = () => {\n router.push({ name: 'track-edit', params: { url: track.value.url } });\n};\n\nconst deleteTrack = async () => {\n if (confirm('Are you sure you want to delete this track?')) {\n try {\n await tracksActions.deleteTrack(track.value._id);\n router.push({ name: 'music-library' });\n } catch (error) {\n console.error('Failed to delete track:', error);\n }\n }\n};\n\nconst copyLink = () => {\n navigator.clipboard.writeText(window.location.href);\n showDropdown.value = false;\n};\n\n// Data fetching\nconst fetchTrackData = async () => {\n try {\n await tracksActions.fetchTrackByUrl(route.params.url);\n await tracksActions.fetchRelatedTracks(route.params.url);\n } catch (error) {\n console.error('Error loading track:', error);\n }\n};\n\n// Lifecycle\nonMounted(async () => {\n emits('page-loading');\n \n await fetchTrackData();\n \n hasLoaded.value = true;\n emits('page-loaded');\n});\n</script>\n\n<style scoped>\n</style>"],"names":["useRoute","useRouter","ref","tracksState","computed","authState","playerActions","tracksActions","onMounted"],"mappings":"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"}
|
|
@@ -7,9 +7,9 @@ import _sfc_main$5 from "../../../../components/Dropdown/Dropdown.vue.js";
|
|
|
7
7
|
import _sfc_main$c from "../../../../components/Popup/Popup.vue.js";
|
|
8
8
|
import _sfc_main$a from "../../../../components/Feed/Feed.vue.js";
|
|
9
9
|
import _sfc_main$2 from "../../../icons/navigation/IconPlay.vue.js";
|
|
10
|
-
import _sfc_main$
|
|
10
|
+
import _sfc_main$4 from "../../../icons/navigation/IconLike.vue.js";
|
|
11
11
|
import _sfc_main$6 from "../../../icons/navigation/IconEllipsis.vue.js";
|
|
12
|
-
import _sfc_main$
|
|
12
|
+
import _sfc_main$3 from "../../../icons/navigation/IconAdd.vue.js";
|
|
13
13
|
import IconClock from "../../../icons/entities/IconTime.vue.js";
|
|
14
14
|
import _sfc_main$8 from "../../../icons/entities/IconCalendar.vue.js";
|
|
15
15
|
import _sfc_main$7 from "../../../icons/navigation/IconCheckmark.vue.js";
|
|
@@ -227,40 +227,46 @@ const _sfc_main = {
|
|
|
227
227
|
onClick: playTrack,
|
|
228
228
|
color: "primary",
|
|
229
229
|
size: "medium",
|
|
230
|
-
class: "flex-1 flex-center gap-thin"
|
|
230
|
+
class: "flex-1 t-white bg-black radius-thin flex-center gap-thin"
|
|
231
231
|
}, {
|
|
232
232
|
default: withCtx(() => [
|
|
233
|
-
createVNode(_sfc_main$2, {
|
|
233
|
+
createVNode(_sfc_main$2, {
|
|
234
|
+
fill: "rgb(var(--white))",
|
|
235
|
+
class: "i-medium"
|
|
236
|
+
}),
|
|
234
237
|
_cache[7] || (_cache[7] = createTextVNode(" Play "))
|
|
235
238
|
]),
|
|
236
239
|
_: 1
|
|
237
240
|
}),
|
|
238
241
|
createVNode(_sfc_main$1, {
|
|
239
|
-
onClick:
|
|
240
|
-
color:
|
|
242
|
+
onClick: addToQueue,
|
|
243
|
+
color: "primary",
|
|
241
244
|
size: "medium",
|
|
242
|
-
class: "
|
|
245
|
+
class: "flex-1 bg-light radius-thin flex-center gap-thin"
|
|
243
246
|
}, {
|
|
244
247
|
default: withCtx(() => [
|
|
245
|
-
createVNode(_sfc_main$3, {
|
|
246
|
-
|
|
247
|
-
fill: isFavorite.value
|
|
248
|
-
}, null, 8, ["fill"])
|
|
248
|
+
createVNode(_sfc_main$3, { class: "i-medium" }),
|
|
249
|
+
_cache[8] || (_cache[8] = createTextVNode(" Add to Queue "))
|
|
249
250
|
]),
|
|
250
251
|
_: 1
|
|
251
|
-
}
|
|
252
|
+
}),
|
|
252
253
|
createVNode(_sfc_main$1, {
|
|
253
|
-
onClick:
|
|
254
|
-
color: "
|
|
254
|
+
onClick: toggleFavorite,
|
|
255
|
+
color: "primary",
|
|
255
256
|
size: "medium",
|
|
256
|
-
class: "
|
|
257
|
+
class: "flex-1 bg-light radius-thin flex-center gap-thin"
|
|
257
258
|
}, {
|
|
258
259
|
default: withCtx(() => [
|
|
259
|
-
createVNode(_sfc_main$4, {
|
|
260
|
+
createVNode(_sfc_main$4, {
|
|
261
|
+
class: "i-medium",
|
|
262
|
+
fill: isFavorite.value
|
|
263
|
+
}, null, 8, ["fill"]),
|
|
264
|
+
createTextVNode(" " + toDisplayString(isFavorite.value ? "Liked" : "Like"), 1)
|
|
260
265
|
]),
|
|
261
266
|
_: 1
|
|
262
267
|
}),
|
|
263
268
|
createVNode(_sfc_main$5, {
|
|
269
|
+
label: { component: _sfc_main$6, class: "bg-light radius-thin pd-thin i-big" },
|
|
264
270
|
modelValue: showDropdown.value,
|
|
265
271
|
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => showDropdown.value = $event),
|
|
266
272
|
class: "relative"
|
|
@@ -285,7 +291,7 @@ const _sfc_main = {
|
|
|
285
291
|
size: "small",
|
|
286
292
|
class: "w-100 justify-start"
|
|
287
293
|
}, {
|
|
288
|
-
default: withCtx(() => _cache[
|
|
294
|
+
default: withCtx(() => _cache[9] || (_cache[9] = [
|
|
289
295
|
createTextVNode(" Add to Playlist ")
|
|
290
296
|
])),
|
|
291
297
|
_: 1
|
|
@@ -296,20 +302,20 @@ const _sfc_main = {
|
|
|
296
302
|
size: "small",
|
|
297
303
|
class: "w-100 justify-start"
|
|
298
304
|
}, {
|
|
299
|
-
default: withCtx(() => _cache[
|
|
305
|
+
default: withCtx(() => _cache[10] || (_cache[10] = [
|
|
300
306
|
createTextVNode(" Copy Link ")
|
|
301
307
|
])),
|
|
302
308
|
_: 1
|
|
303
309
|
}),
|
|
304
310
|
isOwner.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
|
|
305
|
-
_cache[
|
|
311
|
+
_cache[13] || (_cache[13] = createElementVNode("hr", { class: "mn-v-thin border-dark-transp-10" }, null, -1)),
|
|
306
312
|
createVNode(_sfc_main$1, {
|
|
307
313
|
onClick: editTrack,
|
|
308
314
|
color: "transp",
|
|
309
315
|
size: "small",
|
|
310
316
|
class: "w-100 justify-start"
|
|
311
317
|
}, {
|
|
312
|
-
default: withCtx(() => _cache[
|
|
318
|
+
default: withCtx(() => _cache[11] || (_cache[11] = [
|
|
313
319
|
createTextVNode(" Edit Track ")
|
|
314
320
|
])),
|
|
315
321
|
_: 1
|
|
@@ -320,7 +326,7 @@ const _sfc_main = {
|
|
|
320
326
|
size: "small",
|
|
321
327
|
class: "w-100 justify-start"
|
|
322
328
|
}, {
|
|
323
|
-
default: withCtx(() => _cache[
|
|
329
|
+
default: withCtx(() => _cache[12] || (_cache[12] = [
|
|
324
330
|
createTextVNode(" Delete Track ")
|
|
325
331
|
])),
|
|
326
332
|
_: 1
|
|
@@ -329,11 +335,11 @@ const _sfc_main = {
|
|
|
329
335
|
])
|
|
330
336
|
]),
|
|
331
337
|
_: 1
|
|
332
|
-
}, 8, ["modelValue"])
|
|
338
|
+
}, 8, ["label", "modelValue"])
|
|
333
339
|
]),
|
|
334
340
|
createElementVNode("div", _hoisted_18, [
|
|
335
341
|
createVNode(_component_router_link, {
|
|
336
|
-
to:
|
|
342
|
+
to: { name: "artist", params: { url: track.value.artist.url } },
|
|
337
343
|
class: "flex items-center gap-medium flex-1 hover-opacity"
|
|
338
344
|
}, {
|
|
339
345
|
default: withCtx(() => [
|
|
@@ -353,7 +359,7 @@ const _sfc_main = {
|
|
|
353
359
|
class: "w-1r h-1r t-primary"
|
|
354
360
|
})) : createCommentVNode("", true)
|
|
355
361
|
]),
|
|
356
|
-
_cache[
|
|
362
|
+
_cache[14] || (_cache[14] = createElementVNode("span", { class: "t-small t-transp" }, "Artist", -1))
|
|
357
363
|
])
|
|
358
364
|
]),
|
|
359
365
|
_: 1
|
|
@@ -373,43 +379,43 @@ const _sfc_main = {
|
|
|
373
379
|
createElementVNode("div", _hoisted_23, [
|
|
374
380
|
createElementVNode("div", _hoisted_24, [
|
|
375
381
|
createElementVNode("div", _hoisted_25, [
|
|
376
|
-
createVNode(IconClock, { class: "
|
|
382
|
+
createVNode(IconClock, { class: "i-regular t-primary" })
|
|
377
383
|
]),
|
|
378
384
|
createElementVNode("div", null, [
|
|
379
|
-
_cache[
|
|
385
|
+
_cache[15] || (_cache[15] = createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Duration", -1)),
|
|
380
386
|
createElementVNode("div", _hoisted_26, toDisplayString(formatDuration(track.value.duration)), 1)
|
|
381
387
|
])
|
|
382
388
|
]),
|
|
383
389
|
createElementVNode("div", _hoisted_27, [
|
|
384
390
|
createElementVNode("div", _hoisted_28, [
|
|
385
|
-
createVNode(_sfc_main$8, { class: "
|
|
391
|
+
createVNode(_sfc_main$8, { class: "i-regular t-primary" })
|
|
386
392
|
]),
|
|
387
393
|
createElementVNode("div", null, [
|
|
388
|
-
_cache[
|
|
394
|
+
_cache[16] || (_cache[16] = createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Released", -1)),
|
|
389
395
|
createElementVNode("div", _hoisted_29, toDisplayString(formatDate(track.value.releaseDate)), 1)
|
|
390
396
|
])
|
|
391
397
|
]),
|
|
392
398
|
createElementVNode("div", _hoisted_30, [
|
|
393
399
|
createElementVNode("div", _hoisted_31, [
|
|
394
|
-
createVNode(_sfc_main$7, { class: "
|
|
400
|
+
createVNode(_sfc_main$7, { class: "i-regular t-success" })
|
|
395
401
|
]),
|
|
396
402
|
createElementVNode("div", null, [
|
|
397
|
-
_cache[
|
|
403
|
+
_cache[17] || (_cache[17] = createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Status", -1)),
|
|
398
404
|
createElementVNode("div", _hoisted_32, toDisplayString(track.value.status), 1)
|
|
399
405
|
])
|
|
400
406
|
]),
|
|
401
407
|
createElementVNode("div", _hoisted_33, [
|
|
402
408
|
createElementVNode("div", _hoisted_34, [
|
|
403
|
-
createVNode(_sfc_main$9, { class: "
|
|
409
|
+
createVNode(_sfc_main$9, { class: "i-regular t-primary" })
|
|
404
410
|
]),
|
|
405
411
|
createElementVNode("div", null, [
|
|
406
|
-
_cache[
|
|
412
|
+
_cache[18] || (_cache[18] = createElementVNode("div", { class: "t-small t-transp t-uppercase" }, "Visibility", -1)),
|
|
407
413
|
createElementVNode("div", _hoisted_35, toDisplayString(track.value.isPublic ? "Public" : "Private"), 1)
|
|
408
414
|
])
|
|
409
415
|
])
|
|
410
416
|
]),
|
|
411
417
|
track.value.album ? (openBlock(), createElementBlock("div", _hoisted_36, [
|
|
412
|
-
_cache[
|
|
418
|
+
_cache[19] || (_cache[19] = createElementVNode("div", { class: "t-small t-transp t-uppercase mn-b-thin" }, "From Album", -1)),
|
|
413
419
|
createVNode(_component_router_link, {
|
|
414
420
|
to: `/album/${track.value.album.url}`,
|
|
415
421
|
class: "flex items-center gap-medium hover-opacity"
|
|
@@ -427,7 +433,7 @@ const _sfc_main = {
|
|
|
427
433
|
}, 8, ["to"])
|
|
428
434
|
])) : createCommentVNode("", true),
|
|
429
435
|
track.value.genre && track.value.genre.length || track.value.tags && track.value.tags.length ? (openBlock(), createElementBlock("div", _hoisted_38, [
|
|
430
|
-
_cache[
|
|
436
|
+
_cache[20] || (_cache[20] = createElementVNode("h3", { class: "t-medium mn-b-small" }, "Genres & Tags", -1)),
|
|
431
437
|
createElementVNode("div", _hoisted_39, [
|
|
432
438
|
(openBlock(true), createElementBlock(Fragment, null, renderList(track.value.genre, (genre) => {
|
|
433
439
|
return openBlock(), createElementBlock("span", {
|
|
@@ -444,17 +450,17 @@ const _sfc_main = {
|
|
|
444
450
|
])
|
|
445
451
|
])) : createCommentVNode("", true),
|
|
446
452
|
track.value.description ? (openBlock(), createElementBlock("div", _hoisted_40, [
|
|
447
|
-
_cache[
|
|
453
|
+
_cache[21] || (_cache[21] = createElementVNode("h3", { class: "t-medium mn-b-small" }, "About", -1)),
|
|
448
454
|
createElementVNode("p", _hoisted_41, toDisplayString(track.value.description), 1)
|
|
449
455
|
])) : createCommentVNode("", true),
|
|
450
456
|
track.value.lyrics ? (openBlock(), createElementBlock("div", _hoisted_42, [
|
|
451
|
-
_cache[
|
|
457
|
+
_cache[22] || (_cache[22] = createElementVNode("h3", { class: "t-medium mn-b-small" }, "Lyrics", -1)),
|
|
452
458
|
createElementVNode("pre", _hoisted_43, toDisplayString(track.value.lyrics), 1)
|
|
453
459
|
])) : createCommentVNode("", true)
|
|
454
460
|
])
|
|
455
461
|
])) : createCommentVNode("", true),
|
|
456
462
|
track.value && relatedTracks.value && relatedTracks.value.length ? (openBlock(), createElementBlock("section", _hoisted_44, [
|
|
457
|
-
_cache[
|
|
463
|
+
_cache[23] || (_cache[23] = createElementVNode("h2", { class: "h2 mn-b-medium" }, "Related Tracks", -1)),
|
|
458
464
|
createVNode(_sfc_main$a, {
|
|
459
465
|
store: {
|
|
460
466
|
read: () => new _ctx.Promise((resolve) => resolve(relatedTracks.value || [])),
|
|
@@ -490,9 +496,9 @@ const _sfc_main = {
|
|
|
490
496
|
showAddToPlaylistModal.value ? (openBlock(), createBlock(_sfc_main$c, {
|
|
491
497
|
key: 4,
|
|
492
498
|
onClosePopup: _cache[2] || (_cache[2] = ($event) => showAddToPlaylistModal.value = false),
|
|
493
|
-
class: "bg-
|
|
499
|
+
class: "bg-white pd-medium w-m-25r radius-medium"
|
|
494
500
|
}, {
|
|
495
|
-
default: withCtx(() => _cache[
|
|
501
|
+
default: withCtx(() => _cache[24] || (_cache[24] = [
|
|
496
502
|
createElementVNode("h3", { class: "h3 mn-b-medium" }, "Add to Playlist", -1),
|
|
497
503
|
createElementVNode("p", { class: "t-transp" }, "Playlist selector coming soon...", -1)
|
|
498
504
|
])),
|