added featured playlists feature

This commit is contained in:
SrGooglo 2023-11-28 20:58:39 +00:00
parent fa051b73b0
commit 518d2d498a
7 changed files with 238 additions and 32 deletions

View File

@ -3,11 +3,10 @@ import * as antd from "antd"
import classnames from "classnames"
import { Translation } from "react-i18next"
import Image from "components/Image"
import Searcher from "components/Searcher"
import { Icons, createIconRender } from "components/Icons"
import { WithPlayerContext } from "contexts/WithPlayerContext"
import FeedModel from "models/feed"
import MusicModel from "models/music"
@ -16,6 +15,48 @@ import PlaylistItem from "components/Music/PlaylistItem"
import "./index.less"
const FeaturedPlaylist = (props) => {
const [featuredPlaylist, setFeaturedPlaylist] = React.useState(false)
const onClick = () => {
if (!featuredPlaylist) {
return
}
app.navigation.goToPlaylist(featuredPlaylist.playlist_id)
}
React.useEffect(() => {
MusicModel.getFeaturedPlaylists().then((data) => {
if (data[0]) {
console.log(`Loaded featured playlist >`, data[0])
setFeaturedPlaylist(data[0])
}
})
}, [])
if (!featuredPlaylist) {
return null
}
return <div className="featured_playlist" onClick={onClick}>
<Image
src={featuredPlaylist.cover_url}
/>
<div className="featured_playlist_content">
<h1>{featuredPlaylist.title}</h1>
<p>{featuredPlaylist.description}</p>
{
featuredPlaylist.genre && <div className="featured_playlist_genre">
<span>{featuredPlaylist.genre}</span>
</div>
}
</div>
</div>
}
const MusicNavbar = (props) => {
return <div className="music_navbar">
<Searcher
@ -287,6 +328,8 @@ export default (props) => {
{
!searchResults && <div className="feed_main">
<FeaturedPlaylist />
<PlaylistsList
headerTitle="From your following artists"
headerIcon={<Icons.MdPerson />}

View File

@ -1,7 +1,6 @@
html {
&.mobile {
.musicExplorer {
.playlistExplorer_section_list {
overflow: visible;
overflow-x: scroll;
@ -16,6 +15,101 @@ html {
}
}
.featured_playlist {
position: relative;
display: flex;
flex-direction: row;
overflow: hidden;
background-color: var(--background-color-accent);
width: 100%;
min-height: 200px;
height: fit-content;
border-radius: 12px;
cursor: pointer;
&:hover {
.featured_playlist_content {
h1,
p {
-webkit-text-stroke-width: 1.6px;
-webkit-text-stroke-color: var(--border-color);
color: var(--background-color-contrast);
}
}
.lazy-load-image-background {
opacity: 1;
}
}
.lazy-load-image-background {
z-index: 50;
position: absolute;
opacity: 0.3;
transition: all 300ms ease-in-out !important;
img {
width: 100%;
height: 100%;
}
}
.featured_playlist_content {
z-index: 55;
padding: 20px;
display: flex;
flex-direction: column;
h1 {
font-size: 2.5rem;
font-family: "Space Grotesk", sans-serif;
font-weight: 900;
transition: all 300ms ease-in-out !important;
}
p {
font-size: 1rem;
font-family: "Space Grotesk", sans-serif;
transition: all 300ms ease-in-out !important;
}
.featured_playlist_genre {
z-index: 55;
position: absolute;
left: 0;
bottom: 0;
margin: 10px;
background-color: var(--background-color-accent);
border: 1px solid var(--border-color);
border-radius: 12px;
padding: 10px 20px;
}
}
}
.music_navbar {
display: flex;
flex-direction: column;

View File

@ -7,6 +7,21 @@ export default class MusicModel {
return globalThis.__comty_shared_state.instances["music"]
}
/**
* Retrieves the official featured playlists.
*
* @return {Promise<Object>} The data containing the featured playlists.
*/
static async getFeaturedPlaylists() {
const response = await request({
instance: MusicModel.api_instance,
method: "GET",
url: "/featured/playlists",
})
return response.data
}
/**
* Retrieves track data for a given ID.
*

View File

@ -0,0 +1,21 @@
import path from "path"
import createRoutesFromDirectory from "@utils/createRoutesFromDirectory"
import getMiddlewares from "@utils/getMiddlewares"
export default async (router) => {
// create a file based router
const routesPath = path.resolve(__dirname, "routes")
const middlewares = await getMiddlewares(["withOptionalAuth"])
for (const middleware of middlewares) {
router.use(middleware)
}
router = createRoutesFromDirectory("routes", routesPath, router)
return {
path: "/featured",
router,
}
}

View File

@ -0,0 +1,19 @@
import { FeaturedPlaylist } from "@shared-classes/DbModels"
export default async (req, res) => {
const includeDisabled = req.query["include-disabled"] === "true"
const query = {
enabled: true
}
if (includeDisabled) {
query.enabled = undefined
}
let playlists = await FeaturedPlaylist.find(query).catch((error) => {
return []
})
return res.json(playlists)
}

View File

@ -1,3 +1,5 @@
global.FORCE_ENV = "prod"
import Boot from "linebridge/bootstrap"
import { Server } from "linebridge/dist/server"

View File

@ -0,0 +1,12 @@
export default {
name: "FeaturedPlaylist",
collection: "featuredPlaylists",
schema: {
title: { type: String, required: true },
description: { type: String },
cover_url: { type: String },
enabled: { type: Boolean, default: true },
genre: { type: String },
playlist_id: { type: String, required: true },
}
}