mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 18:44:16 +00:00
improve explore & library
This commit is contained in:
parent
39b427dea7
commit
e54c3a1abe
@ -1,18 +1,22 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
import Searcher from "@components/Searcher"
|
import Searcher from "@components/Searcher"
|
||||||
import MusicModel from "@models/music"
|
import SearchModel from "@models/search"
|
||||||
|
|
||||||
const MusicNavbar = (props) => {
|
const MusicNavbar = (props) => {
|
||||||
return <div className="music_navbar">
|
return (
|
||||||
|
<div className="music_navbar">
|
||||||
<Searcher
|
<Searcher
|
||||||
useUrlQuery
|
useUrlQuery
|
||||||
renderResults={false}
|
renderResults={false}
|
||||||
model={MusicModel.search}
|
model={async (keywords, params) =>
|
||||||
|
SearchModel.search(keywords, params, ["tracks"])
|
||||||
|
}
|
||||||
onSearchResult={props.setSearchResults}
|
onSearchResult={props.setSearchResults}
|
||||||
onEmpty={() => props.setSearchResults(false)}
|
onEmpty={() => props.setSearchResults(false)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MusicNavbar
|
export default MusicNavbar
|
@ -1,12 +1,66 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
|
import * as antd from "antd"
|
||||||
|
|
||||||
|
import Image from "@components/Image"
|
||||||
import { Icons } from "@components/Icons"
|
import { Icons } from "@components/Icons"
|
||||||
|
import MusicModel from "@models/music"
|
||||||
|
|
||||||
import "./index.less"
|
import "./index.less"
|
||||||
|
|
||||||
|
const RecentlyPlayedItem = (props) => {
|
||||||
|
const { track } = props
|
||||||
|
|
||||||
|
return <div
|
||||||
|
className="recently_played-item"
|
||||||
|
onClick={() => app.cores.player.start(track._id)}
|
||||||
|
>
|
||||||
|
<div className="recently_played-item-icon">
|
||||||
|
<Icons.FiPlay />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="recently_played-item-cover">
|
||||||
|
<Image
|
||||||
|
src={track.cover}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="recently_played-item-content">
|
||||||
|
<h3>{track.title}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
const RecentlyPlayedList = (props) => {
|
const RecentlyPlayedList = (props) => {
|
||||||
|
const [L_Tracks, R_Tracks, E_Tracks, M_Tracks] = app.cores.api.useRequest(MusicModel.getRecentyPlayed, {
|
||||||
|
limit: 7
|
||||||
|
})
|
||||||
|
|
||||||
|
if (E_Tracks) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
return <div className="recently_played">
|
return <div className="recently_played">
|
||||||
<div className="recently_played-header">
|
<div className="recently_played-header">
|
||||||
<h1>Recently played</h1>
|
<h1><Icons.MdHistory /> Recently played</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="recently_played-content">
|
||||||
|
{
|
||||||
|
L_Tracks && <antd.Skeleton active />
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
!L_Tracks && <div className="recently_played-content-items">
|
||||||
|
{
|
||||||
|
R_Tracks.map((track, index) => {
|
||||||
|
return <RecentlyPlayedItem
|
||||||
|
key={index}
|
||||||
|
track={track}
|
||||||
|
/>
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -14,4 +14,95 @@
|
|||||||
|
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.recently_played-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-x: scroll;
|
||||||
|
|
||||||
|
padding: 0 20px;
|
||||||
|
|
||||||
|
.recently_played-content-items {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
grid-template-rows: auto;
|
||||||
|
grid-column-gap: 20px;
|
||||||
|
grid-row-gap: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.recently_played-item {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
z-index: 50;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 100px;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
background-color: var(--background-color-accent);
|
||||||
|
border-radius: 12px;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.recently_played-item-icon {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recently_played-item-cover {
|
||||||
|
opacity: 0.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.recently_played-item-icon {
|
||||||
|
z-index: 55;
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
|
font-size: 3rem;
|
||||||
|
|
||||||
|
transition: all 150ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recently_played-item-cover {
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
z-index: 50;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
opacity: 0.5;
|
||||||
|
|
||||||
|
transition: all 150ms ease-in-out;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.recently_played-item-content {
|
||||||
|
z-index: 55;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
@ -3,20 +3,23 @@ import * as antd from "antd"
|
|||||||
import { Translation } from "react-i18next"
|
import { Translation } from "react-i18next"
|
||||||
|
|
||||||
import { Icons } from "@components/Icons"
|
import { Icons } from "@components/Icons"
|
||||||
import PlaylistItem from "@components/Music/PlaylistItem"
|
import Playlist from "@components/Music/Playlist"
|
||||||
|
|
||||||
import "./index.less"
|
import "./index.less"
|
||||||
|
|
||||||
const ReleasesList = (props) => {
|
const ReleasesList = (props) => {
|
||||||
const hopNumber = props.hopsPerPage ?? 6
|
const hopNumber = props.hopsPerPage ?? 9
|
||||||
|
|
||||||
const [offset, setOffset] = React.useState(0)
|
const [offset, setOffset] = React.useState(0)
|
||||||
const [ended, setEnded] = React.useState(false)
|
const [ended, setEnded] = React.useState(false)
|
||||||
|
|
||||||
const [loading, result, error, makeRequest] = app.cores.api.useRequest(props.fetchMethod, {
|
const [loading, result, error, makeRequest] = app.cores.api.useRequest(
|
||||||
|
props.fetchMethod,
|
||||||
|
{
|
||||||
limit: hopNumber,
|
limit: hopNumber,
|
||||||
trim: offset
|
trim: offset,
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
const onClickPrev = () => {
|
const onClickPrev = () => {
|
||||||
if (offset === 0) {
|
if (offset === 0) {
|
||||||
@ -79,24 +82,23 @@ const ReleasesList = (props) => {
|
|||||||
if (error) {
|
if (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
|
||||||
return <div className="playlistExplorer_section">
|
return (
|
||||||
|
<div className="playlistExplorer_section">
|
||||||
<antd.Result
|
<antd.Result
|
||||||
status="warning"
|
status="warning"
|
||||||
title="Failed to load"
|
title="Failed to load"
|
||||||
subTitle="We are sorry, but we could not load this requests. Please try again later."
|
subTitle="We are sorry, but we could not load this requests. Please try again later."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="music-releases-list">
|
return (
|
||||||
|
<div className="music-releases-list">
|
||||||
<div className="music-releases-list-header">
|
<div className="music-releases-list-header">
|
||||||
<h1>
|
<h1>
|
||||||
{
|
{props.headerIcon}
|
||||||
props.headerIcon
|
<Translation>{(t) => t(props.headerTitle)}</Translation>
|
||||||
}
|
|
||||||
<Translation>
|
|
||||||
{(t) => t(props.headerTitle)}
|
|
||||||
</Translation>
|
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div className="music-releases-list-actions">
|
<div className="music-releases-list-actions">
|
||||||
@ -114,19 +116,14 @@ const ReleasesList = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="music-releases-list-items">
|
<div className="music-releases-list-items">
|
||||||
{
|
{loading && <antd.Skeleton active />}
|
||||||
loading && <antd.Skeleton active />
|
{!loading &&
|
||||||
}
|
result.items.map((playlist, index) => {
|
||||||
{
|
return <Playlist key={index} playlist={playlist} />
|
||||||
!loading && result.items.map((playlist, index) => {
|
})}
|
||||||
return <PlaylistItem
|
|
||||||
key={index}
|
|
||||||
playlist={playlist}
|
|
||||||
/>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ReleasesList
|
export default ReleasesList
|
@ -33,20 +33,31 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
|
|
||||||
grid-gap: 20px;
|
grid-gap: 20px;
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
|
||||||
min-width: 372px !important;
|
@media (min-width: 768px) {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: 2000px) {
|
@media (min-width: 1000px) {
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 2300px) {
|
@media (min-width: 1500px) {
|
||||||
grid-template-columns: repeat(5, 1fr);
|
grid-template-columns: repeat(7, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
.playlistItem {
|
@media (min-width: 1600px) {
|
||||||
|
grid-template-columns: repeat(7, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1920px) {
|
||||||
|
grid-template-columns: repeat(9, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.playlist {
|
||||||
justify-self: center;
|
justify-self: center;
|
||||||
|
//min-width: 372px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,14 +5,14 @@ import { Translation } from "react-i18next"
|
|||||||
|
|
||||||
import { createIconRender } from "@components/Icons"
|
import { createIconRender } from "@components/Icons"
|
||||||
import MusicTrack from "@components/Music/Track"
|
import MusicTrack from "@components/Music/Track"
|
||||||
import PlaylistItem from "@components/Music/PlaylistItem"
|
import Playlist from "@components/Music/Playlist"
|
||||||
|
|
||||||
const ResultGroupsDecorators = {
|
const ResultGroupsDecorators = {
|
||||||
"playlists": {
|
"playlists": {
|
||||||
icon: "MdPlaylistPlay",
|
icon: "MdPlaylistPlay",
|
||||||
label: "Playlists",
|
label: "Playlists",
|
||||||
renderItem: (props) => {
|
renderItem: (props) => {
|
||||||
return <PlaylistItem
|
return <Playlist
|
||||||
key={props.key}
|
key={props.key}
|
||||||
playlist={props.item}
|
playlist={props.item}
|
||||||
/>
|
/>
|
||||||
@ -41,9 +41,18 @@ const SearchResults = ({
|
|||||||
|
|
||||||
let groupsKeys = Object.keys(data)
|
let groupsKeys = Object.keys(data)
|
||||||
|
|
||||||
// filter out empty groups
|
// filter out groups with no items array property
|
||||||
groupsKeys = groupsKeys.filter((key) => {
|
groupsKeys = groupsKeys.filter((key) => {
|
||||||
return data[key].length > 0
|
if (!Array.isArray(data[key].items)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
// filter out groups with empty items array
|
||||||
|
groupsKeys = groupsKeys.filter((key) => {
|
||||||
|
return data[key].items.length > 0
|
||||||
})
|
})
|
||||||
|
|
||||||
if (groupsKeys.length === 0) {
|
if (groupsKeys.length === 0) {
|
||||||
@ -86,7 +95,7 @@ const SearchResults = ({
|
|||||||
|
|
||||||
<div className="music-explorer_search_results_group_list">
|
<div className="music-explorer_search_results_group_list">
|
||||||
{
|
{
|
||||||
data[key].map((item, index) => {
|
data[key].items.map((item, index) => {
|
||||||
return decorator.renderItem({
|
return decorator.renderItem({
|
||||||
key: index,
|
key: index,
|
||||||
item
|
item
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import classnames from "classnames"
|
import classnames from "classnames"
|
||||||
|
|
||||||
|
import useCenteredContainer from "@hooks/useCenteredContainer"
|
||||||
|
|
||||||
import Searcher from "@components/Searcher"
|
import Searcher from "@components/Searcher"
|
||||||
import { Icons } from "@components/Icons"
|
import { Icons } from "@components/Icons"
|
||||||
|
|
||||||
import FeedModel from "@models/feed"
|
import FeedModel from "@models/feed"
|
||||||
import MusicModel from "@models/music"
|
import SearchModel from "@models/search"
|
||||||
|
|
||||||
import Navbar from "./components/Navbar"
|
import Navbar from "./components/Navbar"
|
||||||
import RecentlyPlayedList from "./components/RecentlyPlayedList"
|
import RecentlyPlayedList from "./components/RecentlyPlayedList"
|
||||||
@ -18,9 +20,9 @@ import "./index.less"
|
|||||||
const MusicExploreTab = (props) => {
|
const MusicExploreTab = (props) => {
|
||||||
const [searchResults, setSearchResults] = React.useState(false)
|
const [searchResults, setSearchResults] = React.useState(false)
|
||||||
|
|
||||||
React.useEffect(() => {
|
useCenteredContainer(false)
|
||||||
app.layout.toggleCenteredContent(true)
|
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
app.layout.page_panels.attachComponent("music_navbar", Navbar, {
|
app.layout.page_panels.attachComponent("music_navbar", Navbar, {
|
||||||
props: {
|
props: {
|
||||||
setSearchResults: setSearchResults,
|
setSearchResults: setSearchResults,
|
||||||
@ -43,7 +45,7 @@ import "./index.less"
|
|||||||
app.isMobile && <Searcher
|
app.isMobile && <Searcher
|
||||||
useUrlQuery
|
useUrlQuery
|
||||||
renderResults={false}
|
renderResults={false}
|
||||||
model={MusicModel.search}
|
model={(keywords, params) => SearchModel.search("music", keywords, params)}
|
||||||
onSearchResult={setSearchResults}
|
onSearchResult={setSearchResults}
|
||||||
onEmpty={() => setSearchResults(false)}
|
onEmpty={() => setSearchResults(false)}
|
||||||
/>
|
/>
|
||||||
@ -62,13 +64,7 @@ import "./index.less"
|
|||||||
<RecentlyPlayedList />
|
<RecentlyPlayedList />
|
||||||
|
|
||||||
<ReleasesList
|
<ReleasesList
|
||||||
headerTitle="From your following artists"
|
headerTitle="Explore"
|
||||||
headerIcon={<Icons.MdPerson />}
|
|
||||||
fetchMethod={FeedModel.getMusicFeed}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ReleasesList
|
|
||||||
headerTitle="Explore from global"
|
|
||||||
headerIcon={<Icons.MdExplore />}
|
headerIcon={<Icons.MdExplore />}
|
||||||
fetchMethod={FeedModel.getGlobalMusicFeed}
|
fetchMethod={FeedModel.getGlobalMusicFeed}
|
||||||
/>
|
/>
|
||||||
|
@ -35,7 +35,6 @@ html {
|
|||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
.featured_playlist_content {
|
.featured_playlist_content {
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
p {
|
p {
|
||||||
-webkit-text-stroke-width: 1.6px;
|
-webkit-text-stroke-width: 1.6px;
|
||||||
@ -106,8 +105,6 @@ html {
|
|||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.music_navbar {
|
.music_navbar {
|
||||||
@ -248,7 +245,9 @@ html {
|
|||||||
@playlistItem_height: 80px;
|
@playlistItem_height: 80px;
|
||||||
@playlistItem_padding: 10px;
|
@playlistItem_padding: 10px;
|
||||||
|
|
||||||
@playlistItem_cover_size: calc(@playlistItem_height - @playlistItem_padding * 2);
|
@playlistItem_cover_size: calc(
|
||||||
|
@playlistItem_height - @playlistItem_padding * 2
|
||||||
|
);
|
||||||
|
|
||||||
.playlistItem {
|
.playlistItem {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@ -28,10 +28,9 @@ const TabToHeader = {
|
|||||||
const Library = (props) => {
|
const Library = (props) => {
|
||||||
const [selectedTab, setSelectedTab] = React.useState("tracks")
|
const [selectedTab, setSelectedTab] = React.useState("tracks")
|
||||||
|
|
||||||
return <div className="music-library">
|
return (
|
||||||
|
<div className="music-library">
|
||||||
<div className="music-library_header">
|
<div className="music-library_header">
|
||||||
<h1>Library</h1>
|
|
||||||
|
|
||||||
<antd.Segmented
|
<antd.Segmented
|
||||||
value={selectedTab}
|
value={selectedTab}
|
||||||
onChange={setSelectedTab}
|
onChange={setSelectedTab}
|
||||||
@ -39,26 +38,27 @@ const Library = (props) => {
|
|||||||
{
|
{
|
||||||
value: "tracks",
|
value: "tracks",
|
||||||
label: "Tracks",
|
label: "Tracks",
|
||||||
icon: <Icons.MdMusicNote />
|
icon: <Icons.MdMusicNote />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "playlist",
|
value: "playlist",
|
||||||
label: "Playlists",
|
label: "Playlists",
|
||||||
icon: <Icons.MdPlaylistPlay />
|
icon: <Icons.MdPlaylistPlay />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "releases",
|
value: "releases",
|
||||||
label: "Releases",
|
label: "Releases",
|
||||||
icon: <Icons.MdPlaylistPlay />
|
icon: <Icons.MdPlaylistPlay />,
|
||||||
}
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
{selectedTab &&
|
||||||
selectedTab && TabToView[selectedTab] && React.createElement(TabToView[selectedTab])
|
TabToView[selectedTab] &&
|
||||||
}
|
React.createElement(TabToView[selectedTab])}
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Library
|
export default Library
|
@ -9,11 +9,12 @@ const loadLimit = 50
|
|||||||
|
|
||||||
const TracksLibraryView = () => {
|
const TracksLibraryView = () => {
|
||||||
const [offset, setOffset] = React.useState(0)
|
const [offset, setOffset] = React.useState(0)
|
||||||
const [list, setList] = React.useState([])
|
const [items, setItems] = React.useState([])
|
||||||
const [hasMore, setHasMore] = React.useState(true)
|
const [hasMore, setHasMore] = React.useState(true)
|
||||||
const [initialLoading, setInitialLoading] = React.useState(true)
|
const [initialLoading, setInitialLoading] = React.useState(true)
|
||||||
|
|
||||||
const [L_Favourites, R_Favourites, E_Favourites, M_Favourites] = app.cores.api.useRequest(MusicModel.getFavouriteFolder, {
|
const [L_Favourites, R_Favourites, E_Favourites, M_Favourites] =
|
||||||
|
app.cores.api.useRequest(MusicModel.getFavouriteFolder, {
|
||||||
offset: offset,
|
offset: offset,
|
||||||
limit: loadLimit,
|
limit: loadLimit,
|
||||||
})
|
})
|
||||||
@ -35,14 +36,11 @@ const TracksLibraryView = () => {
|
|||||||
setInitialLoading(false)
|
setInitialLoading(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R_Favourites.tracks.list.length === 0) {
|
if (R_Favourites.tracks.items.length === 0) {
|
||||||
setHasMore(false)
|
setHasMore(false)
|
||||||
} else {
|
} else {
|
||||||
setList((prev) => {
|
setItems((prev) => {
|
||||||
prev = [
|
prev = [...prev, ...R_Favourites.tracks.items]
|
||||||
...prev,
|
|
||||||
...R_Favourites.tracks.list,
|
|
||||||
]
|
|
||||||
|
|
||||||
return prev
|
return prev
|
||||||
})
|
})
|
||||||
@ -51,28 +49,34 @@ const TracksLibraryView = () => {
|
|||||||
}, [R_Favourites])
|
}, [R_Favourites])
|
||||||
|
|
||||||
if (E_Favourites) {
|
if (E_Favourites) {
|
||||||
return <antd.Result
|
return (
|
||||||
|
<antd.Result
|
||||||
status="warning"
|
status="warning"
|
||||||
title="Failed to load"
|
title="Failed to load"
|
||||||
subTitle={E_Favourites}
|
subTitle={E_Favourites}
|
||||||
/>
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initialLoading) {
|
if (initialLoading) {
|
||||||
return <antd.Skeleton active />
|
return <antd.Skeleton active />
|
||||||
}
|
}
|
||||||
|
|
||||||
return <PlaylistView
|
return (
|
||||||
|
<PlaylistView
|
||||||
noHeader
|
noHeader
|
||||||
|
noSearch
|
||||||
loading={L_Favourites}
|
loading={L_Favourites}
|
||||||
type="vertical"
|
type="vertical"
|
||||||
playlist={{
|
playlist={{
|
||||||
list: list
|
items: items,
|
||||||
|
total_length: R_Favourites.tracks.total_items,
|
||||||
}}
|
}}
|
||||||
onLoadMore={onLoadMore}
|
onLoadMore={onLoadMore}
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
length={R_Favourites.tracks.total_length}
|
length={R_Favourites.tracks.total_length}
|
||||||
/>
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TracksLibraryView
|
export default TracksLibraryView
|
Loading…
x
Reference in New Issue
Block a user