рефакторинг
This commit is contained in:
parent
a74b994b07
commit
96f318a306
16
src/App.css
16
src/App.css
@ -85,8 +85,16 @@
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.song-cover {
|
||||
|
||||
.information {
|
||||
-webkit-box-shadow: 0px 26px 19px 0px rgba(34, 60, 80, 0.2);
|
||||
-moz-box-shadow: 0px 26px 19px 0px rgba(34, 60, 80, 0.2);
|
||||
box-shadow: 0px 26px 19px 0px rgba(34, 60, 80, 0.2);
|
||||
transform-origin: top center;
|
||||
animation: fadeInAndMoveDown 0.2s ease-out forwards;
|
||||
}
|
||||
@keyframes fadeInAndMoveDown {
|
||||
from { opacity: 0; transform: translateY(-50px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.AdBlock {
|
||||
@ -161,6 +169,9 @@
|
||||
}
|
||||
.current-song-cover {
|
||||
object-fit: scale-down;
|
||||
position: relative;
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.player-button {
|
||||
@ -212,6 +223,7 @@
|
||||
.title-side-block {
|
||||
font-size: 22px;
|
||||
border-bottom: 2px solid #505050;
|
||||
align-self: stretch;
|
||||
align-self: flex-start;
|
||||
color: #505050;
|
||||
}
|
@ -3,11 +3,10 @@ import { Tabs } from 'antd';
|
||||
import React from 'react';
|
||||
import { PlaylistsBlock } from '../menuComponents/PlaylistsBlock';
|
||||
import { IAlbum, IGenre, IPlaylist, ISong } from '../../models/IModels';
|
||||
import { NewSongsBlock } from '../menuComponents/NewSongsBlock';
|
||||
import { SongsBlock } from '../menuComponents/NewSongsBlock';
|
||||
import { FullPlaylistBlock } from '../menuComponents/FullPlaylistBlock';
|
||||
import { width } from '@mui/system';
|
||||
import TabPane from 'antd/es/tabs/TabPane';
|
||||
import { ChartSongsBlock } from '../menuComponents/ChartSongsBlock';
|
||||
|
||||
interface MenuBlockProps {
|
||||
playlists?: IPlaylist[],
|
||||
@ -21,7 +20,7 @@ export function MenuBlock({playlists, songs, albums, genres}: MenuBlockProps) {
|
||||
const newSongsTab = {
|
||||
label: 'Новинки',
|
||||
key: 'New',
|
||||
children: songs? <NewSongsBlock /> : null
|
||||
children: songs? <SongsBlock /> : null
|
||||
};
|
||||
const playlistsTab = {
|
||||
label: 'Плейлисты',
|
||||
@ -32,15 +31,15 @@ export function MenuBlock({playlists, songs, albums, genres}: MenuBlockProps) {
|
||||
const chartTab = {
|
||||
label: 'Чарт',
|
||||
key: 'Chart',
|
||||
children: songs? <ChartSongsBlock /> : null
|
||||
children: songs? <SongsBlock charted /> : null
|
||||
};
|
||||
|
||||
const recTab = {
|
||||
label: 'Рекомендации',
|
||||
key: 'Recomendations',
|
||||
children: songs? <NewSongsBlock /> : null
|
||||
children: songs? <SongsBlock /> : null
|
||||
};
|
||||
const tabs = [recTab, newSongsTab, chartTab];
|
||||
const tabs = [newSongsTab, recTab, chartTab];
|
||||
|
||||
|
||||
return (
|
||||
|
@ -1,53 +0,0 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { ISong } from '../../models/IModels';
|
||||
import axios from 'axios';
|
||||
import { Table, Button, Empty } from 'antd';
|
||||
import { PlayCircleFilled, PlayCircleOutlined } from '@ant-design/icons';
|
||||
import { getSongs } from '../../API/api';
|
||||
import Title from 'antd/es/typography/Title';
|
||||
import { GetColumns } from './Templates/songsTemplate';
|
||||
import { GetColumnsWithNumber } from './Templates/numeredSongsTemplate';
|
||||
import { usePlayingContext } from '../../contexts/SongContexts/PlayingProvider';
|
||||
import { useCurrentSongContext } from '../../contexts/SongContexts/SongContextProvider';
|
||||
|
||||
// Функция для генерации номеров строк
|
||||
const generateRowNumbers = (rows: any[]) =>
|
||||
rows.map((_: any, index: number) => ({ ..._, number: index + 1 }));
|
||||
|
||||
export function ChartSongsBlock() {
|
||||
const [songs, setSongs] = useState<ISong[]>([]);
|
||||
const [numberedSongs, setNumberedSongs] = useState<ISong[]>([]);
|
||||
|
||||
const currentSongId = useCurrentSongContext();
|
||||
const isPlaying = usePlayingContext();
|
||||
|
||||
const fetchData = async () => {
|
||||
const response = await getSongs();
|
||||
setSongs(response.data);
|
||||
setNumberedSongs(generateRowNumbers(response.data));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="song-block flex border-slate-100">
|
||||
<Table
|
||||
title={() => <Title style={{textAlign: 'center'}} level={4}>Чарт</Title>}
|
||||
style={{ width: '100%', backgroundColor: 'transparent', overflowX: 'auto' }}
|
||||
className="songs-table menu-block"
|
||||
dataSource={numberedSongs}
|
||||
columns={GetColumnsWithNumber(numberedSongs)}
|
||||
showHeader={false}
|
||||
pagination={false}
|
||||
rowClassName={(record) => isPlaying ? (record.id === currentSongId.songId ? 'song-table-row-active' : 'song-table-row') : 'song-table-row'}
|
||||
rowKey={(record) => record.id}
|
||||
scroll={{ x: true }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -12,7 +12,11 @@ import { useCurrentSongContext } from '../../contexts/SongContexts/SongContextPr
|
||||
import { usePlayingContext } from '../../contexts/SongContexts/PlayingProvider';
|
||||
import { useSideBlockContext } from '../../contexts/SideBlockContexts/SideBlockProvider';
|
||||
|
||||
export function NewSongsBlock() {
|
||||
export function SongsBlock({charted = false}: {charted?: boolean}) {
|
||||
|
||||
// Функция для генерации номеров строк
|
||||
const generateRowNumbers = (rows: any[]) =>
|
||||
rows.map((_: any, index: number) => ({ ..._, number: index + 1 }));
|
||||
|
||||
const [songs, setSongs] = useState<ISong[]>([]);
|
||||
const [bands, setBands] = useState<IBand[]>([]);
|
||||
@ -41,11 +45,16 @@ export function NewSongsBlock() {
|
||||
|
||||
<Spin indicator={<Loading3QuartersOutlined spin style={{color: '#9d0000', fontSize: 30}} />} spinning={songs.length === 0}>
|
||||
<Table
|
||||
title={() => <Title level={4}>Горячие новинки</Title>}
|
||||
title={() =>
|
||||
<Title level={4}>
|
||||
{ charted ? <>Чарт: самые огненные треки</> : <>Горячие новинки </>}
|
||||
</Title>}
|
||||
style={{width: '100%', backgroundColor: 'transparent'}}
|
||||
className="songs-table menu-block"
|
||||
dataSource={songs.map((s: ISong) => ({...s, play: ''}))}
|
||||
columns={GetColumns(songs)}
|
||||
dataSource={
|
||||
charted ? generateRowNumbers(songs) : songs
|
||||
}
|
||||
columns={GetColumns(songs, charted)}
|
||||
showHeader={false}
|
||||
pagination={false}
|
||||
rowClassName={(record) => isPlaying ? (record.id === currentSongId.songId ? 'song-table-row-active' : 'song-table-row') : 'song-table-row'}
|
||||
@ -76,3 +85,4 @@ export function NewSongsBlock() {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -2,14 +2,16 @@ import react from "react";
|
||||
import { IAlbum, IBand, ISong, IAdvertisement } from "../../../models/IModels";
|
||||
import { getSong, getAlbum, getBand } from "../../../API/api";
|
||||
import Text from 'antd/es/typography/Text';
|
||||
import { useSideBlockContext } from '../../../contexts/SideBlockContexts/SideBlockProvider';
|
||||
import { usePlayingContext } from "../../../contexts/SongContexts/PlayingProvider";
|
||||
import { useCurrentSongContext } from "../../../contexts/SongContexts/SongContextProvider";
|
||||
import { AdCard } from "../../cardComponents/AdCard";
|
||||
import { Loading3QuartersOutlined } from "@ant-design/icons";
|
||||
import { Spin } from "antd";
|
||||
|
||||
|
||||
import { HeartOutlined, Loading3QuartersOutlined, PauseCircleFilled, PlayCircleFilled, ShareAltOutlined } from "@ant-design/icons";
|
||||
import { Spin, Typography } from "antd";
|
||||
|
||||
export function InformationTemplate ({obj}: {obj: ISong | IBand | IAlbum | IAdvertisement | undefined}) {
|
||||
|
||||
const { isPlaying, setIsPlaying } = usePlayingContext();
|
||||
const { songId, setSongId } = useCurrentSongContext();
|
||||
|
||||
function isAd(obj: any): obj is IAdvertisement {
|
||||
return Array.isArray(obj) && obj.every(item =>
|
||||
@ -43,28 +45,98 @@ export function InformationTemplate ({obj}: {obj: ISong | IBand | IAlbum | IAdve
|
||||
'city' in obj;
|
||||
}
|
||||
|
||||
const { contentObject } = useSideBlockContext();
|
||||
|
||||
switch (typeof obj) {
|
||||
case 'object':
|
||||
return (
|
||||
<div className="flex container" style={{ display: 'flex'}}>
|
||||
<div className="flex container information" style={{ display: 'flex'}}>
|
||||
|
||||
{isAd(obj) && Array.isArray(obj) ? obj.map((ad) => <AdCard ad={ad} key={ad.id} />) : null}
|
||||
|
||||
{isSong(obj) ?
|
||||
<div>
|
||||
<Text className="title-side-block">ТРЕК</Text>
|
||||
<div style={{marginTop: 10, marginBottom: 10}}>
|
||||
|
||||
<img
|
||||
src={obj.cover} alt={obj.song_name} className="rounded m-auto" style={{ width: '50%'}}>
|
||||
</img>
|
||||
|
||||
<Text>{obj.song_name}</Text>
|
||||
|
||||
<div style={{display: 'flex', textAlign: 'left', justifyContent: 'left', width: '100%', marginLeft: 70, overflow: 'hidden'}}>
|
||||
<Text style={{fontSize: 18, marginTop: 10, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis'}}>{obj.song_name}</Text>
|
||||
</div>
|
||||
<div style={{display: 'flex', textAlign: 'left', justifyContent: 'left', width: '100%', marginLeft: 70, overflow: 'hidden'}}>
|
||||
<Text style={{fontSize: 20, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis'}}>{obj.band_name}</Text>
|
||||
</div>
|
||||
|
||||
{isPlaying ?
|
||||
<PauseCircleFilled style={{color: '#9d0000', fontSize: 30, marginTop: 10}}
|
||||
onClick={() => {setIsPlaying(!isPlaying); setSongId(obj.id)}}>
|
||||
|
||||
</PauseCircleFilled>
|
||||
|
||||
:
|
||||
<PlayCircleFilled style={{color: '#9d0000', fontSize: 30, marginTop: 10}}
|
||||
onClick={() => {setIsPlaying(!isPlaying); setSongId(obj.id)}}>
|
||||
|
||||
</PlayCircleFilled>}
|
||||
|
||||
<HeartOutlined style={{color: '#9d0000', fontSize: 30, marginTop: 10}}></HeartOutlined>
|
||||
<ShareAltOutlined style={{color: '#9d0000', fontSize: 30, marginTop: 10}}></ShareAltOutlined>
|
||||
|
||||
</div>
|
||||
|
||||
: null}
|
||||
|
||||
|
||||
{isBand(obj) ? <Text>{obj.name}</Text> : null}
|
||||
{isBand(obj) ?
|
||||
|
||||
<div style={{marginTop: 10, marginBottom: 10, display: 'flex', flexDirection: 'column', alignContent: 'left'}}>
|
||||
<div style={{display: 'flex', textAlign: 'left', justifyContent: 'left', width: '100%', marginLeft: 70, marginBottom: 20, overflow: 'hidden'}}>
|
||||
<Text style={{fontSize: 22, marginTop: 10, whiteSpace:
|
||||
'nowrap', overflow: 'hidden', textOverflow: 'ellipsis'}}>
|
||||
{obj.name}
|
||||
</Text>
|
||||
</div>
|
||||
<div style={{display: 'flex', textAlign: 'left', justifyContent: 'left', width: '100%', marginLeft: 70, overflow: 'hidden'}}>
|
||||
<Text style={{fontSize: 20, marginTop: 10, whiteSpace:
|
||||
'normal', overflow: 'hidden', textOverflow: 'ellipsis'}}>
|
||||
Информация:
|
||||
</Text>
|
||||
</div>
|
||||
<div style={{display: 'flex', textAlign: 'left', justifyContent: 'left', width: '100%', marginLeft: 70, overflow: 'hidden'}}>
|
||||
<Text style={{fontSize: 18, marginTop: 10, marginLeft: 10, whiteSpace:
|
||||
'normal', overflow: 'hidden', textOverflow: 'ellipsis'}}>
|
||||
{obj.city},{obj.country}
|
||||
</Text>
|
||||
</div>
|
||||
<div style={{display: 'flex', textAlign: 'left', justifyContent: 'left', width: '100%', marginLeft: 70, overflow: 'hidden'}}>
|
||||
<Text style={{fontSize: 18, marginTop: 10, marginLeft: 10, whiteSpace:
|
||||
'normal', overflow: 'hidden', textOverflow: 'ellipsis'}}>
|
||||
годы: {obj.years}
|
||||
</Text>
|
||||
</div>
|
||||
<div style={{display: 'flex', textAlign: 'left', justifyContent: 'left', width: '100%', marginLeft: 70, overflow: 'hidden'}}>
|
||||
<Text style={{fontSize: 18, marginTop: 10, marginLeft: 10, whiteSpace:
|
||||
'normal', overflow: 'hidden', textOverflow: 'ellipsis'}}>
|
||||
жанры: {obj.genres.map((genre: string, index: number) => (
|
||||
<span key={index}>{genre}{index < obj.genres.length - 1 ? ', ' : ''}</span>
|
||||
))}
|
||||
</Text>
|
||||
</div>
|
||||
<div style={{display: 'flex', textAlign: 'left', justifyContent: 'left', width: '100%', marginLeft: 70, overflow: 'hidden'}}>
|
||||
<Text style={{fontSize: 20, marginTop: 10, whiteSpace:
|
||||
'normal', overflow: 'hidden', textOverflow: 'ellipsis'}}>
|
||||
Описание:
|
||||
</Text>
|
||||
</div>
|
||||
<div style={{display: 'flex', textAlign: 'left', justifyContent: 'left', width: '100%', marginLeft: 70, overflow: 'hidden'}}>
|
||||
<Text style={{fontSize: 18, marginTop: 10, marginLeft: 10, whiteSpace:
|
||||
'normal', overflow: 'hidden', textOverflow: 'ellipsis'}}>
|
||||
{obj.description}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
: null}
|
||||
{isAlbum(obj) ? <Text>{obj.name}</Text> : null}
|
||||
|
||||
</div>
|
||||
@ -81,4 +153,3 @@ export function InformationTemplate ({obj}: {obj: ISong | IBand | IAlbum | IAdve
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,72 +0,0 @@
|
||||
import { Button } from "antd";
|
||||
import { ISong } from "../../../models/IModels";
|
||||
import { useState } from "react";
|
||||
import { useCurrentSongContext } from "../../../contexts/SongContexts/SongContextProvider";
|
||||
import { usePlayingContext } from "../../../contexts/SongContexts/PlayingProvider";
|
||||
|
||||
const useColumnsWithNumber = (songs: ISong[]) => {
|
||||
|
||||
const {isPlaying, setIsPlaying} = usePlayingContext();
|
||||
const { songId, setSongId } = useCurrentSongContext();
|
||||
|
||||
const handlePlayClick = (songId: string) => {
|
||||
setIsPlaying(!isPlaying);
|
||||
setSongId(songId);
|
||||
};
|
||||
|
||||
return [
|
||||
{
|
||||
title: '#',
|
||||
dataIndex: 'number',
|
||||
key: 'number',
|
||||
width: 50,
|
||||
render: (value: any, record: ISong, index: number) => {
|
||||
return record.number === 1 ? <span style={{ fontSize: '18px', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>👑</span> :
|
||||
<span style={{ fontSize: '18px', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>{record.number}</span>;
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
title: 'Play',
|
||||
dataIndex: 'play',
|
||||
key: 'play',
|
||||
width: 100,
|
||||
|
||||
render: (text: string, song: ISong) => (
|
||||
<Button data-content={!isPlaying && song.id === songId ? '┃┃' : "▷"}
|
||||
className='play-song-button rounded' style={{background: 'transparent', display: 'contents'}}
|
||||
onClick={() => handlePlayClick(song.id)}>
|
||||
|
||||
<img
|
||||
className="rounded "
|
||||
src={song.cover}
|
||||
alt={song.song_name}
|
||||
/>
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
dataIndex: 'song_name',
|
||||
key: 'song_name',
|
||||
width: 400
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
dataIndex: 'band_name',
|
||||
key: 'band_name',
|
||||
width: 400
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
dataIndex: 'album_name',
|
||||
key: 'album_name',
|
||||
width: 350
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
export function GetColumnsWithNumber(songs: ISong[]) {
|
||||
return useColumnsWithNumber(songs);
|
||||
}
|
@ -5,7 +5,7 @@ import { height, style } from "@mui/system";
|
||||
import { useCurrentSongContext } from "../../../contexts/SongContexts/SongContextProvider";
|
||||
import { usePlayingContext } from "../../../contexts/SongContexts/PlayingProvider";
|
||||
|
||||
const useColumns = (songs: ISong[])=> {
|
||||
const useColumns = (songs: ISong[], chart: boolean = false) => {
|
||||
|
||||
const {isPlaying, setIsPlaying} = usePlayingContext();
|
||||
const { songId, setSongId } = useCurrentSongContext();
|
||||
@ -16,7 +16,20 @@ const useColumns = (songs: ISong[])=> {
|
||||
};
|
||||
|
||||
|
||||
return [
|
||||
const columns = [
|
||||
...(chart ?
|
||||
[
|
||||
{
|
||||
title: '#',
|
||||
dataIndex: 'number',
|
||||
key: 'number',
|
||||
width: 50,
|
||||
render: (value: any, record: ISong, index: number) => {
|
||||
return record.number === 1 ? <span style={{ fontSize: '18px', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>👑</span> :
|
||||
<span style={{ fontSize: '18px', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>{record.number}</span>;
|
||||
},
|
||||
},
|
||||
]: []),
|
||||
{
|
||||
title: 'Play',
|
||||
dataIndex: 'play',
|
||||
@ -44,7 +57,7 @@ const useColumns = (songs: ISong[])=> {
|
||||
dataIndex: 'song_name',
|
||||
key: 'song_name',
|
||||
width: 400,
|
||||
render: (text: string, song: ISong) => <span style={{cursor: 'default'}}>{text}</span>
|
||||
render: (text: string, song: ISong) => (<div style={{cursor: 'default'}}>{text} </div>)
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
@ -60,8 +73,10 @@ const useColumns = (songs: ISong[])=> {
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
return columns
|
||||
}
|
||||
|
||||
export function GetColumns(songs: ISong[]) {
|
||||
return useColumns(songs);
|
||||
export function GetColumns(songs: ISong[], chart: boolean) {
|
||||
return useColumns(songs, chart);
|
||||
}
|
||||
|
@ -19,10 +19,7 @@ const Song = styled.div`
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 0 10px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
type CurrentSongProps = {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { MailOutlined, LockOutlined } from "@ant-design/icons";
|
||||
import { Form, Input, Button, Checkbox } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
// @ts-ignore
|
||||
import ReCAPTCHA from "react-google-recaptcha";
|
||||
import React, { useState } from "react";
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user