@ozdao/martyrs 0.2.470 → 0.2.472
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/{Media-CR0V1zvB.js → Media-DW8RLbfM.js} +1 -1
- package/dist/{Media-C4Ges_Sd.mjs → Media-y_TX6us_.mjs} +1 -1
- package/dist/_virtual/index.cjs +1 -1
- package/dist/_virtual/index.js +1 -1
- package/dist/auth.server.js +1 -1
- package/dist/auth.server.mjs +1 -1
- package/dist/chats.server.js +1 -1
- package/dist/chats.server.mjs +1 -1
- package/dist/community.server.js +1 -1
- package/dist/community.server.mjs +1 -1
- package/dist/events.server.js +1 -1
- package/dist/events.server.mjs +1 -1
- package/dist/files.server.js +1 -1
- package/dist/files.server.mjs +1 -1
- package/dist/gallery.server.js +1 -1
- package/dist/gallery.server.mjs +1 -1
- package/dist/{index-DQqZReAr.js → index-CVXl1rB5.js} +0 -1
- package/dist/{index-DICZTQ-1.mjs → index-Df8vtZx7.mjs} +0 -1
- package/dist/{main-CsZAG5Wz.js → main-CCfQH-Dd.js} +2 -2
- package/dist/{main-CTcal9qN.mjs → main-CgmHzhq5.mjs} +74 -74
- package/dist/{node_modules/.pnpm/@vue_server-renderer@3.5.13_vue@3.5.13_typescript@5.8.3_ → martyrs}/node_modules/@vue/server-renderer/dist/server-renderer.esm-bundler.cjs +1 -1
- package/dist/martyrs/node_modules/@vue/server-renderer/dist/server-renderer.esm-bundler.cjs.map +1 -0
- package/dist/{node_modules/.pnpm/@vue_server-renderer@3.5.13_vue@3.5.13_typescript@5.8.3_ → martyrs}/node_modules/@vue/server-renderer/dist/server-renderer.esm-bundler.js +1 -1
- package/dist/martyrs/node_modules/@vue/server-renderer/dist/server-renderer.esm-bundler.js.map +1 -0
- package/dist/martyrs/node_modules/@vue/shared/dist/shared.esm-bundler.cjs.map +1 -0
- package/dist/martyrs/node_modules/@vue/shared/dist/shared.esm-bundler.js.map +1 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/regex.cjs +5 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/regex.cjs.map +1 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/regex.js +5 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/regex.js.map +1 -0
- package/dist/{node_modules/.pnpm/uuid@11.1.0 → martyrs}/node_modules/uuid/dist/esm-browser/rng.cjs +4 -4
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/rng.cjs.map +1 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/rng.js +15 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/rng.js.map +1 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/stringify.cjs +17 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/stringify.cjs.map +1 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/stringify.js +17 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/stringify.js.map +1 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/v4.cjs +13 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/v4.cjs.map +1 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/v4.js +13 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/v4.js.map +1 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/validate.cjs +8 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/validate.cjs.map +1 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/validate.js +8 -0
- package/dist/martyrs/node_modules/uuid/dist/esm-browser/validate.js.map +1 -0
- package/dist/martyrs/src/components/Feed/Feed.vue.cjs +2 -2
- package/dist/martyrs/src/components/Feed/Feed.vue.cjs.map +1 -1
- package/dist/martyrs/src/components/Feed/Feed.vue.js +2 -2
- package/dist/martyrs/src/components/Feed/Feed.vue.js.map +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/Skeleton/Skeleton.vue.cjs +5 -5
- package/dist/martyrs/src/components/Skeleton/Skeleton.vue.cjs.map +1 -1
- package/dist/martyrs/src/components/Skeleton/Skeleton.vue.js +5 -5
- package/dist/martyrs/src/components/Skeleton/Skeleton.vue.js.map +1 -1
- package/dist/martyrs/src/components/Tab/{Tab.vue2.cjs → Tab.vue.cjs} +2 -2
- package/dist/martyrs/src/components/Tab/{Tab.vue2.js.map → Tab.vue.cjs.map} +1 -1
- package/dist/martyrs/src/components/Tab/{Tab.vue2.js → Tab.vue.js} +2 -2
- package/dist/martyrs/src/components/Tab/Tab.vue.js.map +1 -0
- package/dist/martyrs/src/components/Tree/Tree.vue.cjs +3 -1
- package/dist/martyrs/src/components/Tree/Tree.vue.cjs.map +1 -1
- package/dist/martyrs/src/components/Tree/Tree.vue.js +3 -1
- package/dist/martyrs/src/components/Tree/Tree.vue.js.map +1 -1
- package/dist/martyrs/src/modules/auth/views/components/layouts/Auth.vue.cjs +1 -1
- package/dist/martyrs/src/modules/auth/views/components/layouts/Auth.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 +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/Profile.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/ProfileBlogposts.vue.cjs +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/ProfileBlogposts.vue.js +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEdit.vue.cjs +1 -1
- package/dist/martyrs/src/modules/auth/views/components/pages/ProfileEdit.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/store/auth.cjs +1 -0
- package/dist/martyrs/src/modules/auth/views/store/auth.cjs.map +1 -1
- package/dist/martyrs/src/modules/auth/views/store/auth.js +1 -0
- package/dist/martyrs/src/modules/auth/views/store/auth.js.map +1 -1
- package/dist/martyrs/src/modules/constructor/components/sections/Constructor.vue.cjs +1 -1
- package/dist/martyrs/src/modules/constructor/components/sections/Constructor.vue.js +1 -1
- package/dist/martyrs/src/modules/events/components/pages/EventsBackoffice.vue.cjs +1 -1
- package/dist/martyrs/src/modules/events/components/pages/EventsBackoffice.vue.js +1 -1
- package/dist/martyrs/src/modules/globals/views/classes/globals.store.cjs +107 -21
- package/dist/martyrs/src/modules/globals/views/classes/globals.store.cjs.map +1 -1
- package/dist/martyrs/src/modules/globals/views/classes/globals.store.js +107 -21
- package/dist/martyrs/src/modules/globals/views/classes/globals.store.js.map +1 -1
- package/dist/martyrs/src/modules/globals/views/components/partials/Navigation.vue.cjs +10 -14
- package/dist/martyrs/src/modules/globals/views/components/partials/Navigation.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/globals/views/components/partials/Navigation.vue.js +12 -16
- package/dist/martyrs/src/modules/globals/views/components/partials/Navigation.vue.js.map +1 -1
- package/dist/martyrs/src/modules/globals/views/components/sections/SectionPageTitle.vue.cjs +1 -1
- package/dist/martyrs/src/modules/globals/views/components/sections/SectionPageTitle.vue.js +1 -1
- package/dist/martyrs/src/modules/globals/views/utils/vue-app-renderer.cjs +7 -13
- package/dist/martyrs/src/modules/globals/views/utils/vue-app-renderer.cjs.map +1 -1
- package/dist/martyrs/src/modules/globals/views/utils/vue-app-renderer.js +7 -13
- package/dist/martyrs/src/modules/globals/views/utils/vue-app-renderer.js.map +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.cjs +6 -7
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js +7 -8
- package/dist/martyrs/src/modules/orders/components/pages/OrderCreate.vue.js.map +1 -1
- 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/pages/Orders.vue.cjs +1 -1
- package/dist/martyrs/src/modules/orders/components/pages/Orders.vue.js +1 -1
- 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 +2 -2
- package/dist/martyrs/src/modules/organizations/components/pages/Members.vue.js +2 -2
- package/dist/martyrs/src/modules/organizations/components/pages/Organization.vue.cjs +2 -2
- package/dist/martyrs/src/modules/organizations/components/pages/Organization.vue.js +2 -2
- 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/pages/Organizations.vue.cjs +1 -1
- package/dist/martyrs/src/modules/organizations/components/pages/Organizations.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/products/components/blocks/CardCategory.vue.cjs +11 -5
- package/dist/martyrs/src/modules/products/components/blocks/CardCategory.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/products/components/blocks/CardCategory.vue.js +12 -6
- package/dist/martyrs/src/modules/products/components/blocks/CardCategory.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Categories.vue.cjs +34 -13
- package/dist/martyrs/src/modules/products/components/pages/Categories.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Categories.vue.js +35 -14
- package/dist/martyrs/src/modules/products/components/pages/Categories.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.cjs +20 -9
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js +21 -10
- package/dist/martyrs/src/modules/products/components/pages/CategoryEdit.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Leftovers.vue.cjs +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Leftovers.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Product.vue.cjs +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Product.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.cjs +2 -1
- package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.cjs.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js +2 -1
- package/dist/martyrs/src/modules/products/components/pages/ProductEdit.vue.js.map +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Products.vue.cjs +1 -1
- package/dist/martyrs/src/modules/products/components/pages/Products.vue.js +1 -1
- package/dist/martyrs/src/modules/products/components/sections/SectionProduct.vue.cjs +1 -1
- package/dist/martyrs/src/modules/products/components/sections/SectionProduct.vue.js +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/GanttChart.vue.cjs +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/GanttChart.vue.js +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/Rents.vue.cjs +1 -1
- package/dist/martyrs/src/modules/rents/views/components/pages/Rents.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.cjs.js +1 -1
- package/dist/martyrs.css +1 -1
- package/dist/martyrs.es.js +1 -1
- package/dist/notifications.server.js +35 -2
- package/dist/notifications.server.mjs +35 -2
- package/dist/orders.server.js +3 -3
- package/dist/orders.server.mjs +3 -3
- package/dist/organizations.server.js +1 -1
- package/dist/organizations.server.mjs +1 -1
- package/dist/products.server.js +78 -53
- package/dist/products.server.mjs +78 -53
- package/dist/rents.server.js +1 -1
- package/dist/rents.server.mjs +1 -1
- package/dist/style.css +37 -38
- package/dist/wallet.server.js +1 -1
- package/dist/wallet.server.mjs +1 -1
- package/package.json +2 -1
- package/src/components/Feed/Feed.vue +2 -7
- package/src/components/Skeleton/Skeleton.vue +4 -5
- package/src/components/Tree/Tree.vue +5 -2
- package/src/modules/auth/controllers/middlewares/authJwt.js +1 -1
- package/src/modules/auth/views/store/auth.js +2 -1
- package/src/modules/globals/controllers/classes/globals.crud.js +2 -2
- package/src/modules/globals/views/classes/globals.store.js +119 -31
- package/src/modules/globals/views/components/partials/Navigation.vue +11 -10
- package/src/modules/globals/views/utils/vue-app-renderer.js +7 -16
- package/src/modules/icons/entities/IconMusic.vue +14 -0
- package/src/modules/icons/navigation/IconCheck.vue +31 -0
- package/src/modules/icons/navigation/IconHeart.vue +26 -0
- package/src/modules/icons/navigation/IconPause.vue +31 -0
- package/src/modules/icons/navigation/IconPlay.vue +17 -0
- package/src/modules/icons/navigation/IconRefresh.vue +31 -0
- package/src/modules/icons/navigation/IconShuffle.vue +31 -0
- package/src/modules/icons/navigation/IconVolume.vue +31 -0
- package/src/modules/music/components/SidebarMusic.vue +156 -0
- package/src/modules/music/components/cards/AlbumCard.vue +107 -0
- package/src/modules/music/components/cards/ArtistCard.vue +37 -0
- package/src/modules/music/components/cards/PlaylistCard.vue +100 -0
- package/src/modules/music/components/cards/TrackCard.vue +86 -0
- package/src/modules/music/components/forms/PlaylistForm.vue +156 -0
- package/src/modules/music/components/forms/SearchForm.vue +82 -0
- package/src/modules/music/components/forms/UploadForm.vue +313 -0
- package/src/modules/music/components/layouts/MusicLayout.vue +137 -0
- package/src/modules/music/components/lists/AlbumList.vue +25 -0
- package/src/modules/music/components/lists/ArtistList.vue +25 -0
- package/src/modules/music/components/lists/PlaylistList.vue +25 -0
- package/src/modules/music/components/lists/TrackList.vue +175 -0
- package/src/modules/music/components/pages/AlbumDetail.vue +265 -0
- package/src/modules/music/components/pages/ArtistDetail.vue +247 -0
- package/src/modules/music/components/pages/MusicHome.vue +177 -0
- package/src/modules/music/components/pages/MusicLibrary.vue +192 -0
- package/src/modules/music/components/pages/MusicUpload.vue +44 -0
- package/src/modules/music/components/pages/PlaylistDetail.vue +504 -0
- package/src/modules/music/components/pages/SearchResults.vue +397 -0
- package/src/modules/music/components/pages/TrackDetail.vue +143 -0
- package/src/modules/music/components/player/MusicPlayer.vue +202 -0
- package/src/modules/music/components/player/TrackProgress.vue +110 -0
- package/src/modules/music/components/player/VolumeControl.vue +98 -0
- package/src/modules/music/controllers/album.controller.js +98 -0
- package/src/modules/music/controllers/artist.controller.js +111 -0
- package/src/modules/music/controllers/genre.controller.js +71 -0
- package/src/modules/music/controllers/music.controller.js +174 -0
- package/src/modules/music/controllers/playlist.controller.js +182 -0
- package/src/modules/music/controllers/search.controller.js +103 -0
- package/src/modules/music/controllers/stream.controller.js +106 -0
- package/src/modules/music/models/album.model.js +61 -0
- package/src/modules/music/models/artist.model.js +67 -0
- package/src/modules/music/models/genre.model.js +42 -0
- package/src/modules/music/models/play-history.model.js +51 -0
- package/src/modules/music/models/playlist.model.js +69 -0
- package/src/modules/music/models/track.model.js +94 -0
- package/src/modules/music/music.client.js +186 -0
- package/src/modules/music/music.server.js +114 -0
- package/src/modules/music/policies/music.policies.js +84 -0
- package/src/modules/music/router/music.js +77 -0
- package/src/modules/music/routes/album.routes.js +62 -0
- package/src/modules/music/routes/artist.routes.js +67 -0
- package/src/modules/music/routes/genre.routes.js +60 -0
- package/src/modules/music/routes/music.routes.js +145 -0
- package/src/modules/music/routes/playlist.routes.js +99 -0
- package/src/modules/music/routes/search.routes.js +10 -0
- package/src/modules/music/routes/stream.routes.js +38 -0
- package/src/modules/music/store/albums.js +200 -0
- package/src/modules/music/store/artists.js +180 -0
- package/src/modules/music/store/player.js +397 -0
- package/src/modules/music/store/playlists.js +211 -0
- package/src/modules/music/store/search.js +126 -0
- package/src/modules/music/store/tracks.js +230 -0
- package/src/modules/music/websocket/streaming.handler.js +151 -0
- package/src/modules/notifications/controllers/notifications.controller.js +44 -1
- package/src/modules/notifications/notifications.server.js +0 -1
- package/src/modules/notifications/routes/notifications.routes.js +3 -0
- package/src/modules/orders/components/pages/OrderCreate.vue +0 -2
- package/src/modules/products/components/blocks/CardCategory.vue +5 -4
- package/src/modules/products/components/pages/Categories.vue +38 -20
- package/src/modules/products/components/pages/CategoryEdit.vue +16 -7
- package/src/modules/products/components/pages/ProductEdit.vue +1 -0
- package/src/modules/products/controllers/categories.controller.js +155 -103
- 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/components/Tab/Tab.vue2.cjs.map +0 -1
- package/dist/node_modules/.pnpm/@vue_server-renderer@3.5.13_vue@3.5.13_typescript@5.8.3_/node_modules/@vue/server-renderer/dist/server-renderer.esm-bundler.cjs.map +0 -1
- package/dist/node_modules/.pnpm/@vue_server-renderer@3.5.13_vue@3.5.13_typescript@5.8.3_/node_modules/@vue/server-renderer/dist/server-renderer.esm-bundler.js.map +0 -1
- package/dist/node_modules/.pnpm/@vue_shared@3.5.13/node_modules/@vue/shared/dist/shared.esm-bundler.cjs.map +0 -1
- package/dist/node_modules/.pnpm/@vue_shared@3.5.13/node_modules/@vue/shared/dist/shared.esm-bundler.js.map +0 -1
- package/dist/node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/native.cjs +0 -6
- package/dist/node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/native.cjs.map +0 -1
- package/dist/node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/native.js +0 -6
- package/dist/node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/native.js.map +0 -1
- package/dist/node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/rng.cjs.map +0 -1
- package/dist/node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/rng.js +0 -15
- package/dist/node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/rng.js.map +0 -1
- package/dist/node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/stringify.cjs +0 -11
- package/dist/node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/stringify.cjs.map +0 -1
- package/dist/node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/stringify.js +0 -11
- package/dist/node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/stringify.js.map +0 -1
- package/dist/node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/v4.cjs +0 -21
- package/dist/node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/v4.cjs.map +0 -1
- package/dist/node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/v4.js +0 -21
- package/dist/node_modules/.pnpm/uuid@11.1.0/node_modules/uuid/dist/esm-browser/v4.js.map +0 -1
- /package/dist/{node_modules/.pnpm/@vue_shared@3.5.13 → martyrs}/node_modules/@vue/shared/dist/shared.esm-bundler.cjs +0 -0
- /package/dist/{node_modules/.pnpm/@vue_shared@3.5.13 → martyrs}/node_modules/@vue/shared/dist/shared.esm-bundler.js +0 -0
- /package/dist/{node_modules → martyrs/node_modules}/fast-deep-equal/index.cjs +0 -0
- /package/dist/{node_modules → martyrs/node_modules}/fast-deep-equal/index.cjs.map +0 -0
- /package/dist/{node_modules → martyrs/node_modules}/fast-deep-equal/index.js +0 -0
- /package/dist/{node_modules → martyrs/node_modules}/fast-deep-equal/index.js.map +0 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
<!-- components/lists/TrackList.vue (continued) -->
|
|
2
|
+
<template>
|
|
3
|
+
<div class="track-list w-100">
|
|
4
|
+
<div
|
|
5
|
+
v-if="showHeader"
|
|
6
|
+
class="track-list-header pd-small br-b br-solid br-dark-transp-20 t-grey flex-v-center flex"
|
|
7
|
+
>
|
|
8
|
+
<div class="track-number w-3r t-center">#</div>
|
|
9
|
+
<div class="track-title flex-child-1">TITLE</div>
|
|
10
|
+
<div v-if="showAlbum" class="track-album w-15r mobile:w-0 mobile:hidden">ALBUM</div>
|
|
11
|
+
<div class="track-duration w-5r t-right">DURATION</div>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<div class="track-list-body">
|
|
15
|
+
<div
|
|
16
|
+
v-for="(track, index) in tracks"
|
|
17
|
+
:key="track._id"
|
|
18
|
+
class="track-item pd-small hover-bg-dark-transp-25 flex-v-center flex cursor-pointer"
|
|
19
|
+
:class="{'bg-dark-transp-25': isPlaying(track)}"
|
|
20
|
+
@click="playTrack(track)"
|
|
21
|
+
@dblclick="playTrack(track, true)"
|
|
22
|
+
@mouseenter="hoveredIndex = index"
|
|
23
|
+
@mouseleave="hoveredIndex = -1"
|
|
24
|
+
>
|
|
25
|
+
<div class="track-number w-3r t-center pos-relative">
|
|
26
|
+
<span v-if="!isPlaying(track) && hoveredIndex !== index" class="t-grey">{{ index + 1 }}</span>
|
|
27
|
+
<Button
|
|
28
|
+
v-else-if="!isPlaying(track) && hoveredIndex === index"
|
|
29
|
+
@click.stop="playTrack(track)"
|
|
30
|
+
class="bg-transparent border-none pd-zero"
|
|
31
|
+
:showLoader="false"
|
|
32
|
+
:showSucces="false"
|
|
33
|
+
>
|
|
34
|
+
<IconPlay class="i-small" fill="rgb(var(--white))"/>
|
|
35
|
+
</Button>
|
|
36
|
+
<Button
|
|
37
|
+
v-else
|
|
38
|
+
@click.stop="pauseTrack()"
|
|
39
|
+
class="bg-transparent border-none pd-zero"
|
|
40
|
+
:showLoader="false"
|
|
41
|
+
:showSucces="false"
|
|
42
|
+
>
|
|
43
|
+
<IconPause class="i-small" fill="rgb(var(--main))"/>
|
|
44
|
+
</Button>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<div class="track-title flex-child-1 flex flex-v-center">
|
|
48
|
+
<div v-if="showCover" class="track-cover mn-r-small">
|
|
49
|
+
<Media
|
|
50
|
+
:url="track.coverUrl || (track.album && track.album.coverUrl) || '/assets/placeholder-track.jpg'"
|
|
51
|
+
class="w-3r h-3r object-fit-cover radius-small"
|
|
52
|
+
/>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<div class="track-info">
|
|
56
|
+
<div class="track-name t-white" :class="{'t-main': isPlaying(track)}">{{ track.title }}</div>
|
|
57
|
+
<div class="track-artist t-grey t-small">
|
|
58
|
+
<router-link
|
|
59
|
+
v-if="track.artist && track.artist._id"
|
|
60
|
+
:to="{ name: 'artist-detail', params: { url: track.artist.url } }"
|
|
61
|
+
class="t-grey hover-t-white"
|
|
62
|
+
@click.stop
|
|
63
|
+
>
|
|
64
|
+
{{ getArtistName(track) }}
|
|
65
|
+
</router-link>
|
|
66
|
+
<span v-else>{{ getArtistName(track) }}</span>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<div v-if="showAlbum" class="track-album w-15r mobile:w-0 mobile:hidden t-grey t-truncate">
|
|
72
|
+
<router-link
|
|
73
|
+
v-if="track.album && track.album._id"
|
|
74
|
+
:to="{ name: 'album-detail', params: { url: track.album.url } }"
|
|
75
|
+
class="t-grey hover-t-white"
|
|
76
|
+
@click.stop
|
|
77
|
+
>
|
|
78
|
+
{{ track.album.title }}
|
|
79
|
+
</router-link>
|
|
80
|
+
<span v-else>{{ track.album?.title || 'Single' }}</span>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<div class="track-duration w-5r t-right t-grey">{{ formatDuration(track.duration) }}</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
</template>
|
|
88
|
+
|
|
89
|
+
<script setup>
|
|
90
|
+
import { ref, computed } from 'vue';
|
|
91
|
+
import Media from '@martyrs/src/components/Media/Media.vue';
|
|
92
|
+
import Button from '@martyrs/src/components/Button/Button.vue';
|
|
93
|
+
import IconPlay from '@martyrs/src/modules/icons/navigation/IconPlay.vue';
|
|
94
|
+
import IconPause from '@martyrs/src/modules/icons/navigation/IconPause.vue';
|
|
95
|
+
|
|
96
|
+
// Import player store
|
|
97
|
+
import { state as playerState, actions as playerActions } from '../../store/player.js';
|
|
98
|
+
|
|
99
|
+
const props = defineProps({
|
|
100
|
+
tracks: {
|
|
101
|
+
type: Array,
|
|
102
|
+
required: true
|
|
103
|
+
},
|
|
104
|
+
showHeader: {
|
|
105
|
+
type: Boolean,
|
|
106
|
+
default: true
|
|
107
|
+
},
|
|
108
|
+
showAlbum: {
|
|
109
|
+
type: Boolean,
|
|
110
|
+
default: false
|
|
111
|
+
},
|
|
112
|
+
showCover: {
|
|
113
|
+
type: Boolean,
|
|
114
|
+
default: false
|
|
115
|
+
},
|
|
116
|
+
showIndex: {
|
|
117
|
+
type: Boolean,
|
|
118
|
+
default: true
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// State
|
|
123
|
+
const hoveredIndex = ref(-1);
|
|
124
|
+
|
|
125
|
+
// Computed
|
|
126
|
+
const currentTrack = computed(() => playerState.currentTrack);
|
|
127
|
+
|
|
128
|
+
// Methods
|
|
129
|
+
const isPlaying = (track) => {
|
|
130
|
+
return currentTrack.value && currentTrack.value._id === track._id && isPlaying.value;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const isHovering = (index) => {
|
|
134
|
+
return hoveredIndex.value === index;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const playTrack = (track, addToQueue = false) => {
|
|
138
|
+
if (addToQueue) {
|
|
139
|
+
playerActions.addToQueue(track);
|
|
140
|
+
} else {
|
|
141
|
+
// Find track index to set queue properly
|
|
142
|
+
const trackIndex = props.tracks.findIndex(t => t._id === track._id);
|
|
143
|
+
playerActions.setQueue([...props.tracks], trackIndex);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const pauseTrack = () => {
|
|
148
|
+
playerActions.togglePlay();
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const getArtistName = (track) => {
|
|
152
|
+
if (track.artist) {
|
|
153
|
+
if (typeof track.artist === 'object') {
|
|
154
|
+
return track.artist.name || 'Unknown Artist';
|
|
155
|
+
}
|
|
156
|
+
return track.artist;
|
|
157
|
+
}
|
|
158
|
+
return 'Unknown Artist';
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const formatDuration = (seconds) => {
|
|
162
|
+
if (!seconds) return '0:00';
|
|
163
|
+
|
|
164
|
+
const minutes = Math.floor(seconds / 60);
|
|
165
|
+
const remainingSeconds = Math.floor(seconds % 60);
|
|
166
|
+
|
|
167
|
+
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`;
|
|
168
|
+
};
|
|
169
|
+
</script>
|
|
170
|
+
|
|
171
|
+
<style scoped>
|
|
172
|
+
.track-item {
|
|
173
|
+
transition: background-color 0.2s ease;
|
|
174
|
+
}
|
|
175
|
+
</style>
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
<!-- components/pages/AlbumDetail.vue -->
|
|
2
|
+
<template>
|
|
3
|
+
<div class="album-detail-page">
|
|
4
|
+
<div v-if="isLoading" class="w-100 h-25r flex-center flex">
|
|
5
|
+
<Loader />
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div v-else-if="!album" class="t-center pd-big">
|
|
9
|
+
<h2 class="t-white">Album not found</h2>
|
|
10
|
+
<p class="t-grey t-medium">The album you're looking for doesn't exist or has been removed.</p>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div v-else>
|
|
14
|
+
<!-- Album Header -->
|
|
15
|
+
<div class="album-header mn-b-medium flex flex-v-center gap-medium">
|
|
16
|
+
<div class="album-cover">
|
|
17
|
+
<Media
|
|
18
|
+
:url="album.coverUrl || '/assets/placeholder-album.jpg'"
|
|
19
|
+
class="w-15r h-15r object-fit-cover shadow-lg radius-small"
|
|
20
|
+
/>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div class="album-info">
|
|
24
|
+
<div class="t-small t-uppercase t-white">Album</div>
|
|
25
|
+
<h1 class="t-white">{{ album.title }}</h1>
|
|
26
|
+
|
|
27
|
+
<div class="album-meta mn-t-small flex flex-v-center">
|
|
28
|
+
<router-link
|
|
29
|
+
v-if="album.artist && album.artist._id"
|
|
30
|
+
:to="{ name: 'artist-detail', params: { url: album.artist.url } }"
|
|
31
|
+
class="t-white t-medium hover-t-main"
|
|
32
|
+
>
|
|
33
|
+
{{ getArtistName(album) }}
|
|
34
|
+
</router-link>
|
|
35
|
+
<span v-else class="t-white t-medium">{{ getArtistName(album) }}</span>
|
|
36
|
+
|
|
37
|
+
<span class="t-grey mn-l-small mn-r-small">•</span>
|
|
38
|
+
|
|
39
|
+
<span class="t-grey">{{ formatReleaseYear(album.releaseDate) }}</span>
|
|
40
|
+
|
|
41
|
+
<span class="t-grey mn-l-small mn-r-small">•</span>
|
|
42
|
+
|
|
43
|
+
<span class="t-grey">{{ albumTracks.length }} {{ albumTracks.length === 1 ? 'song' : 'songs' }}</span>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<!-- Album Actions -->
|
|
49
|
+
<div class="album-actions mn-b-medium flex flex-v-center gap-small">
|
|
50
|
+
<Button
|
|
51
|
+
@click="playAlbum"
|
|
52
|
+
class="play-button bg-main radius-round pd-small flex-v-center flex gap-small hover-scale-1"
|
|
53
|
+
:showLoader="false"
|
|
54
|
+
:showSucces="false"
|
|
55
|
+
>
|
|
56
|
+
<IconPlay class="i-small" fill="rgb(var(--black))"/>
|
|
57
|
+
<span class="t-black t-medium">Play</span>
|
|
58
|
+
</Button>
|
|
59
|
+
|
|
60
|
+
<Button
|
|
61
|
+
@click="toggleFavorite"
|
|
62
|
+
class="bg-transparent border-none pd-zero"
|
|
63
|
+
:showLoader="false"
|
|
64
|
+
:showSucces="false"
|
|
65
|
+
>
|
|
66
|
+
<IconHeart class="i-medium" :fill="isFavorite ? 'rgb(var(--main))' : 'rgb(var(--white))'"/>
|
|
67
|
+
</Button>
|
|
68
|
+
|
|
69
|
+
<Dropdown class="pos-relative">
|
|
70
|
+
<Button
|
|
71
|
+
@click="showDropdown = !showDropdown"
|
|
72
|
+
class="bg-transparent border-none pd-zero"
|
|
73
|
+
:showLoader="false"
|
|
74
|
+
:showSucces="false"
|
|
75
|
+
>
|
|
76
|
+
<IconEllipsis class="i-medium" fill="rgb(var(--white))"/>
|
|
77
|
+
</Button>
|
|
78
|
+
|
|
79
|
+
<template #content>
|
|
80
|
+
<ul v-if="showDropdown" class="pd-small bg-dark radius-small pos-absolute pos-t-100 pos-r-0 z-index-3 w-max-15r mn-t-thin">
|
|
81
|
+
<li class="mn-b-thin">
|
|
82
|
+
<Button
|
|
83
|
+
@click="addToQueue"
|
|
84
|
+
class="bg-transparent border-none pd-thin t-white w-100 t-left hover-bg-dark radius-small"
|
|
85
|
+
:showLoader="false"
|
|
86
|
+
:showSucces="false"
|
|
87
|
+
>
|
|
88
|
+
<span>Add to Queue</span>
|
|
89
|
+
</Button>
|
|
90
|
+
</li>
|
|
91
|
+
<li>
|
|
92
|
+
<Button
|
|
93
|
+
@click="copyLink"
|
|
94
|
+
class="bg-transparent border-none pd-thin t-white w-100 t-left hover-bg-dark radius-small"
|
|
95
|
+
:showLoader="false"
|
|
96
|
+
:showSucces="false"
|
|
97
|
+
>
|
|
98
|
+
<span>Copy Link</span>
|
|
99
|
+
</Button>
|
|
100
|
+
</li>
|
|
101
|
+
</ul>
|
|
102
|
+
</template>
|
|
103
|
+
</Dropdown>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<!-- Album Tracks -->
|
|
107
|
+
<div class="album-tracks">
|
|
108
|
+
<TrackList
|
|
109
|
+
:tracks="albumTracks"
|
|
110
|
+
:showAlbum="false"
|
|
111
|
+
:showCover="false"
|
|
112
|
+
class="bg-dark-transp-10 radius-medium o-hidden"
|
|
113
|
+
/>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<!-- Album Info -->
|
|
117
|
+
<div v-if="album.description" class="album-description mn-t-medium pd-medium bg-dark-transp-10 radius-medium">
|
|
118
|
+
<h3 class="t-white mn-b-small">About</h3>
|
|
119
|
+
<p class="t-grey">{{ album.description }}</p>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<!-- More from this artist if available -->
|
|
123
|
+
<div v-if="moreFromArtist.length > 0" class="more-from-artist mn-t-medium">
|
|
124
|
+
<div class="flex-between flex mn-b-small">
|
|
125
|
+
<h2 class="t-white">More by {{ getArtistName(album) }}</h2>
|
|
126
|
+
<router-link
|
|
127
|
+
v-if="album.artist && album.artist._id"
|
|
128
|
+
:to="{ name: 'artist-detail', params: { url: album.artist.url } }"
|
|
129
|
+
class="t-main t-small hover-opacity"
|
|
130
|
+
>
|
|
131
|
+
See all
|
|
132
|
+
</router-link>
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
<div class="albums-grid cols-5 mobile:cols-2 gap-small">
|
|
136
|
+
<div v-for="relatedAlbum in moreFromArtist" :key="relatedAlbum._id">
|
|
137
|
+
<AlbumCard :album="relatedAlbum" />
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</template>
|
|
144
|
+
|
|
145
|
+
<script setup>
|
|
146
|
+
import { ref, computed, onMounted, watch } from 'vue';
|
|
147
|
+
import { useRoute, useRouter } from 'vue-router';
|
|
148
|
+
import TrackList from '../lists/TrackList.vue';
|
|
149
|
+
import AlbumCard from '../cards/AlbumCard.vue';
|
|
150
|
+
import Button from '@martyrs/src/components/Button/Button.vue';
|
|
151
|
+
import Loader from '@martyrs/src/components/Loader/Loader.vue';
|
|
152
|
+
import Media from '@martyrs/src/components/Media/Media.vue';
|
|
153
|
+
import Dropdown from '@martyrs/src/components/Dropdown/Dropdown.vue';
|
|
154
|
+
|
|
155
|
+
// Import icons
|
|
156
|
+
import IconPlay from '@martyrs/src/modules/icons/navigation/IconPlay.vue';
|
|
157
|
+
import IconHeart from '@martyrs/src/modules/icons/navigation/IconHeart.vue';
|
|
158
|
+
import IconEllipsis from '@martyrs/src/modules/icons/navigation/IconEllipsis.vue';
|
|
159
|
+
|
|
160
|
+
// Import store modules
|
|
161
|
+
import { state as albumsState, actions as albumsActions } from '../../store/albums.js';
|
|
162
|
+
import { actions as playerActions } from '../../store/player.js';
|
|
163
|
+
|
|
164
|
+
const route = useRoute();
|
|
165
|
+
const router = useRouter();
|
|
166
|
+
|
|
167
|
+
// State
|
|
168
|
+
const isLoading = ref(true);
|
|
169
|
+
const isFavorite = ref(false);
|
|
170
|
+
const showDropdown = ref(false);
|
|
171
|
+
const moreFromArtist = ref([]);
|
|
172
|
+
|
|
173
|
+
// Computed properties
|
|
174
|
+
const album = computed(() => albumsState.currentAlbum);
|
|
175
|
+
const albumTracks = computed(() => albumsState.currentAlbumTracks);
|
|
176
|
+
|
|
177
|
+
// Methods
|
|
178
|
+
const getArtistName = (albumItem) => {
|
|
179
|
+
if (!albumItem) return 'Unknown Artist';
|
|
180
|
+
|
|
181
|
+
if (albumItem.artist) {
|
|
182
|
+
if (typeof albumItem.artist === 'object') {
|
|
183
|
+
return albumItem.artist.name || 'Unknown Artist';
|
|
184
|
+
}
|
|
185
|
+
return albumItem.artist;
|
|
186
|
+
}
|
|
187
|
+
return 'Unknown Artist';
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const formatReleaseYear = (dateString) => {
|
|
191
|
+
if (!dateString) return '';
|
|
192
|
+
return new Date(dateString).getFullYear();
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const playAlbum = () => {
|
|
196
|
+
if (albumTracks.value && albumTracks.value.length > 0) {
|
|
197
|
+
playerActions.setQueue(albumTracks.value);
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const toggleFavorite = () => {
|
|
202
|
+
isFavorite.value = !isFavorite.value;
|
|
203
|
+
// Implement favorite album logic here
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const addToQueue = () => {
|
|
207
|
+
if (albumTracks.value && albumTracks.value.length > 0) {
|
|
208
|
+
// Add all tracks to queue
|
|
209
|
+
albumTracks.value.forEach(track => {
|
|
210
|
+
playerActions.addToQueue(track);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
showDropdown.value = false;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const copyLink = () => {
|
|
218
|
+
const url = window.location.href;
|
|
219
|
+
navigator.clipboard.writeText(url).then(() => {
|
|
220
|
+
// Could show a success notification here
|
|
221
|
+
showDropdown.value = false;
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const fetchAlbumData = async () => {
|
|
226
|
+
isLoading.value = true;
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
// Fetch album data
|
|
230
|
+
await albumsActions.fetchAlbumByUrl(route.params.url);
|
|
231
|
+
|
|
232
|
+
// If artist is available, fetch more albums from the same artist
|
|
233
|
+
if (album.value?.artist?._id) {
|
|
234
|
+
const artistAlbums = await albumsActions.fetchAlbums({
|
|
235
|
+
artist: album.value.artist._id,
|
|
236
|
+
status: 'published',
|
|
237
|
+
isPublic: true,
|
|
238
|
+
limit: 5
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Filter out the current album
|
|
242
|
+
moreFromArtist.value = artistAlbums.filter(a => a._id !== album.value._id);
|
|
243
|
+
}
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.error('Error fetching album data:', error);
|
|
246
|
+
} finally {
|
|
247
|
+
isLoading.value = false;
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// Fetch data when component mounts or URL changes
|
|
252
|
+
onMounted(fetchAlbumData);
|
|
253
|
+
|
|
254
|
+
watch(() => route.params.url, (newUrl) => {
|
|
255
|
+
if (newUrl) {
|
|
256
|
+
fetchAlbumData();
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
</script>
|
|
260
|
+
|
|
261
|
+
<style scoped>
|
|
262
|
+
.album-cover {
|
|
263
|
+
box-shadow: 0 4px 60px rgba(0, 0, 0, 0.5);
|
|
264
|
+
}
|
|
265
|
+
</style>
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
<!-- components/pages/ArtistDetail.vue -->
|
|
2
|
+
<template>
|
|
3
|
+
<div class="artist-detail-page">
|
|
4
|
+
<div v-if="isLoading" class="w-100 h-25r flex-center flex">
|
|
5
|
+
<Loader />
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<div v-else-if="!artist" class="t-center pd-big">
|
|
9
|
+
<h2 class="t-white">Artist not found</h2>
|
|
10
|
+
<p class="t-grey t-medium">The artist you're looking for doesn't exist or has been removed.</p>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div v-else>
|
|
14
|
+
<!-- Artist Header with Background -->
|
|
15
|
+
<div class="artist-hero pos-relative mn-b-medium pd-medium">
|
|
16
|
+
<div class="artist-cover pos-absolute pos-t-0 pos-l-0 w-100 h-100" v-if="artist.coverUrl">
|
|
17
|
+
<Media
|
|
18
|
+
:url="artist.coverUrl"
|
|
19
|
+
class="w-100 h-100 object-fit-cover"
|
|
20
|
+
/>
|
|
21
|
+
<div class="overlay pos-absolute pos-t-0 pos-l-0 w-100 h-100"></div>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="artist-header z-index-1 pos-relative flex flex-v-center gap-medium">
|
|
25
|
+
<div class="artist-photo">
|
|
26
|
+
<Media
|
|
27
|
+
:url="artist.photoUrl || '/assets/placeholder-artist.jpg'"
|
|
28
|
+
class="w-15r h-15r object-fit-cover radius-round shadow-lg"
|
|
29
|
+
/>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div class="artist-info">
|
|
33
|
+
<div v-if="artist.isVerified" class="verified-badge t-small t-uppercase t-main mn-b-small">
|
|
34
|
+
<IconVerified class="i-small mn-r-thin" fill="rgb(var(--main))"/>
|
|
35
|
+
Verified Artist
|
|
36
|
+
</div>
|
|
37
|
+
<h1 class="t-white">{{ artist.name }}</h1>
|
|
38
|
+
|
|
39
|
+
<div class="artist-stats mn-t-small t-grey">
|
|
40
|
+
{{ formatFollowersCount(artist.popularity || 0) }} followers
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<!-- Artist Actions -->
|
|
47
|
+
<div class="artist-actions mn-b-medium flex flex-v-center gap-small">
|
|
48
|
+
<Button
|
|
49
|
+
@click="playArtistTracks"
|
|
50
|
+
class="play-button bg-main radius-round pd-small flex-v-center flex gap-small hover-scale-1"
|
|
51
|
+
:showLoader="false"
|
|
52
|
+
:showSucces="false"
|
|
53
|
+
>
|
|
54
|
+
<IconPlay class="i-small" fill="rgb(var(--black))"/>
|
|
55
|
+
<span class="t-black t-medium">Play</span>
|
|
56
|
+
</Button>
|
|
57
|
+
|
|
58
|
+
<Button
|
|
59
|
+
@click="toggleFollow"
|
|
60
|
+
class="follow-button pd-small radius-extra"
|
|
61
|
+
:class="isFollowing ? 'bg-dark-transp-25 t-white br-solid br-white-transp-25' : 'bg-dark-transp-25 t-white'"
|
|
62
|
+
:showLoader="false"
|
|
63
|
+
:showSucces="false"
|
|
64
|
+
>
|
|
65
|
+
{{ isFollowing ? 'Following' : 'Follow' }}
|
|
66
|
+
</Button>
|
|
67
|
+
|
|
68
|
+
<Dropdown class="pos-relative">
|
|
69
|
+
<Button
|
|
70
|
+
@click="showDropdown = !showDropdown"
|
|
71
|
+
class="bg-transparent border-none pd-zero"
|
|
72
|
+
:showLoader="false"
|
|
73
|
+
:showSucces="false"
|
|
74
|
+
>
|
|
75
|
+
<IconEllipsis class="i-medium" fill="rgb(var(--white))"/>
|
|
76
|
+
</Button>
|
|
77
|
+
|
|
78
|
+
<template #content>
|
|
79
|
+
<ul v-if="showDropdown" class="pd-small bg-dark radius-small pos-absolute pos-t-100 pos-r-0 z-index-3 w-max-15r mn-t-thin">
|
|
80
|
+
<li>
|
|
81
|
+
<Button
|
|
82
|
+
@click="copyLink"
|
|
83
|
+
class="bg-transparent border-none pd-thin t-white w-100 t-left hover-bg-dark radius-small"
|
|
84
|
+
:showLoader="false"
|
|
85
|
+
:showSucces="false"
|
|
86
|
+
>
|
|
87
|
+
<span>Copy Link</span>
|
|
88
|
+
</Button>
|
|
89
|
+
</li>
|
|
90
|
+
</ul>
|
|
91
|
+
</template>
|
|
92
|
+
</Dropdown>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<!-- Popular Tracks -->
|
|
96
|
+
<section class="artist-popular-tracks mn-b-medium">
|
|
97
|
+
<h2 class="t-white mn-b-small">Popular</h2>
|
|
98
|
+
|
|
99
|
+
<TrackList
|
|
100
|
+
:tracks="discography.singles.slice(0, 5)"
|
|
101
|
+
:showAlbum="true"
|
|
102
|
+
:showCover="true"
|
|
103
|
+
class="bg-dark-transp-10 radius-medium o-hidden"
|
|
104
|
+
/>
|
|
105
|
+
</section>
|
|
106
|
+
|
|
107
|
+
<!-- Discography - Albums -->
|
|
108
|
+
<section v-if="discography.albums.length > 0" class="artist-albums mn-b-medium">
|
|
109
|
+
<div class="flex-between flex mn-b-small">
|
|
110
|
+
<h2 class="t-white">Albums</h2>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<AlbumList :albums="discography.albums" />
|
|
114
|
+
</section>
|
|
115
|
+
|
|
116
|
+
<!-- Singles and EPs -->
|
|
117
|
+
<section v-if="discography.singles.length > 5" class="artist-singles mn-b-medium">
|
|
118
|
+
<div class="flex-between flex mn-b-small">
|
|
119
|
+
<h2 class="t-white">Singles and EPs</h2>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<div class="singles-grid cols-5 mobile:cols-2 gap-small">
|
|
123
|
+
<div v-for="track in discography.singles.slice(5)" :key="track._id">
|
|
124
|
+
<TrackCard :track="track" />
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
</section>
|
|
128
|
+
|
|
129
|
+
<!-- Artist Bio -->
|
|
130
|
+
<section v-if="artist.bio" class="artist-bio mn-b-medium pd-medium bg-dark-transp-10 radius-medium">
|
|
131
|
+
<h2 class="t-white mn-b-small">About</h2>
|
|
132
|
+
<p class="t-grey">{{ artist.bio }}</p>
|
|
133
|
+
</section>
|
|
134
|
+
|
|
135
|
+
<!-- Related Artists -->
|
|
136
|
+
<section v-if="relatedArtists.length > 0" class="related-artists">
|
|
137
|
+
<h2 class="t-white mn-b-small">Fans Also Like</h2>
|
|
138
|
+
|
|
139
|
+
<ArtistList :artists="relatedArtists" />
|
|
140
|
+
</section>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</template>
|
|
144
|
+
|
|
145
|
+
<script setup>
|
|
146
|
+
import { ref, computed, onMounted, watch } from 'vue';
|
|
147
|
+
import { useRoute, useRouter } from 'vue-router';
|
|
148
|
+
import TrackList from '../lists/TrackList.vue';
|
|
149
|
+
import TrackCard from '../cards/TrackCard.vue';
|
|
150
|
+
import AlbumList from '../lists/AlbumList.vue';
|
|
151
|
+
import ArtistList from '../lists/ArtistList.vue';
|
|
152
|
+
import Button from '@martyrs/src/components/Button/Button.vue';
|
|
153
|
+
import Loader from '@martyrs/src/components/Loader/Loader.vue';
|
|
154
|
+
import Media from '@martyrs/src/components/Media/Media.vue';
|
|
155
|
+
import Dropdown from '@martyrs/src/components/Dropdown/Dropdown.vue';
|
|
156
|
+
|
|
157
|
+
// Import icons
|
|
158
|
+
import IconPlay from '@martyrs/src/modules/icons/navigation/IconPlay.vue';
|
|
159
|
+
import IconEllipsis from '@martyrs/src/modules/icons/navigation/IconEllipsis.vue';
|
|
160
|
+
import IconVerified from '@martyrs/src/modules/icons/navigation/IconCheck.vue';
|
|
161
|
+
|
|
162
|
+
// Import store modules
|
|
163
|
+
import { state as artistsState, actions as artistsActions } from '../../store/artists.js';
|
|
164
|
+
import { actions as playerActions } from '../../store/player.js';
|
|
165
|
+
|
|
166
|
+
const route = useRoute();
|
|
167
|
+
const router = useRouter();
|
|
168
|
+
|
|
169
|
+
// State
|
|
170
|
+
const isLoading = ref(true);
|
|
171
|
+
const isFollowing = ref(false);
|
|
172
|
+
const showDropdown = ref(false);
|
|
173
|
+
|
|
174
|
+
// Computed properties
|
|
175
|
+
const artist = computed(() => artistsState.currentArtist);
|
|
176
|
+
const discography = computed(() => artistsState.discography);
|
|
177
|
+
const relatedArtists = computed(() => artistsState.relatedArtists);
|
|
178
|
+
|
|
179
|
+
// Methods
|
|
180
|
+
const formatFollowersCount = (count) => {
|
|
181
|
+
if (count >= 1000000) {
|
|
182
|
+
return `${(count / 1000000).toFixed(1)}M`;
|
|
183
|
+
} else if (count >= 1000) {
|
|
184
|
+
return `${(count / 1000).toFixed(1)}K`;
|
|
185
|
+
}
|
|
186
|
+
return count.toString();
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const playArtistTracks = () => {
|
|
190
|
+
const tracks = [
|
|
191
|
+
...discography.value.singles,
|
|
192
|
+
...discography.value.albums.reduce((acc, album) => {
|
|
193
|
+
// In a real app, you'd first load the album tracks here
|
|
194
|
+
return acc;
|
|
195
|
+
}, [])
|
|
196
|
+
];
|
|
197
|
+
|
|
198
|
+
if (tracks.length > 0) {
|
|
199
|
+
playerActions.setQueue(tracks);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
const toggleFollow = () => {
|
|
204
|
+
isFollowing.value = !isFollowing.value;
|
|
205
|
+
// Implement follow artist logic here
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const copyLink = () => {
|
|
209
|
+
const url = window.location.href;
|
|
210
|
+
navigator.clipboard.writeText(url).then(() => {
|
|
211
|
+
// Could show a success notification here
|
|
212
|
+
showDropdown.value = false;
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const fetchArtistData = async () => {
|
|
217
|
+
isLoading.value = true;
|
|
218
|
+
|
|
219
|
+
try {
|
|
220
|
+
// Fetch artist data
|
|
221
|
+
await artistsActions.fetchArtistByUrl(route.params.url);
|
|
222
|
+
} catch (error) {
|
|
223
|
+
console.error('Error fetching artist data:', error);
|
|
224
|
+
} finally {
|
|
225
|
+
isLoading.value = false;
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
// Fetch data when component mounts or URL changes
|
|
230
|
+
onMounted(fetchArtistData);
|
|
231
|
+
|
|
232
|
+
watch(() => route.params.url, (newUrl) => {
|
|
233
|
+
if (newUrl) {
|
|
234
|
+
fetchArtistData();
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
</script>
|
|
238
|
+
|
|
239
|
+
<style scoped>
|
|
240
|
+
.artist-hero {
|
|
241
|
+
min-height: 20rem;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.overlay {
|
|
245
|
+
background: linear-gradient(transparent 0%, rgba(0, 0, 0, 0.8) 100%);
|
|
246
|
+
}
|
|
247
|
+
</style>
|