@ozdao/martyrs 0.2.492 → 0.2.494
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 +53 -90
- package/dist/builder.js +54 -91
- package/dist/{crud-B-kQw3Z5.cjs → crud-JN_LFj01.cjs} +3 -0
- package/dist/{crud-Cwx5VlSm.js → crud-sE7GLPbj.js} +3 -0
- package/dist/globals.server.cjs +322 -3
- package/dist/globals.server.js +303 -1
- package/dist/{globals.verifier-D68mHEBl.cjs → globals.verifier-C0zj_LLo.cjs} +8 -1
- package/dist/{globals.verifier-CWFz5Gh2.js → globals.verifier-DFqKQ7hK.js} +8 -1
- package/dist/inventory.server.cjs +2 -2
- package/dist/inventory.server.js +2 -2
- package/dist/{main-SZQ1QjeP.js → main-CJm5myDI.js} +631 -607
- package/dist/{main-MzmGbSxs.cjs → main-DTaE01lg.cjs} +6 -6
- package/dist/martyrs/src/components/Calendar/Calendar.vue2.cjs +1 -1
- package/dist/martyrs/src/components/Calendar/Calendar.vue2.cjs.map +1 -1
- package/dist/martyrs/src/components/Calendar/Calendar.vue2.js +1 -1
- package/dist/martyrs/src/components/Calendar/Calendar.vue2.js.map +1 -1
- package/dist/martyrs/src/components/Feed/Feed.vue.cjs +33 -7
- package/dist/martyrs/src/components/Feed/Feed.vue.cjs.map +1 -1
- package/dist/martyrs/src/components/Feed/Feed.vue.js +33 -7
- package/dist/martyrs/src/components/Feed/Feed.vue.js.map +1 -1
- package/dist/martyrs/src/components/Field/{Field.vue2.cjs → Field.vue.cjs} +2 -2
- package/dist/martyrs/src/components/Field/{Field.vue2.js.map → Field.vue.cjs.map} +1 -1
- package/dist/martyrs/src/components/Field/{Field.vue2.js → Field.vue.js} +2 -2
- package/dist/martyrs/src/components/Field/Field.vue.js.map +1 -0
- package/dist/martyrs/src/components/FieldBig/FieldBig.vue.cjs +1 -1
- package/dist/martyrs/src/components/FieldBig/FieldBig.vue.js +1 -1
- 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/components/Menu/{Menu.vue.cjs → Menu.vue2.cjs} +2 -2
- package/dist/martyrs/src/components/Menu/Menu.vue2.cjs.map +1 -0
- package/dist/martyrs/src/components/Menu/{Menu.vue.js → Menu.vue2.js} +2 -2
- package/dist/martyrs/src/components/Menu/Menu.vue2.js.map +1 -0
- package/dist/martyrs/src/components/Menu/MenuItem.vue.js +2 -2
- package/dist/martyrs/src/components/Menu/MenuItem.vue.js.map +1 -1
- package/dist/martyrs/src/components/PhotoViewer/PhotoViewer.vue.js +4 -4
- package/dist/martyrs/src/modules/auth/views/components/pages/EnterCode.vue.cjs +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/EnterCode.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/EnterPassword.vue.cjs +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/EnterPassword.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/Invite.vue.cjs +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/Invite.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.cjs +2 -2
- package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js +2 -2
- package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEditProfile.vue.cjs +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEditProfile.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/ResetPassword.vue.cjs +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/ResetPassword.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/SignIn.vue.cjs +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/SignIn.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/SignUp.vue.cjs +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/SignUp.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/sections/ProfileEditCredentials.vue.cjs +1 -1
- package/dist/martyrs/src/modules/auth/views/components/sections/ProfileEditCredentials.vue.js +1 -1
- package/dist/martyrs/src/modules/community/components/pages/CreateBlogPost.vue.cjs +2 -2
- package/dist/martyrs/src/modules/community/components/pages/CreateBlogPost.vue.js +2 -2
- package/dist/martyrs/src/modules/constructor/components/elements/Card.vue.cjs +1 -1
- package/dist/martyrs/src/modules/constructor/components/elements/Card.vue.js +1 -1
- package/dist/martyrs/src/modules/constructor/components/elements/Embed.vue.cjs +1 -1
- package/dist/martyrs/src/modules/constructor/components/elements/Embed.vue.js +1 -1
- package/dist/martyrs/src/modules/events/components/pages/EditEvent.vue.cjs +1 -1
- package/dist/martyrs/src/modules/events/components/pages/EditEvent.vue.js +1 -1
- package/dist/martyrs/src/modules/events/components/pages/EditEventTickets.vue.cjs +1 -1
- package/dist/martyrs/src/modules/events/components/pages/EditEventTickets.vue.js +1 -1
- package/dist/martyrs/src/modules/events/components/pages/Event.vue.cjs +1 -1
- package/dist/martyrs/src/modules/events/components/pages/Event.vue.js +1 -1
- package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.cjs +1 -1
- package/dist/martyrs/src/modules/gallery/components/sections/BackofficeGallery.vue.js +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/blocks/BlockSearch.vue.cjs +1 -1
- package/dist/martyrs/src/modules/globals/views/components/blocks/BlockSearch.vue.js +1 -1
- package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.cjs +5 -1
- 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 +5 -1
- package/dist/martyrs/src/modules/globals/views/components/layouts/Client.vue.js.map +1 -1
- package/dist/martyrs/src/modules/icons/entities/IconTime.vue.cjs +2 -2
- package/dist/martyrs/src/modules/icons/entities/IconTime.vue.js +2 -2
- package/dist/martyrs/src/modules/icons/navigation/IconChevronLeft.vue.cjs +2 -2
- package/dist/martyrs/src/modules/icons/navigation/IconChevronLeft.vue.js +2 -2
- package/dist/martyrs/src/modules/icons/navigation/IconChevronRight.vue.cjs +2 -2
- package/dist/martyrs/src/modules/icons/navigation/IconChevronRight.vue.js +2 -2
- package/dist/martyrs/src/modules/icons/pages/IconsPage.vue.js +6 -6
- package/dist/martyrs/src/modules/icons/pages/IconsPage.vue.js.map +1 -1
- package/dist/martyrs/src/modules/inventory/components/forms/AdjustmentForm.vue.cjs +1 -1
- package/dist/martyrs/src/modules/inventory/components/forms/AdjustmentForm.vue.js +1 -1
- package/dist/martyrs/src/modules/inventory/components/forms/StockAlertsForm.vue.cjs +1 -1
- package/dist/martyrs/src/modules/inventory/components/forms/StockAlertsForm.vue.js +1 -1
- package/dist/martyrs/src/modules/inventory/components/pages/Inventory.vue.cjs +1 -1
- package/dist/martyrs/src/modules/inventory/components/pages/InventoryEdit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/inventory/components/pages/InventoryEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/cards/AlbumCard.vue.cjs +22 -15
- package/dist/martyrs/src/modules/music/components/cards/AlbumCard.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/cards/AlbumCard.vue.js +23 -16
- package/dist/martyrs/src/modules/music/components/cards/AlbumCard.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/cards/ArtistCard.vue.cjs +2 -2
- package/dist/martyrs/src/modules/music/components/cards/ArtistCard.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/cards/ArtistCard.vue.js +2 -2
- package/dist/martyrs/src/modules/music/components/cards/ArtistCard.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/cards/PlaylistCard.vue.cjs +31 -13
- package/dist/martyrs/src/modules/music/components/cards/PlaylistCard.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/cards/PlaylistCard.vue.js +33 -15
- package/dist/martyrs/src/modules/music/components/cards/PlaylistCard.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.cjs +39 -22
- 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 +39 -22
- package/dist/martyrs/src/modules/music/components/cards/TrackListCard.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/forms/AlbumForm.vue.cjs +1 -1
- package/dist/martyrs/src/modules/music/components/forms/AlbumForm.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/forms/ArtistForm.vue.cjs +1 -1
- package/dist/martyrs/src/modules/music/components/forms/ArtistForm.vue.js +1 -1
- package/dist/martyrs/src/modules/music/components/forms/PlaylistForm.vue.cjs +385 -125
- package/dist/martyrs/src/modules/music/components/forms/PlaylistForm.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/forms/PlaylistForm.vue.js +391 -131
- package/dist/martyrs/src/modules/music/components/forms/PlaylistForm.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.cjs +24 -7
- 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 +25 -8
- package/dist/martyrs/src/modules/music/components/forms/SearchForm.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/forms/TrackForm.vue.cjs +99 -87
- package/dist/martyrs/src/modules/music/components/forms/TrackForm.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/forms/TrackForm.vue.js +111 -99
- package/dist/martyrs/src/modules/music/components/forms/TrackForm.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/layouts/MusicBottomPlayer.vue.cjs +21 -0
- package/dist/martyrs/src/modules/music/components/layouts/MusicBottomPlayer.vue.cjs.map +1 -0
- package/dist/martyrs/src/modules/music/components/layouts/MusicBottomPlayer.vue.js +21 -0
- package/dist/martyrs/src/modules/music/components/layouts/MusicBottomPlayer.vue.js.map +1 -0
- package/dist/martyrs/src/modules/music/components/pages/Album.vue.cjs +442 -210
- 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 +445 -213
- 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 +92 -117
- 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 +93 -118
- package/dist/martyrs/src/modules/music/components/pages/Artist.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/MusicHome.vue.cjs +72 -113
- package/dist/martyrs/src/modules/music/components/pages/MusicHome.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/MusicHome.vue.js +78 -119
- package/dist/martyrs/src/modules/music/components/pages/MusicHome.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/pages/MusicLibrary.vue.cjs +15 -12
- 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 +15 -12
- 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 +558 -429
- 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 +560 -431
- 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 +146 -284
- 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 +149 -287
- 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 +460 -63
- 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 +462 -65
- package/dist/martyrs/src/modules/music/components/pages/Track.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/player/MusicPlayer.vue.cjs +126 -136
- package/dist/martyrs/src/modules/music/components/player/MusicPlayer.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/player/MusicPlayer.vue.js +129 -139
- package/dist/martyrs/src/modules/music/components/player/MusicPlayer.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/player/TrackProgress.vue.cjs +18 -15
- package/dist/martyrs/src/modules/music/components/player/TrackProgress.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/player/TrackProgress.vue.js +18 -15
- package/dist/martyrs/src/modules/music/components/player/TrackProgress.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/components/player/VolumeControl.vue.cjs +28 -23
- package/dist/martyrs/src/modules/music/components/player/VolumeControl.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/components/player/VolumeControl.vue.js +29 -24
- package/dist/martyrs/src/modules/music/components/player/VolumeControl.vue.js.map +1 -1
- package/dist/martyrs/src/modules/music/music.client.cjs +3 -6
- package/dist/martyrs/src/modules/music/music.client.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/music.client.js +9 -12
- package/dist/martyrs/src/modules/music/music.client.js.map +1 -1
- package/dist/martyrs/src/modules/music/router/music.cjs +27 -1
- package/dist/martyrs/src/modules/music/router/music.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/router/music.js +27 -1
- package/dist/martyrs/src/modules/music/router/music.js.map +1 -1
- package/dist/martyrs/src/modules/music/store/artists.cjs +6 -4
- package/dist/martyrs/src/modules/music/store/artists.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/store/artists.js +6 -4
- package/dist/martyrs/src/modules/music/store/artists.js.map +1 -1
- package/dist/martyrs/src/modules/music/store/player.cjs +5 -0
- package/dist/martyrs/src/modules/music/store/player.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/store/player.js +5 -0
- package/dist/martyrs/src/modules/music/store/player.js.map +1 -1
- package/dist/martyrs/src/modules/music/store/tracks.cjs +22 -0
- package/dist/martyrs/src/modules/music/store/tracks.cjs.map +1 -1
- package/dist/martyrs/src/modules/music/store/tracks.js +22 -0
- package/dist/martyrs/src/modules/music/store/tracks.js.map +1 -1
- package/dist/martyrs/src/modules/orders/components/blocks/CardOrderBackoffice.vue.js +2 -2
- package/dist/martyrs/src/modules/orders/components/pages/OrderBackoffice.vue.js +2 -2
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreateBackoffice.vue.cjs +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreateBackoffice.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/FormAddCustomer.vue.cjs +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/FormAddCustomer.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/FormCustomerDetails.vue.cjs +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/FormCustomerDetails.vue.js +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.cjs +1 -1
- package/dist/martyrs/src/modules/orders/components/sections/FormDelivery.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/blocks/CardOrganization.vue.js +2 -2
- package/dist/martyrs/src/modules/organizations/components/pages/DepartmentEdit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/DepartmentEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.cjs +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Organization.vue.cjs +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Organization.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationBackoffice.vue.cjs +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationBackoffice.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/OrganizationEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/sections/Documents.vue.cjs +1 -1
- package/dist/martyrs/src/modules/organizations/components/sections/Documents.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/sections/MembersAdd.vue.cjs +1 -1
- package/dist/martyrs/src/modules/organizations/components/sections/MembersAdd.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/components/sections/Organizations.vue.cjs +1 -1
- package/dist/martyrs/src/modules/organizations/components/sections/Organizations.vue.js +1 -1
- package/dist/martyrs/src/modules/organizations/router/organizations.cjs +1 -1
- package/dist/martyrs/src/modules/organizations/router/organizations.js +1 -1
- package/dist/martyrs/src/modules/pages/views/components/blocks/CardPage.vue.cjs +1 -1
- package/dist/martyrs/src/modules/pages/views/components/blocks/CardPage.vue.js +1 -1
- package/dist/martyrs/src/modules/pages/views/components/pages/PageEdit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/pages/views/components/pages/PageEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/sections/EditAttributes.vue.cjs +1 -1
- package/dist/martyrs/src/modules/products/components/sections/EditAttributes.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/sections/EditDiscounts.vue.cjs +1 -1
- package/dist/martyrs/src/modules/products/components/sections/EditDiscounts.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/sections/EditVariants.vue.cjs +1 -1
- package/dist/martyrs/src/modules/products/components/sections/EditVariants.vue.js +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttBar.vue.cjs +4 -3
- package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttBar.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttBar.vue.js +4 -3
- package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttBar.vue.js.map +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttChart.vue.cjs +37 -70
- package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttChart.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttChart.vue.js +38 -71
- package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttChart.vue.js.map +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttToolbar.vue.cjs +2 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttToolbar.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttToolbar.vue.js +6 -5
- package/dist/martyrs/src/modules/rents/views/components/pages/Gant/GanttToolbar.vue.js.map +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/Rents.vue.cjs +45 -52
- package/dist/martyrs/src/modules/rents/views/components/pages/Rents.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/Rents.vue.js +46 -53
- package/dist/martyrs/src/modules/rents/views/components/pages/Rents.vue.js.map +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/RentsEdit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/RentsEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/spots/components/blocks/SpotMemberModify.vue.cjs +1 -1
- package/dist/martyrs/src/modules/spots/components/blocks/SpotMemberModify.vue.js +1 -1
- package/dist/martyrs/src/modules/spots/components/layouts/Spots.vue.cjs +1 -1
- package/dist/martyrs/src/modules/spots/components/layouts/Spots.vue.js +1 -1
- package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/spots/components/pages/SpotEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/spots/components/sections/WorktimeEdit.vue.js +1 -1
- package/dist/martyrs/src/modules/wallet/views/components/blocks/CardDeposit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/wallet/views/components/blocks/CardDeposit.vue.js +1 -1
- package/dist/martyrs/src/modules/wallet/views/components/blocks/CryptoDeposit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/wallet/views/components/blocks/CryptoDeposit.vue.js +1 -1
- package/dist/martyrs.cjs.js +1 -1
- package/dist/martyrs.css +1 -1
- package/dist/martyrs.es.js +1 -1
- package/dist/music.server.cjs +124 -31
- package/dist/music.server.js +124 -31
- package/dist/organizations.server.cjs +1 -1
- package/dist/organizations.server.js +1 -1
- package/dist/products.server.cjs +2 -2
- package/dist/products.server.js +2 -2
- package/dist/rents.server.cjs +3 -3
- package/dist/rents.server.js +3 -3
- package/dist/style.css +373 -80
- package/dist/{web-D7lZjuC0.js → web-Dkk0_7TA.js} +1 -1
- package/dist/{web-D-YZ9KHz.cjs → web-stVkXd0l.cjs} +1 -1
- package/package.json +1 -1
- package/src/builder/modes/ssr.prod.js +21 -5
- package/src/builder/rspack/rspack.config.spa.client.js +0 -44
- package/src/builder/rspack/rspack.config.ssr.client.js +40 -40
- package/src/components/Calendar/Calendar.vue +378 -377
- package/src/components/Feed/Feed.vue +28 -2
- package/src/modules/globals/controllers/classes/crud/crud.policies.js +5 -0
- package/src/modules/globals/controllers/classes/globals.validator.js +8 -1
- package/src/modules/globals/views/components/layouts/Client.vue +7 -0
- package/src/modules/music/README.md +8 -0
- package/src/modules/music/components/SidebarMusic.vue +6 -9
- package/src/modules/music/components/cards/AlbumCard.vue +20 -14
- package/src/modules/music/components/cards/ArtistCard.vue +1 -1
- package/src/modules/music/components/cards/PlaylistCard.vue +31 -11
- package/src/modules/music/components/cards/TrackListCard.vue +24 -13
- package/src/modules/music/components/forms/PlaylistForm.vue +417 -107
- package/src/modules/music/components/forms/SearchForm.vue +31 -8
- package/src/modules/music/components/forms/TrackForm.vue +50 -32
- package/src/modules/music/components/layouts/MusicBottomPlayer.vue +17 -0
- package/src/modules/music/components/pages/Album.vue +373 -186
- package/src/modules/music/components/pages/Artist.vue +54 -94
- package/src/modules/music/components/pages/MusicHome.vue +59 -56
- package/src/modules/music/components/pages/MusicLibrary.vue +13 -11
- package/src/modules/music/components/pages/Playlist.vue +495 -379
- package/src/modules/music/components/pages/SearchResults.vue +185 -313
- package/src/modules/music/components/pages/Track.vue +363 -69
- package/src/modules/music/components/player/MusicPlayer.vue +368 -97
- package/src/modules/music/components/player/TrackProgress.vue +76 -22
- package/src/modules/music/components/player/VolumeControl.vue +61 -28
- package/src/modules/music/controllers/search.controller.js +3 -0
- package/src/modules/music/controllers/stream.controller.js +11 -3
- package/src/modules/music/middlewares/playlists.verifier.js +1 -1
- package/src/modules/music/music.client.js +3 -6
- package/src/modules/music/music.server.js +8 -4
- package/src/modules/music/router/music.js +8 -1
- package/src/modules/music/routes/albums.routes.js +37 -5
- package/src/modules/music/routes/artists.routes.js +14 -4
- package/src/modules/music/routes/genres.routes.js +5 -1
- package/src/modules/music/routes/playlists.routes.js +42 -9
- package/src/modules/music/routes/tracks.routes.js +27 -2
- package/src/modules/music/store/artists.js +6 -2
- package/src/modules/music/store/player.js +6 -0
- package/src/modules/music/store/tracks.js +31 -0
- package/src/modules/music/websocket/streaming.handler.js +7 -1
- package/src/modules/rents/controllers/services/rents.services.js +2 -2
- package/src/modules/rents/views/components/pages/Gant/GanttBar.vue +4 -3
- package/src/modules/rents/views/components/pages/Gant/GanttChart.vue +42 -40
- package/src/modules/rents/views/components/pages/Gant/GanttToolbar.vue +3 -1
- package/src/modules/rents/views/components/pages/Rents.vue +60 -56
- package/dist/globals.websocket-DzvdIBf6.js +0 -306
- package/dist/globals.websocket-k6_B1T7k.cjs +0 -322
- package/dist/martyrs/src/components/Field/Field.vue2.cjs.map +0 -1
- package/dist/martyrs/src/components/Menu/Menu.vue.cjs.map +0 -1
- package/dist/martyrs/src/components/Menu/Menu.vue.js.map +0 -1
- package/dist/martyrs/src/modules/music/components/cards/TrackCard.vue.cjs +0 -69
- package/dist/martyrs/src/modules/music/components/cards/TrackCard.vue.cjs.map +0 -1
- package/dist/martyrs/src/modules/music/components/cards/TrackCard.vue.js +0 -69
- package/dist/martyrs/src/modules/music/components/cards/TrackCard.vue.js.map +0 -1
- package/dist/martyrs/src/modules/music/components/layouts/MusicLayout.vue.cjs +0 -104
- package/dist/martyrs/src/modules/music/components/layouts/MusicLayout.vue.cjs.map +0 -1
- package/dist/martyrs/src/modules/music/components/layouts/MusicLayout.vue.js +0 -104
- package/dist/martyrs/src/modules/music/components/layouts/MusicLayout.vue.js.map +0 -1
- package/src/modules/music/components/cards/TrackCard.vue +0 -86
- package/src/modules/music/components/layouts/MusicLayout.vue +0 -83
|
@@ -1,167 +1,427 @@
|
|
|
1
|
-
import { reactive, createElementBlock, openBlock, createElementVNode, withModifiers, createVNode,
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import _sfc_main$
|
|
5
|
-
import _sfc_main$
|
|
6
|
-
import
|
|
7
|
-
import _sfc_main$
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
import { reactive, ref, watch, computed, onMounted, createElementBlock, openBlock, createElementVNode, toDisplayString, withModifiers, createVNode, withCtx, createCommentVNode, createTextVNode } from "vue";
|
|
2
|
+
import { useRouter, useRoute } from "vue-router";
|
|
3
|
+
import Field from "../../../../components/Field/Field.vue.js";
|
|
4
|
+
import _sfc_main$2 from "../../../../components/Block/Block.vue.js";
|
|
5
|
+
import _sfc_main$5 from "../../../../components/Button/Button.vue.js";
|
|
6
|
+
import _sfc_main$4 from "../../../../components/Radio/Radio.vue.js";
|
|
7
|
+
import _sfc_main$1 from "../../../../components/UploadImage/UploadImage.vue.js";
|
|
8
|
+
import _sfc_main$3 from "../../../icons/navigation/IconCross.vue.js";
|
|
9
|
+
import BlockMultiselect from "../../../globals/views/components/blocks/BlockMultiselect.vue.js";
|
|
10
|
+
import { actions as actions$1 } from "../../store/playlists.js";
|
|
11
|
+
import { state, actions } from "../../store/tracks.js";
|
|
12
|
+
import { actions as actions$2 } from "../../../globals/views/store/globals.js";
|
|
13
|
+
import { state as state$1 } from "../../../auth/views/store/auth.js";
|
|
14
|
+
const _hoisted_1 = { class: "pd-medium" };
|
|
15
|
+
const _hoisted_2 = { class: "h2 mn-b-medium" };
|
|
16
|
+
const _hoisted_3 = { class: "bg-light pd-medium radius-medium" };
|
|
17
|
+
const _hoisted_4 = { class: "mn-b-medium" };
|
|
18
|
+
const _hoisted_5 = { class: "flex-nowrap flex-v-center flex gap-thin" };
|
|
19
|
+
const _hoisted_6 = ["onClick", "disabled"];
|
|
20
|
+
const _hoisted_7 = ["onClick", "disabled"];
|
|
21
|
+
const _hoisted_8 = { class: "flex-1" };
|
|
22
|
+
const _hoisted_9 = { class: "t-medium" };
|
|
23
|
+
const _hoisted_10 = { class: "t-small t-transp" };
|
|
24
|
+
const _hoisted_11 = { key: 0 };
|
|
25
|
+
const _hoisted_12 = {
|
|
26
|
+
key: 2,
|
|
27
|
+
class: "t-small t-transp"
|
|
21
28
|
};
|
|
22
|
-
const
|
|
29
|
+
const _hoisted_13 = ["onClick"];
|
|
30
|
+
const _hoisted_14 = { class: "flex-nowrap flex-v-center flex" };
|
|
31
|
+
const _hoisted_15 = { class: "w-100" };
|
|
32
|
+
const _hoisted_16 = { class: "t-medium" };
|
|
33
|
+
const _hoisted_17 = { class: "t-small t-transp" };
|
|
34
|
+
const _hoisted_18 = { key: 0 };
|
|
35
|
+
const _hoisted_19 = {
|
|
36
|
+
key: 0,
|
|
37
|
+
class: "t-small t-transp mn-l-small"
|
|
38
|
+
};
|
|
39
|
+
const _hoisted_20 = {
|
|
40
|
+
key: 0,
|
|
41
|
+
class: "t-small t-transp mn-t-small"
|
|
42
|
+
};
|
|
43
|
+
const _hoisted_21 = { class: "bg-light pd-medium radius-medium" };
|
|
44
|
+
const _hoisted_22 = { class: "mn-b-medium" };
|
|
45
|
+
const _hoisted_23 = { class: "flex gap-medium" };
|
|
46
|
+
const _hoisted_24 = { class: "mn-b-medium" };
|
|
47
|
+
const _hoisted_25 = { class: "flex gap-medium" };
|
|
48
|
+
const _hoisted_26 = { class: "flex flex-justify-between" };
|
|
23
49
|
const _sfc_main = {
|
|
24
50
|
__name: "PlaylistForm",
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
51
|
+
props: {
|
|
52
|
+
editMode: {
|
|
53
|
+
type: Boolean,
|
|
54
|
+
default: false
|
|
55
|
+
},
|
|
56
|
+
url: {
|
|
57
|
+
type: String,
|
|
58
|
+
default: ""
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
setup(__props) {
|
|
62
|
+
const props = __props;
|
|
63
|
+
const router = useRouter();
|
|
64
|
+
useRoute();
|
|
65
|
+
const playlist = reactive({
|
|
29
66
|
title: "",
|
|
30
67
|
description: "",
|
|
31
|
-
isPublic: true,
|
|
32
68
|
coverUrl: "",
|
|
33
|
-
|
|
34
|
-
|
|
69
|
+
tracks: [],
|
|
70
|
+
url: "",
|
|
71
|
+
isPublic: true,
|
|
72
|
+
isCollaborative: false
|
|
73
|
+
});
|
|
74
|
+
const validation = reactive({
|
|
75
|
+
title: false,
|
|
76
|
+
description: false
|
|
77
|
+
});
|
|
78
|
+
const urlManuallySet = ref(false);
|
|
79
|
+
const generateSlug = (text) => {
|
|
80
|
+
if (!text) return "";
|
|
81
|
+
return text.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim("-");
|
|
82
|
+
};
|
|
83
|
+
watch(() => playlist.title, (newTitle) => {
|
|
84
|
+
if (!urlManuallySet.value && !props.editMode) {
|
|
85
|
+
playlist.url = generateSlug(newTitle);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
watch(() => playlist.url, (newUrl, oldUrl) => {
|
|
89
|
+
if (newUrl !== generateSlug(playlist.title)) {
|
|
90
|
+
urlManuallySet.value = true;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
const totalDuration = computed(() => {
|
|
94
|
+
return playlist.tracks.reduce((sum, track) => sum + (track.duration || 0), 0);
|
|
35
95
|
});
|
|
36
|
-
const
|
|
96
|
+
const formatDuration = (seconds) => {
|
|
97
|
+
if (!seconds) return "0:00";
|
|
98
|
+
const hours = Math.floor(seconds / 3600);
|
|
99
|
+
const minutes = Math.floor(seconds % 3600 / 60);
|
|
100
|
+
const secs = seconds % 60;
|
|
101
|
+
if (hours > 0) {
|
|
102
|
+
return `${hours}:${minutes.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
|
|
103
|
+
}
|
|
104
|
+
return `${minutes}:${secs.toString().padStart(2, "0")}`;
|
|
105
|
+
};
|
|
106
|
+
const moveTrack = (index, direction) => {
|
|
107
|
+
const newIndex = direction === "up" ? index - 1 : index + 1;
|
|
108
|
+
if (newIndex < 0 || newIndex >= playlist.tracks.length) return;
|
|
109
|
+
const tracks = [...playlist.tracks];
|
|
110
|
+
[tracks[index], tracks[newIndex]] = [tracks[newIndex], tracks[index]];
|
|
111
|
+
playlist.tracks = tracks;
|
|
112
|
+
};
|
|
113
|
+
const fetchPlaylist = async () => {
|
|
114
|
+
if (!props.url) return;
|
|
115
|
+
try {
|
|
116
|
+
const fetchedPlaylist = await actions$1.fetchPlaylistByUrl(props.url);
|
|
117
|
+
if (!fetchedPlaylist) {
|
|
118
|
+
actions$2.setError({
|
|
119
|
+
message: "Playlist not found"
|
|
120
|
+
});
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
Object.assign(playlist, {
|
|
124
|
+
title: fetchedPlaylist.title || "",
|
|
125
|
+
description: fetchedPlaylist.description || "",
|
|
126
|
+
coverUrl: fetchedPlaylist.coverUrl || "",
|
|
127
|
+
tracks: fetchedPlaylist.tracks || [],
|
|
128
|
+
url: fetchedPlaylist.url || "",
|
|
129
|
+
isPublic: fetchedPlaylist.isPublic !== false,
|
|
130
|
+
isCollaborative: fetchedPlaylist.isCollaborative || false,
|
|
131
|
+
_id: fetchedPlaylist._id
|
|
132
|
+
});
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error("Error fetching playlist:", error);
|
|
135
|
+
actions$2.setError({
|
|
136
|
+
message: "Failed to load playlist details"
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
const validateForm = () => {
|
|
141
|
+
let isValid = true;
|
|
142
|
+
if (!playlist.title.trim()) {
|
|
143
|
+
validation.title = {
|
|
144
|
+
message: "Playlist title is required"
|
|
145
|
+
};
|
|
146
|
+
isValid = false;
|
|
147
|
+
} else {
|
|
148
|
+
validation.title = false;
|
|
149
|
+
}
|
|
150
|
+
if (playlist.description && playlist.description.length > 2e3) {
|
|
151
|
+
validation.description = {
|
|
152
|
+
message: "Description is too long (max 2000 characters)"
|
|
153
|
+
};
|
|
154
|
+
isValid = false;
|
|
155
|
+
} else {
|
|
156
|
+
validation.description = false;
|
|
157
|
+
}
|
|
158
|
+
return isValid;
|
|
159
|
+
};
|
|
37
160
|
const submitForm = async () => {
|
|
38
|
-
|
|
39
|
-
if (Object.values(validationErrors).some((error) => error !== null)) {
|
|
161
|
+
if (!validateForm()) {
|
|
40
162
|
return;
|
|
41
163
|
}
|
|
42
|
-
const playlistData = {
|
|
43
|
-
...form,
|
|
44
|
-
creator: {
|
|
45
|
-
type: "User",
|
|
46
|
-
target: state.user._id
|
|
47
|
-
},
|
|
48
|
-
owner: {
|
|
49
|
-
type: "User",
|
|
50
|
-
target: state.user._id
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
164
|
try {
|
|
54
|
-
const
|
|
55
|
-
|
|
165
|
+
const formData = {
|
|
166
|
+
...playlist,
|
|
167
|
+
tracks: playlist.tracks.map((track) => ({
|
|
168
|
+
track: track._id || track,
|
|
169
|
+
addedAt: /* @__PURE__ */ new Date()
|
|
170
|
+
}))
|
|
171
|
+
};
|
|
172
|
+
if (!props.editMode) {
|
|
173
|
+
formData.creator = {
|
|
174
|
+
type: "user",
|
|
175
|
+
target: state$1.user._id
|
|
176
|
+
};
|
|
177
|
+
formData.owner = {
|
|
178
|
+
type: "user",
|
|
179
|
+
target: state$1.user._id
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
let result;
|
|
183
|
+
if (props.editMode) {
|
|
184
|
+
result = await actions$1.updatePlaylist(formData);
|
|
185
|
+
} else {
|
|
186
|
+
result = await actions$1.createPlaylist(formData);
|
|
187
|
+
}
|
|
188
|
+
setTimeout(() => {
|
|
189
|
+
router.push({
|
|
190
|
+
name: "playlist",
|
|
191
|
+
params: { url: result.url }
|
|
192
|
+
});
|
|
193
|
+
}, 1e3);
|
|
56
194
|
} catch (error) {
|
|
57
|
-
console.error("Error
|
|
195
|
+
console.error("Error saving playlist:", error);
|
|
196
|
+
actions$2.setError({
|
|
197
|
+
message: "Failed to save playlist"
|
|
198
|
+
});
|
|
58
199
|
}
|
|
59
200
|
};
|
|
201
|
+
const handleUploadError = (error) => {
|
|
202
|
+
console.error("Upload error:", error);
|
|
203
|
+
actions$2.setError({
|
|
204
|
+
message: "Error uploading image"
|
|
205
|
+
});
|
|
206
|
+
};
|
|
207
|
+
onMounted(async () => {
|
|
208
|
+
if (props.editMode) {
|
|
209
|
+
await fetchPlaylist();
|
|
210
|
+
urlManuallySet.value = true;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
60
213
|
return (_ctx, _cache) => {
|
|
61
214
|
return openBlock(), createElementBlock("div", _hoisted_1, [
|
|
215
|
+
createElementVNode("h2", _hoisted_2, toDisplayString(__props.editMode ? "Edit Playlist" : "Create Playlist"), 1),
|
|
62
216
|
createElementVNode("form", {
|
|
63
|
-
onSubmit: withModifiers(submitForm, ["prevent"])
|
|
217
|
+
onSubmit: withModifiers(submitForm, ["prevent"]),
|
|
218
|
+
class: "cols-1 gap-medium"
|
|
64
219
|
}, [
|
|
65
|
-
createElementVNode("div", _hoisted_2, [
|
|
66
|
-
_cache[6] || (_cache[6] = createElementVNode("label", {
|
|
67
|
-
for: "title",
|
|
68
|
-
class: "t-medium mn-b-thin d-block"
|
|
69
|
-
}, "Playlist Name", -1)),
|
|
70
|
-
createVNode(Field, {
|
|
71
|
-
field: form.title,
|
|
72
|
-
"onUpdate:field": _cache[0] || (_cache[0] = ($event) => form.title = $event),
|
|
73
|
-
id: "title",
|
|
74
|
-
type: "text",
|
|
75
|
-
placeholder: "New Playlist",
|
|
76
|
-
validation: validationErrors.title,
|
|
77
|
-
class: "w-100 pd-small bg-dark-transp-25 radius-small"
|
|
78
|
-
}, null, 8, ["field", "validation"])
|
|
79
|
-
]),
|
|
80
220
|
createElementVNode("div", _hoisted_3, [
|
|
81
|
-
_cache[
|
|
82
|
-
|
|
83
|
-
class: "
|
|
84
|
-
|
|
221
|
+
_cache[11] || (_cache[11] = createElementVNode("h3", { class: "h3 mn-b-medium" }, "Basic Information", -1)),
|
|
222
|
+
createElementVNode("div", _hoisted_4, [
|
|
223
|
+
_cache[10] || (_cache[10] = createElementVNode("p", { class: "p-semi mn-b-small" }, "Playlist Cover", -1)),
|
|
224
|
+
createVNode(_sfc_main$1, {
|
|
225
|
+
photo: playlist.coverUrl,
|
|
226
|
+
"onUpdate:photo": _cache[0] || (_cache[0] = ($event) => playlist.coverUrl = $event),
|
|
227
|
+
uploadPath: "playlists/covers",
|
|
228
|
+
class: "w-100 h-15r radius-small o-hidden mn-b-small",
|
|
229
|
+
onError: handleUploadError
|
|
230
|
+
}, null, 8, ["photo"])
|
|
231
|
+
]),
|
|
85
232
|
createVNode(Field, {
|
|
86
|
-
field:
|
|
87
|
-
"onUpdate:field": _cache[1] || (_cache[1] = ($event) =>
|
|
88
|
-
|
|
233
|
+
field: playlist.title,
|
|
234
|
+
"onUpdate:field": _cache[1] || (_cache[1] = ($event) => playlist.title = $event),
|
|
235
|
+
label: "Title",
|
|
236
|
+
placeholder: "Enter playlist title",
|
|
237
|
+
class: "bg-white radius-small pd-small mn-b-thin",
|
|
238
|
+
validation: validation.title
|
|
239
|
+
}, null, 8, ["field", "validation"]),
|
|
240
|
+
createVNode(Field, {
|
|
241
|
+
field: playlist.url,
|
|
242
|
+
"onUpdate:field": _cache[2] || (_cache[2] = ($event) => playlist.url = $event),
|
|
243
|
+
label: "URL",
|
|
244
|
+
placeholder: "Leave blank for auto-generation based on the playlist title",
|
|
245
|
+
class: "bg-white radius-small pd-small mn-b-small"
|
|
246
|
+
}, null, 8, ["field"]),
|
|
247
|
+
createVNode(Field, {
|
|
248
|
+
field: playlist.description,
|
|
249
|
+
"onUpdate:field": _cache[3] || (_cache[3] = ($event) => playlist.description = $event),
|
|
250
|
+
label: "Description",
|
|
89
251
|
type: "textarea",
|
|
90
|
-
placeholder: "
|
|
91
|
-
|
|
92
|
-
|
|
252
|
+
placeholder: "Enter playlist description",
|
|
253
|
+
class: "bg-white radius-small pd-small mn-b-thin",
|
|
254
|
+
validation: validation.description
|
|
93
255
|
}, null, 8, ["field", "validation"])
|
|
94
256
|
]),
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
257
|
+
createVNode(_sfc_main$2, { title: "Tracks" }, {
|
|
258
|
+
default: withCtx(() => [
|
|
259
|
+
createVNode(BlockMultiselect, {
|
|
260
|
+
modelValue: playlist.tracks,
|
|
261
|
+
"onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => playlist.tracks = $event),
|
|
262
|
+
placeholder: "Search tracks...",
|
|
263
|
+
multiple: true,
|
|
264
|
+
transform: (item) => ({
|
|
265
|
+
_id: item._id,
|
|
266
|
+
title: item.title,
|
|
267
|
+
artists: item.artists,
|
|
268
|
+
album: item.album,
|
|
269
|
+
duration: item.duration
|
|
270
|
+
}),
|
|
271
|
+
store: {
|
|
272
|
+
read: (options) => actions.fetchTracks(options),
|
|
273
|
+
state
|
|
274
|
+
},
|
|
275
|
+
options: {
|
|
276
|
+
rootOnly: false,
|
|
277
|
+
excludeChildren: false,
|
|
278
|
+
limit: 50
|
|
279
|
+
},
|
|
280
|
+
skeleton: {
|
|
281
|
+
hide: false,
|
|
282
|
+
horizontal: true,
|
|
283
|
+
class: "radius-small",
|
|
284
|
+
structure: [{
|
|
285
|
+
block: "text",
|
|
286
|
+
size: "large"
|
|
287
|
+
}]
|
|
288
|
+
},
|
|
289
|
+
states: {
|
|
290
|
+
empty: {
|
|
291
|
+
title: "No tracks found",
|
|
292
|
+
description: "Try different search terms",
|
|
293
|
+
class: "radius-small"
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
key: "_id",
|
|
297
|
+
label: (item) => item.title,
|
|
298
|
+
classSearch: "bg-white radius-small",
|
|
299
|
+
classSelected: "bg-white pd-small radius-small",
|
|
300
|
+
classDropdown: "bg-white pd-small radius-medium bs-small",
|
|
301
|
+
classItem: "pd-small radius-small hover-bg-light cursor-pointer",
|
|
302
|
+
classFeed: "h-max-30r gap-thin flex-column flex o-scroll"
|
|
303
|
+
}, {
|
|
304
|
+
selected: withCtx(({ item, clear, index }) => [
|
|
305
|
+
createElementVNode("div", _hoisted_5, [
|
|
306
|
+
playlist.tracks.length > 1 ? (openBlock(), createElementBlock("button", {
|
|
307
|
+
key: 0,
|
|
308
|
+
onClick: withModifiers(($event) => moveTrack(index, "up"), ["stop"]),
|
|
309
|
+
disabled: index === 0,
|
|
310
|
+
class: "i-small pd-micro bg-grey-nano radius-extra flex-center flex aspect-1x1 hover-scale-1"
|
|
311
|
+
}, [
|
|
312
|
+
createVNode(_sfc_main$3, { class: "i-micro" })
|
|
313
|
+
], 8, _hoisted_6)) : createCommentVNode("", true),
|
|
314
|
+
playlist.tracks.length > 1 ? (openBlock(), createElementBlock("button", {
|
|
315
|
+
key: 1,
|
|
316
|
+
onClick: withModifiers(($event) => moveTrack(index, "down"), ["stop"]),
|
|
317
|
+
disabled: index === playlist.tracks.length - 1,
|
|
318
|
+
class: "i-small pd-micro bg-grey-nano radius-extra flex-center flex aspect-1x1 hover-scale-1"
|
|
319
|
+
}, [
|
|
320
|
+
createVNode(_sfc_main$3, { class: "i-micro" })
|
|
321
|
+
], 8, _hoisted_7)) : createCommentVNode("", true),
|
|
322
|
+
createElementVNode("div", _hoisted_8, [
|
|
323
|
+
createElementVNode("p", _hoisted_9, toDisplayString(item.title), 1),
|
|
324
|
+
createElementVNode("p", _hoisted_10, [
|
|
325
|
+
createTextVNode(toDisplayString(item.artists?.map((a) => a.name || a).join(", ")) + " ", 1),
|
|
326
|
+
item.album ? (openBlock(), createElementBlock("span", _hoisted_11, " • " + toDisplayString(item.album.title || item.album), 1)) : createCommentVNode("", true)
|
|
327
|
+
])
|
|
328
|
+
]),
|
|
329
|
+
item.duration ? (openBlock(), createElementBlock("span", _hoisted_12, toDisplayString(formatDuration(item.duration)), 1)) : createCommentVNode("", true),
|
|
330
|
+
createElementVNode("button", {
|
|
331
|
+
onClick: withModifiers(clear, ["stop"]),
|
|
332
|
+
class: "i-small pd-micro bg-red radius-extra flex-center flex aspect-1x1 hover-scale-1"
|
|
333
|
+
}, [
|
|
334
|
+
createVNode(_sfc_main$3, { class: "i-micro fill-white" })
|
|
335
|
+
], 8, _hoisted_13)
|
|
336
|
+
])
|
|
337
|
+
]),
|
|
338
|
+
item: withCtx(({ item }) => [
|
|
339
|
+
createElementVNode("div", _hoisted_14, [
|
|
340
|
+
createElementVNode("div", _hoisted_15, [
|
|
341
|
+
createElementVNode("p", _hoisted_16, toDisplayString(item.title), 1),
|
|
342
|
+
createElementVNode("p", _hoisted_17, [
|
|
343
|
+
createTextVNode(toDisplayString(item.artists?.map((a) => a.name || a).join(", ")) + " ", 1),
|
|
344
|
+
item.album ? (openBlock(), createElementBlock("span", _hoisted_18, " • " + toDisplayString(item.album.title || item.album), 1)) : createCommentVNode("", true)
|
|
345
|
+
])
|
|
346
|
+
]),
|
|
347
|
+
item.duration ? (openBlock(), createElementBlock("span", _hoisted_19, toDisplayString(formatDuration(item.duration)), 1)) : createCommentVNode("", true)
|
|
348
|
+
])
|
|
349
|
+
]),
|
|
350
|
+
_: 1
|
|
351
|
+
}, 8, ["modelValue", "transform", "store", "label"]),
|
|
352
|
+
playlist.tracks.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_20, toDisplayString(playlist.tracks.length) + " tracks • " + toDisplayString(formatDuration(totalDuration.value)), 1)) : createCommentVNode("", true)
|
|
353
|
+
]),
|
|
354
|
+
_: 1
|
|
355
|
+
}),
|
|
356
|
+
createElementVNode("div", _hoisted_21, [
|
|
357
|
+
_cache[14] || (_cache[14] = createElementVNode("h3", { class: "h3 mn-b-medium" }, "Privacy & Settings", -1)),
|
|
358
|
+
createElementVNode("div", _hoisted_22, [
|
|
359
|
+
_cache[12] || (_cache[12] = createElementVNode("p", { class: "p-semi mn-b-small" }, "Privacy", -1)),
|
|
360
|
+
createElementVNode("div", _hoisted_23, [
|
|
361
|
+
createVNode(_sfc_main$4, {
|
|
362
|
+
radio: playlist.isPublic,
|
|
363
|
+
"onUpdate:radio": _cache[5] || (_cache[5] = ($event) => playlist.isPublic = $event),
|
|
364
|
+
value: true,
|
|
365
|
+
name: "privacy",
|
|
366
|
+
label: "Public",
|
|
367
|
+
class: "bg-white pd-small radius-small"
|
|
368
|
+
}, null, 8, ["radio"]),
|
|
369
|
+
createVNode(_sfc_main$4, {
|
|
370
|
+
radio: playlist.isPublic,
|
|
371
|
+
"onUpdate:radio": _cache[6] || (_cache[6] = ($event) => playlist.isPublic = $event),
|
|
372
|
+
value: false,
|
|
373
|
+
name: "privacy",
|
|
374
|
+
label: "Private",
|
|
375
|
+
class: "bg-white pd-small radius-small"
|
|
376
|
+
}, null, 8, ["radio"])
|
|
377
|
+
])
|
|
378
|
+
]),
|
|
379
|
+
createElementVNode("div", _hoisted_24, [
|
|
380
|
+
_cache[13] || (_cache[13] = createElementVNode("p", { class: "p-semi mn-b-small" }, "Collaborative Playlist", -1)),
|
|
381
|
+
createElementVNode("div", _hoisted_25, [
|
|
382
|
+
createVNode(_sfc_main$4, {
|
|
383
|
+
radio: playlist.isCollaborative,
|
|
384
|
+
"onUpdate:radio": _cache[7] || (_cache[7] = ($event) => playlist.isCollaborative = $event),
|
|
385
|
+
value: true,
|
|
386
|
+
name: "collaborative",
|
|
387
|
+
label: "Yes",
|
|
388
|
+
class: "bg-white pd-small radius-small"
|
|
389
|
+
}, null, 8, ["radio"]),
|
|
390
|
+
createVNode(_sfc_main$4, {
|
|
391
|
+
radio: playlist.isCollaborative,
|
|
392
|
+
"onUpdate:radio": _cache[8] || (_cache[8] = ($event) => playlist.isCollaborative = $event),
|
|
393
|
+
value: false,
|
|
394
|
+
name: "collaborative",
|
|
395
|
+
label: "No",
|
|
396
|
+
class: "bg-white pd-small radius-small"
|
|
397
|
+
}, null, 8, ["radio"])
|
|
398
|
+
])
|
|
137
399
|
])
|
|
138
400
|
]),
|
|
139
|
-
createElementVNode("div",
|
|
140
|
-
createVNode(_sfc_main$
|
|
141
|
-
onClick: _cache[
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
showLoader: false
|
|
145
|
-
showSucces: false
|
|
401
|
+
createElementVNode("div", _hoisted_26, [
|
|
402
|
+
createVNode(_sfc_main$5, {
|
|
403
|
+
onClick: _cache[9] || (_cache[9] = ($event) => _ctx.$router.go(-1)),
|
|
404
|
+
class: "bg-grey-nano t-black",
|
|
405
|
+
showSucces: false,
|
|
406
|
+
showLoader: false
|
|
146
407
|
}, {
|
|
147
|
-
default: withCtx(() => _cache[
|
|
408
|
+
default: withCtx(() => _cache[15] || (_cache[15] = [
|
|
148
409
|
createTextVNode(" Cancel ")
|
|
149
410
|
])),
|
|
150
411
|
_: 1
|
|
151
412
|
}),
|
|
152
|
-
createVNode(_sfc_main$
|
|
153
|
-
type: "submit",
|
|
154
|
-
class: "bg-main pd-small radius-small hover-scale-1",
|
|
413
|
+
createVNode(_sfc_main$5, {
|
|
155
414
|
submit: submitForm,
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
415
|
+
class: "bg-main t-black",
|
|
416
|
+
text: {
|
|
417
|
+
success: __props.editMode ? "Updated!" : "Created!"
|
|
418
|
+
}
|
|
159
419
|
}, {
|
|
160
|
-
default: withCtx(() =>
|
|
161
|
-
createTextVNode(" Create Playlist
|
|
162
|
-
])
|
|
420
|
+
default: withCtx(() => [
|
|
421
|
+
createTextVNode(toDisplayString(__props.editMode ? "Update Playlist" : "Create Playlist"), 1)
|
|
422
|
+
]),
|
|
163
423
|
_: 1
|
|
164
|
-
}, 8, ["
|
|
424
|
+
}, 8, ["text"])
|
|
165
425
|
])
|
|
166
426
|
], 32)
|
|
167
427
|
]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlaylistForm.vue.js","sources":["../../../../../../../src/modules/music/components/forms/PlaylistForm.vue"],"sourcesContent":["<!-- components/forms/PlaylistForm.vue -->\n<template>\n <div class=\"playlist-form\">\n <form @submit.prevent=\"submitForm\">\n <div class=\"form-group mn-b-medium\">\n <label for=\"title\" class=\" t-medium mn-b-thin d-block\">Playlist Name</label>\n <Field \n v-model:field=\"form.title\"\n id=\"title\"\n type=\"text\"\n placeholder=\"New Playlist\"\n :validation=\"validationErrors.title\"\n class=\"w-100 pd-small bg-dark-transp-25 radius-small \"\n />\n </div>\n \n <div class=\"form-group mn-b-medium\">\n <label for=\"description\" class=\" t-medium mn-b-thin d-block\">Description</label>\n <Field \n v-model:field=\"form.description\"\n id=\"description\"\n type=\"textarea\"\n placeholder=\"Add an optional description\"\n :validation=\"validationErrors.description\"\n class=\"w-100 pd-small bg-dark-transp-25 radius-small \"\n />\n </div>\n \n <div class=\"form-group mn-b-medium\">\n <label class=\" t-medium mn-b-thin d-block\">Privacy</label>\n <div class=\"flex gap-small\">\n <Radio \n v-model:radio=\"form.isPublic\"\n :value=\"true\"\n name=\"privacy\"\n label=\"Public\"\n class=\"\"\n />\n <Radio \n v-model:radio=\"form.isPublic\"\n :value=\"false\"\n name=\"privacy\"\n label=\"Private\"\n class=\"\"\n />\n </div>\n </div>\n \n <div class=\"form-group mn-b-medium\">\n <label class=\" t-medium mn-b-thin d-block\">Cover Image</label>\n <div class=\"playlist-cover-upload flex gap-medium\">\n <div class=\"playlist-cover-preview bg-dark-transp-25 radius-small o-hidden\">\n <Media \n v-if=\"form.coverUrl\"\n :url=\"form.coverUrl\"\n class=\"w-10r h-10r object-fit-cover\"\n />\n <div v-else class=\"w-10r h-10r flex-center flex\">\n <IconMusic class=\"i-big\" fill=\"rgb(var(--grey))\"/>\n </div>\n </div>\n \n <UploadImage\n v-model:photo=\"form.coverUrl\"\n uploadPath=\"playlists\"\n class=\"flex-1 h-10r bg-dark-transp-25 radius-small\"\n />\n </div>\n </div>\n \n <div class=\"form-actions t-right\">\n <Button \n @click=\"$emit('cancel')\"\n type=\"button\"\n class=\"bg-dark-transp-25 pd-small radius-small mn-r-small hover-bg-dark\"\n :showLoader=\"false\" \n :showSucces=\"false\"\n >\n Cancel\n </Button>\n \n <Button \n type=\"submit\"\n class=\"bg-main pd-small radius-small hover-scale-1\"\n :submit=\"submitForm\"\n :showLoader=\"true\" \n :showSucces=\"true\"\n :validation=\"!!Object.keys(validationErrors).length\"\n >\n Create Playlist\n </Button>\n </div>\n </form>\n </div>\n</template>\n\n<script setup>\nimport { ref, reactive } from 'vue';\nimport Field from '@martyrs/src/components/Field/Field.vue';\nimport Radio from '@martyrs/src/components/Radio/Radio.vue';\nimport Button from '@martyrs/src/components/Button/Button.vue';\nimport UploadImage from '@martyrs/src/components/UploadImage/UploadImage.vue';\nimport Media from '@martyrs/src/components/Media/Media.vue';\nimport IconMusic from '@martyrs/src/modules/icons/entities/IconMusic.vue';\n\n// Import auth store and playlists store\nimport { state as authState } from '@martyrs/src/modules/auth/views/store/auth.js';\nimport { actions as playlistsActions } from '../../store/playlists.js';\n\nconst emit = defineEmits(['created', 'cancel']);\n\n// Form data\nconst form = reactive({\n title: '',\n description: '',\n isPublic: true,\n coverUrl: '',\n isCollaborative: false,\n tracks: []\n});\n\n// Validation\nconst validationErrors = reactive({});\n\n// Form submission\nconst submitForm = async () => {\n // Validate form\n validationErrors.title = !form.title ? { message: 'Playlist name is required' } : null;\n \n // If there are validation errors, don't submit\n if (Object.values(validationErrors).some(error => error !== null)) {\n return;\n }\n \n // Prepare playlist data\n const playlistData = {\n ...form,\n creator: {\n type: 'User',\n target: authState.user._id\n },\n owner: {\n type: 'User',\n target: authState.user._id\n }\n };\n \n try {\n const playlist = await playlistsActions.createPlaylist(playlistData);\n emit('created', playlist);\n } catch (error) {\n console.error('Error creating playlist:', error);\n // Handle error (could add form-level error message)\n }\n};\n</script>"],"names":["authState","playlistsActions"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AA6GA,UAAM,OAAO;AAGb,UAAM,OAAO,SAAS;AAAA,MACpB,OAAO;AAAA,MACP,aAAa;AAAA,MACb,UAAU;AAAA,MACV,UAAU;AAAA,MACV,iBAAiB;AAAA,MACjB,QAAQ,CAAA;AAAA,IACV,CAAC;AAGD,UAAM,mBAAmB,SAAS,EAAE;AAGpC,UAAM,aAAa,YAAY;AAE7B,uBAAiB,QAAQ,CAAC,KAAK,QAAQ,EAAE,SAAS,4BAA2B,IAAK;AAGlF,UAAI,OAAO,OAAO,gBAAgB,EAAE,KAAK,WAAS,UAAU,IAAI,GAAG;AACjE;AAAA,MACF;AAGA,YAAM,eAAe;AAAA,QACnB,GAAG;AAAA,QACH,SAAS;AAAA,UACP,MAAM;AAAA,UACN,QAAQA,MAAU,KAAK;AAAA,QAC7B;AAAA,QACI,OAAO;AAAA,UACL,MAAM;AAAA,UACN,QAAQA,MAAU,KAAK;AAAA,QAC7B;AAAA,MACA;AAEE,UAAI;AACF,cAAM,WAAW,MAAMC,QAAiB,eAAe,YAAY;AACnE,aAAK,WAAW,QAAQ;AAAA,MAC1B,SAAS,OAAO;AACd,gBAAQ,MAAM,4BAA4B,KAAK;AAAA,MAEjD;AAAA,IACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"PlaylistForm.vue.js","sources":["../../../../../../../src/modules/music/components/forms/PlaylistForm.vue"],"sourcesContent":["<template>\n <div class=\"pd-medium\">\n <h2 class=\"h2 mn-b-medium\">{{ editMode ? 'Edit Playlist' : 'Create Playlist' }}</h2>\n \n <form @submit.prevent=\"submitForm\" class=\"cols-1 gap-medium\">\n <!-- Basic Info Section -->\n <div class=\"bg-light pd-medium radius-medium\">\n <h3 class=\"h3 mn-b-medium\">Basic Information</h3>\n \n <!-- Playlist Cover -->\n <div class=\"mn-b-medium\">\n <p class=\"p-semi mn-b-small\">Playlist Cover</p>\n <UploadImage\n v-model:photo=\"playlist.coverUrl\"\n uploadPath=\"playlists/covers\"\n class=\"w-100 h-15r radius-small o-hidden mn-b-small\"\n @error=\"handleUploadError\"\n />\n </div>\n \n <!-- Title -->\n <Field\n v-model:field=\"playlist.title\"\n label=\"Title\"\n placeholder=\"Enter playlist title\"\n class=\"bg-white radius-small pd-small mn-b-thin\"\n :validation=\"validation.title\"\n />\n \n <!-- URL -->\n <Field\n v-model:field=\"playlist.url\"\n label=\"URL\"\n placeholder=\"Leave blank for auto-generation based on the playlist title\"\n class=\"bg-white radius-small pd-small mn-b-small\"\n />\n \n <!-- Description -->\n <Field\n v-model:field=\"playlist.description\"\n label=\"Description\"\n type=\"textarea\"\n placeholder=\"Enter playlist description\"\n class=\"bg-white radius-small pd-small mn-b-thin\"\n :validation=\"validation.description\"\n />\n </div>\n \n <!-- Tracks Section -->\n <Block title=\"Tracks\">\n <BlockMultiselect\n v-model=\"playlist.tracks\"\n placeholder=\"Search tracks...\"\n :multiple=\"true\"\n :transform=\"(item) => ({ \n _id: item._id, \n title: item.title,\n artists: item.artists,\n album: item.album,\n duration: item.duration \n })\"\n :store=\"{\n read: (options) => tracksStore.actions.fetchTracks(options),\n state: tracksStore.state\n }\"\n :options=\"{\n rootOnly: false,\n excludeChildren: false,\n limit: 50\n }\"\n :skeleton=\"{\n hide: false,\n horizontal: true,\n class: 'radius-small',\n structure: [{ \n block: 'text', size: 'large'\n }]\n }\"\n :states=\"{\n empty: {\n title: 'No tracks found',\n description: 'Try different search terms',\n class: 'radius-small'\n }\n }\"\n key=\"_id\"\n :label=\"item => item.title\"\n classSearch=\"bg-white radius-small\"\n classSelected=\"bg-white pd-small radius-small\"\n classDropdown=\"bg-white pd-small radius-medium bs-small\"\n classItem=\"pd-small radius-small hover-bg-light cursor-pointer\"\n classFeed=\"h-max-30r gap-thin flex-column flex o-scroll\"\n >\n <!-- Selected tracks with reorder support -->\n <template #selected=\"{ item, clear, index }\">\n <div class=\"flex-nowrap flex-v-center flex gap-thin\">\n <button \n v-if=\"playlist.tracks.length > 1\"\n @click.stop=\"moveTrack(index, 'up')\"\n :disabled=\"index === 0\"\n class=\"i-small pd-micro bg-grey-nano radius-extra flex-center flex aspect-1x1 hover-scale-1\"\n >\n <IconArrowUp class=\"i-micro\" />\n </button>\n \n <button \n v-if=\"playlist.tracks.length > 1\"\n @click.stop=\"moveTrack(index, 'down')\"\n :disabled=\"index === playlist.tracks.length - 1\"\n class=\"i-small pd-micro bg-grey-nano radius-extra flex-center flex aspect-1x1 hover-scale-1\"\n >\n <IconArrowDown class=\"i-micro\" />\n </button>\n \n <div class=\"flex-1\">\n <p class=\"t-medium\">{{ item.title }}</p>\n <p class=\"t-small t-transp\">\n {{ item.artists?.map(a => a.name || a).join(', ') }}\n <span v-if=\"item.album\"> • {{ item.album.title || item.album }}</span>\n </p>\n </div>\n \n <span v-if=\"item.duration\" class=\"t-small t-transp\">\n {{ formatDuration(item.duration) }}\n </span>\n \n <button \n @click.stop=\"clear\"\n class=\"i-small pd-micro bg-red radius-extra flex-center flex aspect-1x1 hover-scale-1\"\n >\n <IconCross class=\"i-micro fill-white\" />\n </button>\n </div>\n </template>\n \n <!-- Track items in dropdown -->\n <template #item=\"{ item }\">\n <div class=\"flex-nowrap flex-v-center flex\">\n <div class=\"w-100\">\n <p class=\"t-medium\">{{ item.title }}</p>\n <p class=\"t-small t-transp\">\n {{ item.artists?.map(a => a.name || a).join(', ') }}\n <span v-if=\"item.album\"> • {{ item.album.title || item.album }}</span>\n </p>\n </div>\n <span v-if=\"item.duration\" class=\"t-small t-transp mn-l-small\">\n {{ formatDuration(item.duration) }}\n </span>\n </div>\n </template>\n </BlockMultiselect>\n \n <!-- Tracks summary -->\n <div v-if=\"playlist.tracks.length > 0\" class=\"t-small t-transp mn-t-small\">\n {{ playlist.tracks.length }} tracks • {{ formatDuration(totalDuration) }}\n </div>\n </Block>\n \n <!-- Privacy & Settings Section -->\n <div class=\"bg-light pd-medium radius-medium\">\n <h3 class=\"h3 mn-b-medium\">Privacy & Settings</h3>\n \n <!-- Privacy -->\n <div class=\"mn-b-medium\">\n <p class=\"p-semi mn-b-small\">Privacy</p>\n <div class=\"flex gap-medium\">\n <Radio\n v-model:radio=\"playlist.isPublic\"\n :value=\"true\"\n name=\"privacy\"\n label=\"Public\"\n class=\"bg-white pd-small radius-small\"\n />\n <Radio\n v-model:radio=\"playlist.isPublic\"\n :value=\"false\"\n name=\"privacy\"\n label=\"Private\"\n class=\"bg-white pd-small radius-small\"\n />\n </div>\n </div>\n \n <!-- Collaborative -->\n <div class=\"mn-b-medium\">\n <p class=\"p-semi mn-b-small\">Collaborative Playlist</p>\n <div class=\"flex gap-medium\">\n <Radio\n v-model:radio=\"playlist.isCollaborative\"\n :value=\"true\"\n name=\"collaborative\"\n label=\"Yes\"\n class=\"bg-white pd-small radius-small\"\n />\n <Radio\n v-model:radio=\"playlist.isCollaborative\"\n :value=\"false\"\n name=\"collaborative\"\n label=\"No\"\n class=\"bg-white pd-small radius-small\"\n />\n </div>\n </div>\n </div>\n \n <!-- Submit Button -->\n <div class=\"flex flex-justify-between\">\n <Button\n @click=\"$router.go(-1)\"\n class=\"bg-grey-nano t-black\"\n :showSucces=\"false\"\n :showLoader=\"false\"\n >\n Cancel\n </Button>\n \n <Button\n :submit=\"submitForm\"\n class=\"bg-main t-black\"\n :text=\"{\n success: editMode ? 'Updated!' : 'Created!'\n }\"\n >\n {{ editMode ? 'Update Playlist' : 'Create Playlist' }}\n </Button>\n </div>\n </form>\n </div>\n</template>\n\n<script setup>\nimport { ref, reactive, onMounted, watch, computed } from 'vue';\nimport { useRouter, useRoute } from 'vue-router';\n\n// Import Martyrs components\nimport Field from '@martyrs/src/components/Field/Field.vue';\nimport Block from '@martyrs/src/components/Block/Block.vue';\nimport Button from '@martyrs/src/components/Button/Button.vue';\nimport Radio from '@martyrs/src/components/Radio/Radio.vue';\nimport UploadImage from '@martyrs/src/components/UploadImage/UploadImage.vue';\nimport IconCross from '@martyrs/src/modules/icons/navigation/IconCross.vue';\nimport IconArrowUp from '@martyrs/src/modules/icons/navigation/IconCross.vue';\nimport IconArrowDown from '@martyrs/src/modules/icons/navigation/IconCross.vue';\n\nimport BlockMultiselect from '@martyrs/src/modules/globals/views/components/blocks/BlockMultiselect.vue';\n\n// Import stores\nimport * as playlistsStore from '../../store/playlists';\nimport * as tracksStore from '../../store/tracks';\nimport * as globals from '@martyrs/src/modules/globals/views/store/globals.js';\nimport * as auth from '@martyrs/src/modules/auth/views/store/auth.js';\n\n// Props\nconst props = defineProps({\n editMode: {\n type: Boolean,\n default: false\n },\n url: {\n type: String,\n default: ''\n }\n});\n\n// Router and route\nconst router = useRouter();\nconst route = useRoute();\n\n// State\nconst playlist = reactive({\n title: '',\n description: '',\n coverUrl: '',\n tracks: [],\n url: '',\n isPublic: true,\n isCollaborative: false\n});\n\nconst validation = reactive({\n title: false,\n description: false\n});\n\n// Track if URL was manually entered\nconst urlManuallySet = ref(false);\n\n// Function to generate URL-friendly slug from text\nconst generateSlug = (text) => {\n if (!text) return '';\n return text\n .toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, '') // Remove special characters\n .replace(/\\s+/g, '-') // Replace spaces with hyphens\n .replace(/-+/g, '-') // Replace multiple hyphens with single\n .trim('-'); // Remove leading/trailing hyphens\n};\n\n// Watch for changes in playlist title to auto-generate URL\nwatch(() => playlist.title, (newTitle) => {\n // Only auto-generate if URL hasn't been manually set and we're not in edit mode\n if (!urlManuallySet.value && !props.editMode) {\n playlist.url = generateSlug(newTitle);\n }\n});\n\n// Watch for manual changes to URL field\nwatch(() => playlist.url, (newUrl, oldUrl) => {\n // If user manually changes URL, mark as manually set\n if (newUrl !== generateSlug(playlist.title)) {\n urlManuallySet.value = true;\n }\n});\n\n// Computed\nconst totalDuration = computed(() => {\n return playlist.tracks.reduce((sum, track) => sum + (track.duration || 0), 0);\n});\n\n// Methods\nconst formatDuration = (seconds) => {\n if (!seconds) return '0:00';\n const hours = Math.floor(seconds / 3600);\n const minutes = Math.floor((seconds % 3600) / 60);\n const secs = seconds % 60;\n \n if (hours > 0) {\n return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;\n }\n return `${minutes}:${secs.toString().padStart(2, '0')}`;\n};\n\nconst moveTrack = (index, direction) => {\n const newIndex = direction === 'up' ? index - 1 : index + 1;\n if (newIndex < 0 || newIndex >= playlist.tracks.length) return;\n \n const tracks = [...playlist.tracks];\n [tracks[index], tracks[newIndex]] = [tracks[newIndex], tracks[index]];\n playlist.tracks = tracks;\n};\n\nconst fetchPlaylist = async () => {\n if (!props.url) return;\n \n try {\n const fetchedPlaylist = await playlistsStore.actions.fetchPlaylistByUrl(props.url);\n \n if (!fetchedPlaylist) {\n globals.actions.setError({\n message: 'Playlist not found'\n });\n return;\n }\n \n // Update local playlist data\n Object.assign(playlist, {\n title: fetchedPlaylist.title || '',\n description: fetchedPlaylist.description || '',\n coverUrl: fetchedPlaylist.coverUrl || '',\n tracks: fetchedPlaylist.tracks || [],\n url: fetchedPlaylist.url || '',\n isPublic: fetchedPlaylist.isPublic !== false,\n isCollaborative: fetchedPlaylist.isCollaborative || false,\n _id: fetchedPlaylist._id\n });\n \n } catch (error) {\n console.error('Error fetching playlist:', error);\n globals.actions.setError({\n message: 'Failed to load playlist details'\n });\n }\n};\n\nconst validateForm = () => {\n let isValid = true;\n \n // Validate title\n if (!playlist.title.trim()) {\n validation.title = {\n message: 'Playlist title is required'\n };\n isValid = false;\n } else {\n validation.title = false;\n }\n \n // Validate description\n if (playlist.description && playlist.description.length > 2000) {\n validation.description = {\n message: 'Description is too long (max 2000 characters)'\n };\n isValid = false;\n } else {\n validation.description = false;\n }\n \n return isValid;\n};\n\nconst submitForm = async () => {\n if (!validateForm()) {\n return;\n }\n \n try {\n // Prepare data for submission\n const formData = {\n ...playlist,\n tracks: playlist.tracks.map(track => ({\n track: track._id || track,\n addedAt: new Date()\n }))\n };\n \n // Add ownership data if creating new playlist\n if (!props.editMode) {\n formData.creator = {\n type: 'user',\n target: auth.state.user._id\n };\n formData.owner = {\n type: 'user',\n target: auth.state.user._id\n };\n }\n \n let result;\n if (props.editMode) {\n result = await playlistsStore.actions.updatePlaylist(formData);\n } else {\n result = await playlistsStore.actions.createPlaylist(formData);\n }\n \n // Navigate to playlist detail page\n setTimeout(() => {\n router.push({\n name: 'playlist',\n params: { url: result.url }\n });\n }, 1000);\n \n } catch (error) {\n console.error('Error saving playlist:', error);\n globals.actions.setError({\n message: 'Failed to save playlist'\n });\n }\n};\n\nconst handleUploadError = (error) => {\n console.error('Upload error:', error);\n globals.actions.setError({\n message: 'Error uploading image'\n });\n};\n\n// Lifecycle hooks\nonMounted(async () => {\n if (props.editMode) {\n await fetchPlaylist();\n // Mark URL as manually set in edit mode to prevent auto-generation\n urlManuallySet.value = true;\n }\n});\n</script>"],"names":["playlistsStore.actions","globals.actions","auth.state"],"mappings":"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"}
|