@ozdao/martyrs 0.2.565 → 0.2.567
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/{main-B9o1iBAZ.js → main-BFvlam0J.js} +9 -6
- package/dist/martyrs/dist/main-BFvlam0J.js +943 -0
- package/dist/martyrs/dist/main-BFvlam0J.js.map +1 -0
- package/dist/martyrs/dist/web-CH5wzMHy.js +55 -0
- package/dist/martyrs/dist/web-CH5wzMHy.js.map +1 -0
- package/dist/martyrs/src/components/BottomSheet/BottomSheet.vue.js +96 -0
- package/dist/martyrs/src/components/BottomSheet/BottomSheet.vue.js.map +1 -0
- package/dist/martyrs/src/components/Feed/Carousel.vue.js +2 -2
- package/dist/martyrs/src/components/Feed/Carousel.vue.js.map +1 -1
- package/dist/martyrs/src/components/Feed/Feed.vue.js +6 -3
- package/dist/martyrs/src/components/Feed/Feed.vue.js.map +1 -1
- package/dist/martyrs/src/components/Menu/{Menu.vue2.js → Menu.vue.js} +2 -2
- package/dist/martyrs/src/components/Menu/Menu.vue.js.map +1 -0
- package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js +1 -1
- package/dist/martyrs/src/modules/community/components/sections/HotPosts.vue.js.map +1 -1
- package/dist/martyrs/src/modules/core/views/components/layouts/App.vue.js +1 -1
- package/dist/martyrs/src/modules/core/views/components/layouts/Client.vue.js +1 -0
- package/dist/martyrs/src/modules/core/views/components/layouts/Client.vue.js.map +1 -1
- package/dist/martyrs/src/modules/core/views/components/sections/Walkthrough.vue.js +1 -1
- package/dist/martyrs/src/modules/events/components/elements/ButtonCheck.vue.js +1 -1
- package/dist/martyrs/src/modules/events/components/sections/EventsHot.vue.js +17 -1
- package/dist/martyrs/src/modules/events/components/sections/EventsHot.vue.js.map +1 -1
- package/dist/martyrs/src/modules/events/events.client.js +15 -12
- package/dist/martyrs/src/modules/events/events.client.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/blocks/ActionButtons.vue.js +95 -0
- package/dist/martyrs/src/modules/music/components/blocks/ActionButtons.vue.js.map +1 -0
- package/dist/martyrs/src/modules/music/components/cards/AlbumCard.vue.js +5 -2
- package/dist/martyrs/src/modules/music/components/cards/AlbumCard.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/cards/ArtistCardSmall.vue.js +24 -24
- package/dist/martyrs/src/modules/music/components/cards/ArtistCardSmall.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.js +3 -3
- package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/layouts/MusicBottomPlayer.vue.js +31 -6
- package/dist/martyrs/src/modules/music/components/layouts/MusicBottomPlayer.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/Album.vue.js +120 -205
- package/dist/martyrs/src/modules/music/components/pages/Album.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/MusicHome.vue.js +9 -13
- package/dist/martyrs/src/modules/music/components/pages/MusicHome.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.js +166 -245
- package/dist/martyrs/src/modules/music/components/pages/Playlist.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/Track.vue.js +135 -220
- package/dist/martyrs/src/modules/music/components/pages/Track.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/player/FullscreenPlayer.vue.js +171 -0
- package/dist/martyrs/src/modules/music/components/player/FullscreenPlayer.vue.js.map +1 -0
- package/dist/martyrs/src/modules/music/components/player/MusicPlayer.vue.js +31 -153
- package/dist/martyrs/src/modules/music/components/player/MusicPlayer.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/player/PlayerControls.vue.js +96 -0
- package/dist/martyrs/src/modules/music/components/player/PlayerControls.vue.js.map +1 -0
- package/dist/martyrs/src/modules/music/components/player/VolumeControl.vue.js +55 -27
- package/dist/martyrs/src/modules/music/components/player/VolumeControl.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/player/tonar.png.js +5 -0
- package/dist/martyrs/src/modules/music/components/player/tonar.png.js.map +1 -0
- package/dist/martyrs/src/modules/music/store/albums.js +8 -2
- package/dist/martyrs/src/modules/music/store/albums.js.map +1 -1
- package/dist/martyrs/src/modules/music/store/player.js +83 -65
- package/dist/martyrs/src/modules/music/store/player.js.map +1 -1
- package/dist/martyrs/src/modules/music/store/tracks.js +4 -13
- package/dist/martyrs/src/modules/music/store/tracks.js.map +1 -1
- package/dist/martyrs/src/modules/notifications/notifications.client.js +2 -2
- package/dist/martyrs/src/modules/organizations/components/pages/Organization.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationBackoffice.vue.js +1 -1
- package/dist/martyrs.css +1 -1
- package/dist/martyrs.es.js +1 -1
- package/dist/music.server.js +33 -6
- package/dist/node_modules/.pnpm/{@capacitor-mlkit_barcode-scanning@7.1.0_@capacitor_core@7.0.1 → @capacitor-mlkit_barcode-scanning@7.3.0_@capacitor_core@7.4.4}/node_modules/@capacitor-mlkit/barcode-scanning/dist/esm/definitions.js +1 -0
- package/dist/node_modules/.pnpm/@capacitor-mlkit_barcode-scanning@7.3.0_@capacitor_core@7.4.4/node_modules/@capacitor-mlkit/barcode-scanning/dist/esm/definitions.js.map +1 -0
- package/dist/node_modules/.pnpm/{@capacitor-mlkit_barcode-scanning@7.1.0_@capacitor_core@7.0.1 → @capacitor-mlkit_barcode-scanning@7.3.0_@capacitor_core@7.4.4}/node_modules/@capacitor-mlkit/barcode-scanning/dist/esm/index.js +1 -1
- package/dist/node_modules/.pnpm/{@capacitor-mlkit_barcode-scanning@7.1.0_@capacitor_core@7.0.1 → @capacitor-mlkit_barcode-scanning@7.3.0_@capacitor_core@7.4.4}/node_modules/@capacitor-mlkit/barcode-scanning/dist/esm/index.js.map +1 -1
- package/dist/node_modules/.pnpm/{@capacitor-mlkit_barcode-scanning@7.1.0_@capacitor_core@7.0.1 → @capacitor-mlkit_barcode-scanning@7.3.0_@capacitor_core@7.4.4}/node_modules/@capacitor-mlkit/barcode-scanning/dist/esm/web.js +16 -1
- package/dist/node_modules/.pnpm/@capacitor-mlkit_barcode-scanning@7.3.0_@capacitor_core@7.4.4/node_modules/@capacitor-mlkit/barcode-scanning/dist/esm/web.js.map +1 -0
- package/dist/node_modules/.pnpm/{@capacitor_core@7.0.1 → @capacitor_core@7.4.4}/node_modules/@capacitor/core/dist/index.js +2 -1
- package/dist/node_modules/.pnpm/@capacitor_core@7.4.4/node_modules/@capacitor/core/dist/index.js.map +1 -0
- package/dist/node_modules/.pnpm/{@capacitor_device@7.0.0_@capacitor_core@7.0.1 → @capacitor_device@7.0.1_@capacitor_core@7.4.4}/node_modules/@capacitor/device/dist/esm/index.js +1 -1
- package/dist/node_modules/.pnpm/{@capacitor_device@7.0.0_@capacitor_core@7.0.1 → @capacitor_device@7.0.1_@capacitor_core@7.4.4}/node_modules/@capacitor/device/dist/esm/index.js.map +1 -1
- package/dist/node_modules/.pnpm/{@capacitor_device@7.0.0_@capacitor_core@7.0.1 → @capacitor_device@7.0.1_@capacitor_core@7.4.4}/node_modules/@capacitor/device/dist/esm/web.js +1 -1
- package/dist/node_modules/.pnpm/{@capacitor_device@7.0.0_@capacitor_core@7.0.1 → @capacitor_device@7.0.1_@capacitor_core@7.4.4}/node_modules/@capacitor/device/dist/esm/web.js.map +1 -1
- package/dist/node_modules/.pnpm/{@capacitor_keyboard@7.0.0_@capacitor_core@7.0.1 → @capacitor_keyboard@7.0.1_@capacitor_core@7.4.4}/node_modules/@capacitor/keyboard/dist/esm/definitions.js.map +1 -1
- package/dist/node_modules/.pnpm/{@capacitor_keyboard@7.0.0_@capacitor_core@7.0.1 → @capacitor_keyboard@7.0.1_@capacitor_core@7.4.4}/node_modules/@capacitor/keyboard/dist/esm/index.js +1 -1
- package/dist/node_modules/.pnpm/{@capacitor_keyboard@7.0.0_@capacitor_core@7.0.1 → @capacitor_keyboard@7.0.1_@capacitor_core@7.4.4}/node_modules/@capacitor/keyboard/dist/esm/index.js.map +1 -1
- package/dist/node_modules/.pnpm/{@capacitor_push-notifications@7.0.0_@capacitor_core@7.0.1 → @capacitor_push-notifications@7.0.3_@capacitor_core@7.4.4}/node_modules/@capacitor/push-notifications/dist/esm/index.js +1 -1
- package/dist/node_modules/.pnpm/{@capacitor_push-notifications@7.0.0_@capacitor_core@7.0.1 → @capacitor_push-notifications@7.0.3_@capacitor_core@7.4.4}/node_modules/@capacitor/push-notifications/dist/esm/index.js.map +1 -1
- package/dist/node_modules/.pnpm/{capacitor-plugin-app-tracking-transparency@2.0.5_@capacitor_core@7.0.1 → capacitor-plugin-app-tracking-transparency@2.0.5_@capacitor_core@7.4.4}/node_modules/capacitor-plugin-app-tracking-transparency/dist/esm/index.js +1 -1
- package/dist/node_modules/.pnpm/{capacitor-plugin-app-tracking-transparency@2.0.5_@capacitor_core@7.0.1 → capacitor-plugin-app-tracking-transparency@2.0.5_@capacitor_core@7.4.4}/node_modules/capacitor-plugin-app-tracking-transparency/dist/esm/index.js.map +1 -1
- package/dist/node_modules/.pnpm/{capacitor-plugin-app-tracking-transparency@2.0.5_@capacitor_core@7.0.1 → capacitor-plugin-app-tracking-transparency@2.0.5_@capacitor_core@7.4.4}/node_modules/capacitor-plugin-app-tracking-transparency/dist/esm/web.js +1 -1
- package/dist/node_modules/.pnpm/{capacitor-plugin-app-tracking-transparency@2.0.5_@capacitor_core@7.0.1 → capacitor-plugin-app-tracking-transparency@2.0.5_@capacitor_core@7.4.4}/node_modules/capacitor-plugin-app-tracking-transparency/dist/esm/web.js.map +1 -1
- package/dist/style.css +221 -145
- package/dist/{web-BF3ijvEr.js → web-CH5wzMHy.js} +1 -1
- package/package.json +1 -1
- package/src/components/BottomSheet/BottomSheet.vue +4 -4
- package/src/components/Feed/Carousel.vue +1 -1
- package/src/components/Feed/Feed.vue +3 -3
- package/src/modules/LAYOUT.MD +767 -0
- package/src/modules/community/components/sections/HotPosts.vue +8 -4
- package/src/modules/core/views/components/layouts/Client.vue +1 -1
- package/src/modules/events/components/sections/EventsHot.vue +21 -4
- package/src/modules/events/events.client.js +3 -0
- package/src/modules/music/components/blocks/ActionButtons.vue +74 -0
- package/src/modules/music/components/cards/AlbumCard.vue +1 -1
- package/src/modules/music/components/cards/ArtistCardSmall.vue +8 -6
- package/src/modules/music/components/cards/TrackListCard.vue +6 -6
- package/src/modules/music/components/layouts/MusicBottomPlayer.vue +94 -4
- package/src/modules/music/components/pages/Album.vue +55 -67
- package/src/modules/music/components/pages/MusicHome.vue +4 -6
- package/src/modules/music/components/pages/Playlist.vue +61 -70
- package/src/modules/music/components/pages/Track.vue +54 -71
- package/src/modules/music/components/player/FullscreenPlayer.vue +248 -0
- package/src/modules/music/components/player/MusicPlayer.vue +21 -216
- package/src/modules/music/components/player/PlayerControls.vue +112 -0
- package/src/modules/music/components/player/Visualizer.vue +151 -0
- package/src/modules/music/components/player/VolumeControl.vue +75 -23
- package/src/modules/music/components/player/tonar.png +0 -0
- package/src/modules/music/routes/albums.routes.js +13 -12
- package/src/modules/music/routes/tracks.routes.js +39 -0
- package/src/modules/music/store/albums.js +10 -2
- package/src/modules/music/store/player.js +101 -89
- package/src/modules/music/store/tracks.js +5 -21
- package/src/styles/config.scss +6 -6
- package/dist/martyrs/src/components/Menu/Menu.vue2.js.map +0 -1
- package/dist/node_modules/.pnpm/@capacitor-mlkit_barcode-scanning@7.1.0_@capacitor_core@7.0.1/node_modules/@capacitor-mlkit/barcode-scanning/dist/esm/definitions.js.map +0 -1
- package/dist/node_modules/.pnpm/@capacitor-mlkit_barcode-scanning@7.1.0_@capacitor_core@7.0.1/node_modules/@capacitor-mlkit/barcode-scanning/dist/esm/web.js.map +0 -1
- package/dist/node_modules/.pnpm/@capacitor_core@7.0.1/node_modules/@capacitor/core/dist/index.js.map +0 -1
- /package/dist/node_modules/.pnpm/{@capacitor_keyboard@7.0.0_@capacitor_core@7.0.1 → @capacitor_keyboard@7.0.1_@capacitor_core@7.4.4}/node_modules/@capacitor/keyboard/dist/esm/definitions.js +0 -0
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
</div>
|
|
8
8
|
|
|
9
9
|
<!-- Playlist Content -->
|
|
10
|
-
<div v-if="playlist" class="playlist-content cols-2
|
|
10
|
+
<div v-if="playlist" class="playlist-content cols-2 mobile:cols-1 gap-big">
|
|
11
11
|
<!-- Left Column - Cover & Stats -->
|
|
12
|
-
<div class="pos-sticky
|
|
12
|
+
<div class="pos-sticky pos-t-0 mobile:pos-relative playlist-cover-section">
|
|
13
13
|
<!-- Cover -->
|
|
14
14
|
<div class="cover-container relative mn-b-medium radius-big overflow-hidden shadow-big">
|
|
15
15
|
<Media
|
|
@@ -51,67 +51,7 @@
|
|
|
51
51
|
<h1 class="h1 mn-b-medium">{{ playlist.title }}</h1>
|
|
52
52
|
|
|
53
53
|
<!-- Action Buttons -->
|
|
54
|
-
<
|
|
55
|
-
<Button
|
|
56
|
-
@click="playPlaylist"
|
|
57
|
-
color="primary"
|
|
58
|
-
size="medium"
|
|
59
|
-
class="flex-1 t-white bg-black radius-thin flex-center gap-thin"
|
|
60
|
-
>
|
|
61
|
-
<IconPlay fill="rgb(var(--white))" class="i-medium" />
|
|
62
|
-
Play All
|
|
63
|
-
</Button>
|
|
64
|
-
|
|
65
|
-
<Button
|
|
66
|
-
@click="shufflePlay"
|
|
67
|
-
color="primary"
|
|
68
|
-
size="medium"
|
|
69
|
-
class="flex-1 bg-light radius-thin flex-center gap-thin"
|
|
70
|
-
>
|
|
71
|
-
<IconShuffle class="i-medium" />
|
|
72
|
-
Shuffle
|
|
73
|
-
</Button>
|
|
74
|
-
|
|
75
|
-
<Button
|
|
76
|
-
@click="toggleFollow"
|
|
77
|
-
color="primary"
|
|
78
|
-
size="medium"
|
|
79
|
-
class="flex-1 bg-light radius-thin flex-center gap-thin"
|
|
80
|
-
>
|
|
81
|
-
{{isFollowing ? 'Follow' : 'Unfollow'}}
|
|
82
|
-
</Button>
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
<Dropdown :label="{component: IconEllipsis, class: 'bg-light radius-thin pd-thin i-big' }" v-model="showDropdown" class="relative">
|
|
86
|
-
<template #trigger>
|
|
87
|
-
<Button color="transp" size="medium" class="w-3r h-3r radius-full">
|
|
88
|
-
<IconEllipsis class="w-1-25r h-1-25r" />
|
|
89
|
-
</Button>
|
|
90
|
-
</template>
|
|
91
|
-
<template #default>
|
|
92
|
-
<div class="dropdown-menu bg-white pd-small radius-medium shadow-big mn-t-thin">
|
|
93
|
-
<Button @click="addToQueue" color="transp" size="small" class="w-100 t-nowrap justify-start">
|
|
94
|
-
Add to Queue
|
|
95
|
-
</Button>
|
|
96
|
-
<Button @click="copyLink" color="transp" size="small" class="w-100 t-nowrap justify-start">
|
|
97
|
-
Copy Link
|
|
98
|
-
</Button>
|
|
99
|
-
<template v-if="isOwner || isCollaborator">
|
|
100
|
-
<hr class="mn-v-thin border-dark-transp-10" />
|
|
101
|
-
<Button @click="editPlaylist" color="transp" size="small" class="w-100 t-nowrap justify-start">
|
|
102
|
-
Edit Playlist
|
|
103
|
-
</Button>
|
|
104
|
-
<Button v-if="isOwner" @click="toggleCollaborative" color="transp" size="small" class="t-nowrap w-100 justify-start">
|
|
105
|
-
{{ playlist.isCollaborative ? 'Make Private' : 'Make Collaborative' }}
|
|
106
|
-
</Button>
|
|
107
|
-
<Button v-if="isOwner" @click="deletePlaylist" color="danger" size="small" class="t-nowrap w-100 justify-start">
|
|
108
|
-
Delete Playlist
|
|
109
|
-
</Button>
|
|
110
|
-
</template>
|
|
111
|
-
</div>
|
|
112
|
-
</template>
|
|
113
|
-
</Dropdown>
|
|
114
|
-
</div>
|
|
54
|
+
<ActionButtons :buttons="actionButtons" />
|
|
115
55
|
|
|
116
56
|
<div class="artists-section mn-b-medium">
|
|
117
57
|
<h3 class="t-medium mn-b-small">Created by</h3>
|
|
@@ -349,6 +289,7 @@ import IconRefresh from '@martyrs/src/modules/icons/navigation/IconRefresh.vue';
|
|
|
349
289
|
import IconVerified from '@martyrs/src/modules/icons/navigation/IconCheckmark.vue';
|
|
350
290
|
|
|
351
291
|
// Components
|
|
292
|
+
import ActionButtons from '../blocks/ActionButtons.vue';
|
|
352
293
|
import TrackListCard from '../cards/TrackListCard.vue';
|
|
353
294
|
import PlaylistCard from '../cards/PlaylistCard.vue';
|
|
354
295
|
import PlaylistForm from '../forms/PlaylistForm.vue';
|
|
@@ -372,7 +313,6 @@ const emits = defineEmits(['page-loading', 'page-loaded']);
|
|
|
372
313
|
// State
|
|
373
314
|
const hasLoaded = ref(false);
|
|
374
315
|
const isFollowing = ref(false);
|
|
375
|
-
const showDropdown = ref(false);
|
|
376
316
|
const showEditModal = ref(false);
|
|
377
317
|
const showDeleteModal = ref(false);
|
|
378
318
|
const followedUsers = ref([]);
|
|
@@ -407,6 +347,62 @@ const totalDuration = computed(() => {
|
|
|
407
347
|
return formatDuration(totalSeconds);
|
|
408
348
|
});
|
|
409
349
|
|
|
350
|
+
const actionButtons = computed(() => {
|
|
351
|
+
const buttons = [
|
|
352
|
+
{
|
|
353
|
+
type: 'button',
|
|
354
|
+
class: 't-white bg-black',
|
|
355
|
+
icon: IconPlay,
|
|
356
|
+
iconFill: 'rgb(var(--white))',
|
|
357
|
+
text: 'Play All',
|
|
358
|
+
action: playPlaylist
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
type: 'button',
|
|
362
|
+
class: 'bg-light',
|
|
363
|
+
icon: IconShuffle,
|
|
364
|
+
text: 'Shuffle',
|
|
365
|
+
action: shufflePlay
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
type: 'button',
|
|
369
|
+
class: 'bg-light',
|
|
370
|
+
icon: null,
|
|
371
|
+
text: isFollowing.value ? 'Unfollow' : 'Follow',
|
|
372
|
+
action: toggleFollow
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
type: 'dropdown',
|
|
376
|
+
items: [
|
|
377
|
+
{ text: 'Add to Queue', action: addToQueue, class: 't-nowrap' },
|
|
378
|
+
{ text: 'Copy Link', action: copyLink, class: 't-nowrap' }
|
|
379
|
+
]
|
|
380
|
+
}
|
|
381
|
+
];
|
|
382
|
+
|
|
383
|
+
if (isOwner.value || isCollaborator.value) {
|
|
384
|
+
const items = buttons[3].items;
|
|
385
|
+
items.push({ separator: true });
|
|
386
|
+
items.push({ text: 'Edit Playlist', action: editPlaylist, class: 't-nowrap' });
|
|
387
|
+
|
|
388
|
+
if (isOwner.value) {
|
|
389
|
+
items.push({
|
|
390
|
+
text: playlist.value?.isCollaborative ? 'Make Private' : 'Make Collaborative',
|
|
391
|
+
action: toggleCollaborative,
|
|
392
|
+
class: 't-nowrap'
|
|
393
|
+
});
|
|
394
|
+
items.push({
|
|
395
|
+
text: 'Delete Playlist',
|
|
396
|
+
action: deletePlaylist,
|
|
397
|
+
color: 'danger',
|
|
398
|
+
class: 't-nowrap'
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return buttons;
|
|
404
|
+
});
|
|
405
|
+
|
|
410
406
|
// Helper functions
|
|
411
407
|
const getOwnerData = (playlist) => {
|
|
412
408
|
if (!playlist) return null;
|
|
@@ -521,13 +517,11 @@ const addToQueue = () => {
|
|
|
521
517
|
playlistTracks.value.forEach(track => {
|
|
522
518
|
playerActions.addToQueue(track);
|
|
523
519
|
});
|
|
524
|
-
showDropdown.value = false;
|
|
525
520
|
}
|
|
526
521
|
};
|
|
527
522
|
|
|
528
523
|
const editPlaylist = () => {
|
|
529
524
|
showEditModal.value = true;
|
|
530
|
-
showDropdown.value = false;
|
|
531
525
|
};
|
|
532
526
|
|
|
533
527
|
const toggleCollaborative = async () => {
|
|
@@ -536,9 +530,8 @@ const toggleCollaborative = async () => {
|
|
|
536
530
|
_id: playlist.value._id,
|
|
537
531
|
isCollaborative: !playlist.value.isCollaborative
|
|
538
532
|
};
|
|
539
|
-
|
|
533
|
+
|
|
540
534
|
await playlistsActions.updatePlaylist(updatedData);
|
|
541
|
-
showDropdown.value = false;
|
|
542
535
|
} catch (error) {
|
|
543
536
|
console.error('Error updating playlist:', error);
|
|
544
537
|
}
|
|
@@ -546,7 +539,6 @@ const toggleCollaborative = async () => {
|
|
|
546
539
|
|
|
547
540
|
const deletePlaylist = () => {
|
|
548
541
|
showDeleteModal.value = true;
|
|
549
|
-
showDropdown.value = false;
|
|
550
542
|
};
|
|
551
543
|
|
|
552
544
|
const confirmDelete = async () => {
|
|
@@ -576,7 +568,6 @@ const removeTrack = async (trackId) => {
|
|
|
576
568
|
|
|
577
569
|
const copyLink = () => {
|
|
578
570
|
navigator.clipboard.writeText(window.location.href);
|
|
579
|
-
showDropdown.value = false;
|
|
580
571
|
};
|
|
581
572
|
|
|
582
573
|
const handlePlaylistUpdated = () => {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
</div>
|
|
14
14
|
|
|
15
15
|
<!-- Track Content -->
|
|
16
|
-
<div v-if="track" class="track-content cols-2
|
|
16
|
+
<div v-if="track" class="track-content cols-2 mobile:cols-1 gap-big">
|
|
17
17
|
<!-- Left Column - Cover & Stats -->
|
|
18
18
|
<div class="pos-sticky pos-t-0 mobile:pos-relative track-cover-section">
|
|
19
19
|
<!-- Cover with Play Overlay -->
|
|
@@ -62,78 +62,18 @@
|
|
|
62
62
|
<!-- Track Title -->
|
|
63
63
|
<h1 class="h1 mn-b-medium">{{ track.title }}</h1>
|
|
64
64
|
<!-- Action Buttons -->
|
|
65
|
-
<
|
|
66
|
-
<Button
|
|
67
|
-
@click="playTrack"
|
|
68
|
-
color="primary"
|
|
69
|
-
size="medium"
|
|
70
|
-
class="flex-1 t-white bg-black radius-thin flex-center gap-thin"
|
|
71
|
-
>
|
|
72
|
-
<IconPlay v-if="!isPlaying" fill="rgb(var(--white))" class="i-medium" />
|
|
73
|
-
<IconPause v-else fill="rgb(var(--white))" class="i-medium" />
|
|
74
|
-
{{ !isPlaying ? 'Play' : 'Pause'}}
|
|
75
|
-
</Button>
|
|
76
|
-
|
|
77
|
-
<Button
|
|
78
|
-
@click="addToQueue"
|
|
79
|
-
color="primary"
|
|
80
|
-
size="medium"
|
|
81
|
-
class="flex-1 bg-light radius-thin flex-center gap-thin"
|
|
82
|
-
>
|
|
83
|
-
<IconAdd class="i-medium" />
|
|
84
|
-
Add to Queue
|
|
85
|
-
</Button>
|
|
86
|
-
|
|
87
|
-
<Button
|
|
88
|
-
@click="toggleFavorite"
|
|
89
|
-
color="primary"
|
|
90
|
-
size="medium"
|
|
91
|
-
class="flex-1 bg-light radius-thin flex-center gap-thin"
|
|
92
|
-
>
|
|
93
|
-
<IconLike class="i-medium" :fill="isFavorite ? 'rgb(var(--main)':'rgb(var(--black)'" />
|
|
94
|
-
{{isFavorite ? 'Liked' : 'Like'}}
|
|
95
|
-
</Button>
|
|
96
|
-
|
|
97
|
-
<Dropdown :label="{component: IconEllipsis, class: 'bg-light radius-thin pd-thin i-big' }" v-model="showDropdown" class="relative">
|
|
98
|
-
<template #trigger>
|
|
99
|
-
<Button color="transp" size="medium" class="w-3r h-3r radius-full">
|
|
100
|
-
<IconEllipsis class="w-1-25r h-1-25r" />
|
|
101
|
-
</Button>
|
|
102
|
-
</template>
|
|
103
|
-
<template #default>
|
|
104
|
-
<div class="dropdown-menu bg-dark pd-small radius-medium shadow-big mn-t-thin">
|
|
105
|
-
<Button @click="showAddToPlaylistModal = true" color="transp" size="small" class="w-100 justify-start">
|
|
106
|
-
Add to Playlist
|
|
107
|
-
</Button>
|
|
108
|
-
<Button @click="copyLink" color="transp" size="small" class="w-100 justify-start">
|
|
109
|
-
Copy Link
|
|
110
|
-
</Button>
|
|
111
|
-
<template v-if="isOwner">
|
|
112
|
-
<hr class="mn-v-thin border-dark-transp-10" />
|
|
113
|
-
<Button @click="editTrack" color="transp" size="small" class="w-100 justify-start">
|
|
114
|
-
Edit Track
|
|
115
|
-
</Button>
|
|
116
|
-
<Button @click="deleteTrack" color="danger" size="small" class="w-100 justify-start">
|
|
117
|
-
Delete Track
|
|
118
|
-
</Button>
|
|
119
|
-
</template>
|
|
120
|
-
</div>
|
|
121
|
-
</template>
|
|
122
|
-
</Dropdown>
|
|
123
|
-
</div>
|
|
65
|
+
<ActionButtons :buttons="actionButtons" />
|
|
124
66
|
|
|
125
67
|
<!-- Artist Card -->
|
|
126
68
|
<div class="artists-section mn-b-medium">
|
|
127
69
|
<h3 class="t-medium mn-b-small" v-if="track.artist">Artist</h3>
|
|
128
|
-
<
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
/>
|
|
136
|
-
</div>
|
|
70
|
+
<ArtistCardSmall
|
|
71
|
+
:key="track.artist._id"
|
|
72
|
+
:artist="track.artist"
|
|
73
|
+
:is-following="isFollowingArtist"
|
|
74
|
+
:show-follow-button="!isOwner"
|
|
75
|
+
@toggle-follow="toggleFollowArtist"
|
|
76
|
+
/>
|
|
137
77
|
</div>
|
|
138
78
|
|
|
139
79
|
<!-- Metadata Cards -->
|
|
@@ -302,6 +242,7 @@ import IconEye from '@martyrs/src/modules/icons/actions/IconShow.vue';
|
|
|
302
242
|
import IconVerified from '@martyrs/src/modules/icons/navigation/IconCheckmark.vue';
|
|
303
243
|
|
|
304
244
|
// Components
|
|
245
|
+
import ActionButtons from '../blocks/ActionButtons.vue';
|
|
305
246
|
import TrackListCard from '../cards/TrackListCard.vue';
|
|
306
247
|
import ArtistCardSmall from '../cards/ArtistCardSmall.vue';
|
|
307
248
|
// import PlaylistSelector from '../forms/PlaylistSelector.vue';
|
|
@@ -321,7 +262,6 @@ const emits = defineEmits(['page-loading', 'page-loaded']);
|
|
|
321
262
|
|
|
322
263
|
// State
|
|
323
264
|
const hasLoaded = ref(false);
|
|
324
|
-
const showDropdown = ref(false);
|
|
325
265
|
const showAddToPlaylistModal = ref(false);
|
|
326
266
|
const isFavorite = ref(false);
|
|
327
267
|
const isFollowingArtist = ref(false);
|
|
@@ -338,6 +278,50 @@ const isOwner = computed(() => {
|
|
|
338
278
|
return track.value?.owner?.target === authState.user?._id;
|
|
339
279
|
});
|
|
340
280
|
|
|
281
|
+
const actionButtons = computed(() => {
|
|
282
|
+
const buttons = [
|
|
283
|
+
{
|
|
284
|
+
type: 'button',
|
|
285
|
+
class: 't-white bg-black',
|
|
286
|
+
icon: isPlaying.value ? IconPause : IconPlay,
|
|
287
|
+
iconFill: 'rgb(var(--white))',
|
|
288
|
+
text: isPlaying.value ? 'Pause' : 'Play',
|
|
289
|
+
action: playTrack
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
type: 'button',
|
|
293
|
+
class: 'bg-light',
|
|
294
|
+
icon: IconAdd,
|
|
295
|
+
text: 'Add to Queue',
|
|
296
|
+
action: addToQueue
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
type: 'button',
|
|
300
|
+
class: 'bg-light',
|
|
301
|
+
icon: IconLike,
|
|
302
|
+
iconFill: isFavorite.value ? 'rgb(var(--main))' : 'rgb(var(--black))',
|
|
303
|
+
text: isFavorite.value ? 'Liked' : 'Like',
|
|
304
|
+
action: toggleFavorite
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
type: 'dropdown',
|
|
308
|
+
items: [
|
|
309
|
+
{ text: 'Add to Playlist', action: () => showAddToPlaylistModal.value = true },
|
|
310
|
+
{ text: 'Copy Link', action: copyLink }
|
|
311
|
+
]
|
|
312
|
+
}
|
|
313
|
+
];
|
|
314
|
+
|
|
315
|
+
if (isOwner.value) {
|
|
316
|
+
const items = buttons[3].items;
|
|
317
|
+
items.push({ separator: true });
|
|
318
|
+
items.push({ text: 'Edit Track', action: editTrack });
|
|
319
|
+
items.push({ text: 'Delete Track', action: deleteTrack, color: 'danger' });
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return buttons;
|
|
323
|
+
});
|
|
324
|
+
|
|
341
325
|
// Format helpers
|
|
342
326
|
const formatDuration = (seconds) => {
|
|
343
327
|
if (!seconds) return '0:00';
|
|
@@ -410,7 +394,6 @@ const deleteTrack = async () => {
|
|
|
410
394
|
|
|
411
395
|
const copyLink = () => {
|
|
412
396
|
navigator.clipboard.writeText(window.location.href);
|
|
413
|
-
showDropdown.value = false;
|
|
414
397
|
};
|
|
415
398
|
|
|
416
399
|
// Data fetching
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section
|
|
3
|
+
class="o-y-scroll o-x-hidden bg-light pd-small pos-relative z-index-2 t-center t-black w-100 h-100"
|
|
4
|
+
>
|
|
5
|
+
|
|
6
|
+
<div
|
|
7
|
+
class="pos-relative gap-small flex-nowrap flex-column flex-center flex z-index-1"
|
|
8
|
+
>
|
|
9
|
+
<!-- COVER -->
|
|
10
|
+
<div class="mn-b-thin h-max-30r br-2px br-solid br-black-transp-10 radius-extra w-100 pos-relative aspect-1x1 flex-center flex "
|
|
11
|
+
style="
|
|
12
|
+
background: linear-gradient(180deg, #BDBDBD 0%, #D9D9D9 79.69%, #A5A5A5 100%);
|
|
13
|
+
box-shadow: 0 2px 0px 2px #aaaaaa;
|
|
14
|
+
"
|
|
15
|
+
>
|
|
16
|
+
|
|
17
|
+
<div class="pos-relative">
|
|
18
|
+
<div class="radioTonarWrapper" :class="{'activeTonar': playerState.isPlaying}">
|
|
19
|
+
<img
|
|
20
|
+
class="radioTonar z-index-2"
|
|
21
|
+
src="./tonar.png"
|
|
22
|
+
:class="{'playingTonar': playerState.isPlaying}"
|
|
23
|
+
>
|
|
24
|
+
</div>
|
|
25
|
+
<div
|
|
26
|
+
ref="disk"
|
|
27
|
+
:class="['radius-100 rotate-gradient flex-center flex']"
|
|
28
|
+
:style="{
|
|
29
|
+
transform: `rotate(${playerState.rotationAngle}deg)`,
|
|
30
|
+
width: '24rem',
|
|
31
|
+
height: '24rem',
|
|
32
|
+
border: '3px solid var(--black)',
|
|
33
|
+
'box-shadow': 'rgba(0,0,0,0.5) 0 0 64px 0px'
|
|
34
|
+
}"
|
|
35
|
+
class="pos-relative z-index-1"
|
|
36
|
+
>
|
|
37
|
+
<div
|
|
38
|
+
v-for="i in 11"
|
|
39
|
+
:key="i"
|
|
40
|
+
:style="{
|
|
41
|
+
border: '1px solid rgba(0,0,0,0.25)',
|
|
42
|
+
position: 'absolute',
|
|
43
|
+
width: 23 - i * 1 + 'rem',
|
|
44
|
+
height: 23 - i * 1 + 'rem',
|
|
45
|
+
'border-radius': '100%',
|
|
46
|
+
'box-shadow': 'rgb(47 47 47 / 18%) 0px 0px 5px 10px'
|
|
47
|
+
}"
|
|
48
|
+
>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<div
|
|
52
|
+
:style="{
|
|
53
|
+
width: '10rem',
|
|
54
|
+
height: '10rem',
|
|
55
|
+
backgroundImage: `url('${playerState.currentTrack?.coverUrl || playerState.currentTrack?.album?.coverArt}')`,
|
|
56
|
+
backgroundPosition: 'center center',
|
|
57
|
+
backgroundSize: '106%',
|
|
58
|
+
}"
|
|
59
|
+
class="radius-extra br-solid br-black-transp-10 br-1px"
|
|
60
|
+
>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<!-- NOW PLAYING -->
|
|
69
|
+
<div
|
|
70
|
+
class="pd-thin bg-white radius-medium o-hidden w-100 pos-relative"
|
|
71
|
+
>
|
|
72
|
+
<p class="mn-l-auto mn-b-thin mn-r-auto radius-big pd-thin bg-second w-min">NOW PLAYING</p>
|
|
73
|
+
<!-- SONG -->
|
|
74
|
+
<Marquee
|
|
75
|
+
v-if="playerState.currentTrack"
|
|
76
|
+
class="h2 uppercase mn-b-thin"
|
|
77
|
+
:gradient="true"
|
|
78
|
+
:gradientColor="'rgb(var(--white))'"
|
|
79
|
+
:clone="true"
|
|
80
|
+
gradient-length="10%"
|
|
81
|
+
>
|
|
82
|
+
{{ playerState.currentTrack.title + '\xa0\xa0'}}
|
|
83
|
+
</Marquee>
|
|
84
|
+
|
|
85
|
+
<!-- AUTHOR -->
|
|
86
|
+
<p
|
|
87
|
+
v-if="playerState.currentTrack"
|
|
88
|
+
class="h3 uppercase t-transp"
|
|
89
|
+
>
|
|
90
|
+
{{ playerState.currentTrack.artist?.name || 'Unknown Artist' }}
|
|
91
|
+
</p>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<!-- LIKES -->
|
|
95
|
+
<div
|
|
96
|
+
class="pd-thin bg-white radius-medium w-100 pos-relative flex flex-v-center gap-thin"
|
|
97
|
+
>
|
|
98
|
+
<div v-if="authState.user" class="flex-nowrap flex gap-thin flex-v-center">
|
|
99
|
+
<IconLike
|
|
100
|
+
@click="toggleLike()"
|
|
101
|
+
:isLiked="isLiked"
|
|
102
|
+
fill="rgb(var(--black))"
|
|
103
|
+
class="i-medium cursor-pointer"
|
|
104
|
+
:class="{'no-events': isLoading}"
|
|
105
|
+
/>
|
|
106
|
+
<p class="t-semi h4">{{ isLiked ? 'Liked' : 'Like' }}</p>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<p class="t-semi h4" :class="{'mn-l-auto': authState.user}">{{ likesCount }} {{ likesCount === 1 ? 'person' : 'people' }} liked</p>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<!-- CONTROLS -->
|
|
113
|
+
<div
|
|
114
|
+
class="gap-thin flex-center flex-nowrap flex pd-small bg-white radius-medium o-hidden w-100 pos-relative"
|
|
115
|
+
>
|
|
116
|
+
<PlayerControls />
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<!-- VOLUME -->
|
|
120
|
+
<div class="pd-thin bg-white radius-medium w-100 pos-relative">
|
|
121
|
+
<VolumeControl />
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
<!-- QUEUE LIST -->
|
|
126
|
+
<div
|
|
127
|
+
v-if="playerState.queue.length > 0"
|
|
128
|
+
class="mn-b-small bg-white radius-medium o-hidden w-100 pos-relative"
|
|
129
|
+
>
|
|
130
|
+
|
|
131
|
+
<div class="pd-regular w-100 gap-thin flex-nowrap flex flex-v-center">
|
|
132
|
+
<IconEvents :fill="'rgb(var(--black))'" class="t-transp i-medium"/>
|
|
133
|
+
<p class="w-100 t-transp t-left">QUEUE</p>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<TrackListCard
|
|
137
|
+
v-for="(track, index) in playerState.queue.slice(0, 10)"
|
|
138
|
+
:key="track._id || index"
|
|
139
|
+
:track="track"
|
|
140
|
+
:index="index"
|
|
141
|
+
:showCover="true"
|
|
142
|
+
:showAlbum="false"
|
|
143
|
+
/>
|
|
144
|
+
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
</section>
|
|
150
|
+
</template>
|
|
151
|
+
|
|
152
|
+
<script setup>
|
|
153
|
+
import { ref, computed, onMounted } from 'vue';
|
|
154
|
+
|
|
155
|
+
import { Text, Tooltip, Marquee } from '@ozdao/martyrs';
|
|
156
|
+
import IconLike from '@martyrs/src/modules/icons/navigation/IconLike.vue';
|
|
157
|
+
import IconEvents from '@martyrs/src/modules/icons/entities/IconEvents.vue';
|
|
158
|
+
|
|
159
|
+
import TrackListCard from '../cards/TrackListCard.vue';
|
|
160
|
+
import VolumeControl from './VolumeControl.vue';
|
|
161
|
+
import PlayerControls from './PlayerControls.vue';
|
|
162
|
+
import { state as playerState, actions as playerActions } from '../../store/player.js';
|
|
163
|
+
import { state as authState } from '@martyrs/src/modules/auth/views/store/auth.js';
|
|
164
|
+
|
|
165
|
+
const isLiked = ref(false);
|
|
166
|
+
const isLoading = ref(false);
|
|
167
|
+
const likesCount = ref(0);
|
|
168
|
+
|
|
169
|
+
async function toggleLike() {
|
|
170
|
+
// TODO: Implement likes integration with community module
|
|
171
|
+
isLiked.value = !isLiked.value;
|
|
172
|
+
likesCount.value += isLiked.value ? 1 : -1;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
onMounted(() => {
|
|
176
|
+
if ('mediaSession' in navigator) {
|
|
177
|
+
navigator.mediaSession.setActionHandler('pause', () => playerActions.togglePlay());
|
|
178
|
+
navigator.mediaSession.setActionHandler('play', () => playerActions.togglePlay());
|
|
179
|
+
navigator.mediaSession.setActionHandler('stop', () => playerActions.togglePlay());
|
|
180
|
+
navigator.mediaSession.setActionHandler('previoustrack', () => playerActions.playPrevious());
|
|
181
|
+
navigator.mediaSession.setActionHandler('nexttrack', () => playerActions.playNext());
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
</script>
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
<style lang="scss" scoped>
|
|
189
|
+
.radioTonarWrapper {
|
|
190
|
+
width: 15rem;
|
|
191
|
+
position: absolute;
|
|
192
|
+
z-index: 30;
|
|
193
|
+
transform: rotate(253deg);
|
|
194
|
+
transform-origin: 75% center;
|
|
195
|
+
top: 0;
|
|
196
|
+
right: -2.5rem;
|
|
197
|
+
transition: transform 1s ease-in-out;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.radioTonar {
|
|
201
|
+
width: 15rem;
|
|
202
|
+
transform-origin: 75% center;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.activeTonar {
|
|
206
|
+
transform: rotate(285deg);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.playingTonar {
|
|
210
|
+
animation: playingTonar 2s ease-in-out infinite;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
@keyframes playingTonar {
|
|
214
|
+
0%, 100% {
|
|
215
|
+
transform: rotate(0deg);
|
|
216
|
+
}
|
|
217
|
+
25% {
|
|
218
|
+
transform: rotate(2deg);
|
|
219
|
+
}
|
|
220
|
+
50% {
|
|
221
|
+
transform: rotate(-2deg);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
@property --a {
|
|
226
|
+
syntax: '<angle>';
|
|
227
|
+
inherits: false;
|
|
228
|
+
initial-value: 0deg;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
@property --b {
|
|
232
|
+
syntax: '<angle>';
|
|
233
|
+
inherits: false;
|
|
234
|
+
initial-value: 0deg;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.rotate-gradient {
|
|
238
|
+
--a: 0deg;
|
|
239
|
+
--b: 0deg;
|
|
240
|
+
transition: --a 0.5s, --b 0.5s;
|
|
241
|
+
|
|
242
|
+
background:
|
|
243
|
+
conic-gradient(from var(--a), rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.33), rgba(255, 255, 255, 0.1)),
|
|
244
|
+
linear-gradient(180deg, rgba(0, 0, 0, 1) 0%, rgba(255, 255, 255, 0.1) 50%, rgba(0, 0, 0, 1) 100%),
|
|
245
|
+
linear-gradient(180deg, #000 0%, rgba(10, 10, 10, 0.00) 100%),
|
|
246
|
+
#000;
|
|
247
|
+
}
|
|
248
|
+
</style>
|