рефакторинг

This commit is contained in:
devilofthedeath 2024-11-19 01:26:23 +04:00
parent a74b994b07
commit 96f318a306
9 changed files with 139 additions and 159 deletions

View File

@ -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;
}

View File

@ -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 (

View File

@ -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>
);
};

View File

@ -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>
);
};

View File

@ -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
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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 = {

View File

@ -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";