Это полное фиаско
This commit is contained in:
parent
19a608b934
commit
73954d9d5a
3
.env
3
.env
@ -1 +1,2 @@
|
||||
REACT_APP_DATABASE='http://localhost:3000/'
|
||||
REACT_APP_DATABASE='http://localhost:3000/'
|
||||
REACT_APP_RECAPTCHA_SITE_KEY='6LcZ-kkqAAAAAFdmy2tD1gKFdjxb0D71w5VMaisr'
|
16
README.md
16
README.md
@ -1,2 +1,18 @@
|
||||
# PromoCursed
|
||||
|
||||
ВАЖНАЯ ИНФОРМАЦИЯ!!!
|
||||
|
||||
По какой-то причине при передаче объекта песни в CurrentTrack и получение свойств объекта в этом компонента
|
||||
появляются ошибки. Их не было до какого-то момента, но я не успел к сроку выявить причины (я долго дебажил),
|
||||
но результата это не принесло. До сих пор причины для меня остаются, к сожалению, загадкой...
|
||||
|
||||
Что было добавлено/исправлено после очной демонстрации:
|
||||
|
||||
1. Компоненты были раскиданы по папкам
|
||||
2. Переименовал некоторые папки (например, API),
|
||||
3. Добавил новые компоненты
|
||||
4. Роутинг и страницы
|
||||
5. Валидация форм
|
||||
|
||||
Должен был добавить плеер с воспроизведением песен, но из-за ошибок, про которые я написал выше, не удалось.
|
||||
Пришлось жестко передать объект песни прямо в коде компонента.
|
||||
|
34
data.json
34
data.json
@ -7,7 +7,7 @@
|
||||
"band_name": "Nevroz",
|
||||
"albumid": "1",
|
||||
"album_name": "Album 1",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/Nirvana_-_Smells_Like_Teen_Spirit_75941061.mp3",
|
||||
"cover": "https://cdn1.ozone.ru/s3/multimedia-t/6893834213.jpg",
|
||||
"playlists": [
|
||||
"1",
|
||||
@ -23,7 +23,7 @@
|
||||
"band_name": "Nevroz",
|
||||
"albumid": "1",
|
||||
"album_name": "Album 1",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/Blur_-_Song_2_47967381.mp3",
|
||||
"cover": "https://cdn1.ozone.ru/s3/multimedia-t/6893834213.jpg",
|
||||
"playlists": [
|
||||
"2"
|
||||
@ -38,7 +38,7 @@
|
||||
"band_name": "noizemchik",
|
||||
"albumid": "2",
|
||||
"album_name": "Ругань из-за Стёпы",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/Noice_MC_-_Rugan_iz-za_steny_63872179.mp3",
|
||||
"cover": "https://sun9-11.userapi.com/impg/yfCwuWXI6NkFVC2HvMlegM2qWLlenkeiiRyvNQ/jpH8m1wlLqs.jpg?size=604x604&quality=95&sign=60a1d1877b49631fb6078db88715fc88&c_uniq_tag=UKrig2vg02reyBH_ML0OKeqt5gm_2jpwEXD7NJBUXoQ&type=album"
|
||||
,
|
||||
"playlists": [
|
||||
@ -54,7 +54,7 @@
|
||||
"band_name": "DSPD",
|
||||
"albumid": "3",
|
||||
"album_name": "Album 3",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/DSPD_-_Crazy_Frog_75801748.mp3",
|
||||
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
|
||||
"playlists": [
|
||||
"2", "3"
|
||||
@ -69,7 +69,7 @@
|
||||
"band_name": "DSPD",
|
||||
"albumid": "3",
|
||||
"album_name": "Album 3",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
|
||||
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
|
||||
"playlists": [
|
||||
"3"
|
||||
@ -84,7 +84,7 @@
|
||||
"band_name": "Nevroz",
|
||||
"albumid": "1",
|
||||
"album_name": "Album 1",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/Nirvana_-_Smells_Like_Teen_Spirit_75941061.mp3",
|
||||
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
|
||||
"playlists": [
|
||||
"1", "2"
|
||||
@ -99,7 +99,7 @@
|
||||
"band_name": "Nevroz",
|
||||
"albumid": "1",
|
||||
"album_name": "Album 1",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/Blur_-_Song_2_47967381.mp3",
|
||||
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
|
||||
"playlists": [
|
||||
"2"
|
||||
@ -114,7 +114,7 @@
|
||||
"band_name": "noizemchik",
|
||||
"albumid": "2",
|
||||
"album_name": "Ругань из-за Стёпы",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/Noice_MC_-_Rugan_iz-za_steny_63872179.mp3",
|
||||
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh"
|
||||
,
|
||||
"playlists": [
|
||||
@ -130,7 +130,7 @@
|
||||
"band_name": "DSPD",
|
||||
"albumid": "3",
|
||||
"album_name": "Album 3",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/DSPD_-_Crazy_Frog_75801748.mp3",
|
||||
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
|
||||
"playlists": [
|
||||
"2", "3"
|
||||
@ -145,7 +145,7 @@
|
||||
"band_name": "DSPD",
|
||||
"albumid": "3",
|
||||
"album_name": "Album 3",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
|
||||
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
|
||||
"playlists": [
|
||||
"3"
|
||||
@ -160,7 +160,7 @@
|
||||
"band_name": "DSPD",
|
||||
"albumid": "3",
|
||||
"album_name": "Album 3",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
|
||||
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
|
||||
"playlists": [
|
||||
"3"
|
||||
@ -175,7 +175,7 @@
|
||||
"band_name": "DSPD",
|
||||
"albumid": "3",
|
||||
"album_name": "Album 3",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
|
||||
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
|
||||
"playlists": [
|
||||
"3"
|
||||
@ -190,7 +190,7 @@
|
||||
"band_name": "DSPD",
|
||||
"albumid": "3",
|
||||
"album_name": "Album 3",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
|
||||
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
|
||||
"playlists": [
|
||||
"3"
|
||||
@ -205,7 +205,7 @@
|
||||
"band_name": "DSPD",
|
||||
"albumid": "3",
|
||||
"album_name": "Album 3",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
|
||||
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
|
||||
"playlists": [
|
||||
"3"
|
||||
@ -220,7 +220,7 @@
|
||||
"band_name": "DSPD",
|
||||
"albumid": "3",
|
||||
"album_name": "Album 3",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
|
||||
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
|
||||
"playlists": [
|
||||
"3"
|
||||
@ -235,7 +235,7 @@
|
||||
"band_name": "DSPD",
|
||||
"albumid": "3",
|
||||
"album_name": "Album 3",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
|
||||
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
|
||||
"playlists": [
|
||||
"3"
|
||||
@ -250,7 +250,7 @@
|
||||
"band_name": "DSPD",
|
||||
"albumid": "3",
|
||||
"album_name": "Album 3",
|
||||
"source": "source_path",
|
||||
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
|
||||
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
|
||||
"playlists": [
|
||||
"3"
|
||||
|
38
package-lock.json
generated
38
package-lock.json
generated
@ -26,6 +26,7 @@
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-dotenv": "^0.1.3",
|
||||
"react-google-recaptcha": "^3.1.0",
|
||||
"react-router-dom": "^6.26.2",
|
||||
"react-scripts": "5.0.1",
|
||||
"styled-components": "^6.1.12",
|
||||
@ -46,6 +47,7 @@
|
||||
"@storybook/react-webpack5": "^8.2.9",
|
||||
"@storybook/test": "^8.2.9",
|
||||
"@types/node-fetch": "^2.6.11",
|
||||
"@types/react-google-recaptcha": "^2.1.9",
|
||||
"eslint-plugin-storybook": "^0.8.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"storybook": "^8.2.9",
|
||||
@ -9518,6 +9520,16 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-google-recaptcha": {
|
||||
"version": "2.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.9.tgz",
|
||||
"integrity": "sha512-nT31LrBDuoSZJN4QuwtQSF3O89FVHC4jLhM+NtKEmVF5R1e8OY0Jo4//x2Yapn2aNHguwgX5doAq8Zo+Ehd0ug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-transition-group": {
|
||||
"version": "4.4.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz",
|
||||
@ -24607,6 +24619,19 @@
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-async-script": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz",
|
||||
"integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"hoist-non-react-statics": "^3.3.0",
|
||||
"prop-types": "^15.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-colorful": {
|
||||
"version": "5.6.1",
|
||||
"resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz",
|
||||
@ -24948,6 +24973,19 @@
|
||||
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-google-recaptcha": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz",
|
||||
"integrity": "sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prop-types": "^15.5.0",
|
||||
"react-async-script": "^1.2.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
|
@ -21,6 +21,7 @@
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-dotenv": "^0.1.3",
|
||||
"react-google-recaptcha": "^3.1.0",
|
||||
"react-router-dom": "^6.26.2",
|
||||
"react-scripts": "5.0.1",
|
||||
"styled-components": "^6.1.12",
|
||||
@ -74,6 +75,7 @@
|
||||
"@storybook/react-webpack5": "^8.2.9",
|
||||
"@storybook/test": "^8.2.9",
|
||||
"@types/node-fetch": "^2.6.11",
|
||||
"@types/react-google-recaptcha": "^2.1.9",
|
||||
"eslint-plugin-storybook": "^0.8.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"storybook": "^8.2.9",
|
||||
|
@ -20,6 +20,10 @@
|
||||
href="https://fonts.googleapis.com/css2?family=Permanent+Marker&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<title>React App</title>
|
||||
<script id="react-dotenv" src="./env.js"></script>
|
||||
|
41
src/App.css
41
src/App.css
@ -85,21 +85,17 @@
|
||||
}
|
||||
|
||||
.AdBlock {
|
||||
|
||||
border-top: none !important;
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.song-table-row {
|
||||
border: #61dafb !important;
|
||||
border-style: solid !important;
|
||||
border-width: 1px !important;
|
||||
border-radius: 5px !important;
|
||||
|
||||
}
|
||||
|
||||
.song-table-row:hover {
|
||||
border: #61dafb !important;
|
||||
border-style: solid !important;
|
||||
border-width: 1px !important;
|
||||
border-radius: 5px !important;
|
||||
outline: #9b9b9b solid 1px !important;
|
||||
outline-offset: -1px !important;
|
||||
}
|
||||
|
||||
|
||||
@ -158,4 +154,31 @@
|
||||
.menu-block {
|
||||
font-weight: 400;
|
||||
font-size: 42px;
|
||||
}
|
||||
|
||||
.login {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 20px;
|
||||
height: 100%;
|
||||
width: 40%;
|
||||
font-size: 24px;
|
||||
background-color: #fff;
|
||||
margin: 200px;
|
||||
}
|
||||
|
||||
.login-button {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
.login-button:hover {
|
||||
background-color: transparent !important;
|
||||
border-color: #ad0000 !important;
|
||||
color: #ad0000 !important;
|
||||
}
|
||||
|
||||
.bg-gradient {
|
||||
background-image: linear-gradient(-45deg, red 0%, yellow 25%, yellow 51%, #ad0000 100%);
|
||||
}
|
36
src/App.tsx
36
src/App.tsx
@ -24,46 +24,14 @@ import { Profilepage } from './pages/Profilepage';
|
||||
import { Layout } from './components/layoutComponents/Layout';
|
||||
|
||||
function App() {
|
||||
const [songs, setSongs] = React.useState<ISong[]>([]);
|
||||
const [albums, setAlbums] = React.useState<IAlbum[]>([]);
|
||||
const [genres, setGenres] = React.useState<IGenre[]>([]);
|
||||
const [bands, setBands] = React.useState<IBand[]>([]);
|
||||
const [playlists, setPlaylist] = React.useState<IPlaylist[]>([]);
|
||||
const [ads, setAds] = React.useState<IAdvertisement[]>([]);
|
||||
|
||||
async function fetchData() {
|
||||
|
||||
const responseSongs = getSongs();
|
||||
// const responseAlbums = await axios.get<IAlbum[]>('http://localhost:3000/albums');
|
||||
const responseGenres = getGenres();
|
||||
// const responseBands = await axios.get<IBand[]>('http://localhost:3000/bands');
|
||||
const responsePlaylists = getPlaylists();
|
||||
const responseAds = getAds();
|
||||
|
||||
setSongs((await responseSongs).data);
|
||||
// setAlbums(responseAlbums.data);
|
||||
setGenres((await responseGenres).data);
|
||||
// setBands(responseBands.data);
|
||||
setPlaylist((await responsePlaylists).data);
|
||||
setAds((await responseAds).data);
|
||||
}
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
fetchData();
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
const song = songs[1];
|
||||
|
||||
return (
|
||||
|
||||
<div className="App bg-slate-100">
|
||||
<div id="app" className='bg-white'>
|
||||
<div id="app" className='bg-gradient'>
|
||||
<Routes>
|
||||
<Route path='/' element={<Layout />}>
|
||||
<Route index element={<Homepage playlists={playlists} songs={songs} genres={genres} albums={albums} ads={ads} />} />
|
||||
<Route index element={<Homepage />} />
|
||||
<Route path='login' element={<Loginpage />} />
|
||||
<Route path='register' element={<Registerpage />} />
|
||||
<Route path='profile' element={<Profilepage />} />
|
||||
|
@ -1,7 +1,10 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { IAdvertisement } from "../../models/IModels";
|
||||
import { AdCard } from "../cardComponents/AdCard";
|
||||
import { getAds } from "../../API/api";
|
||||
|
||||
export function AdBlock({ads}: {ads: IAdvertisement[]}) {
|
||||
|
||||
export function AdBlock({ads}: {ads: any[]}) {
|
||||
return (
|
||||
<div className="AdBlock border-solid border-2 border-slate-100" style={{height: 'auto', minHeight: '100%', width: '30%'}}>
|
||||
{ads.map(ad => <AdCard key={ad.id} ad={ad} />)}
|
||||
|
@ -18,17 +18,17 @@ export function MenuBlock({playlists, songs, albums, genres}: MenuBlockProps) {
|
||||
const chartTab = {
|
||||
label: 'Чарт',
|
||||
key: 'Chart',
|
||||
children: songs? <SongsBlock songs={songs}/> : null
|
||||
children: songs? <SongsBlock /> : null
|
||||
};
|
||||
const playlistsTab = {
|
||||
label: 'Плейлисты',
|
||||
key: 'Playlists',
|
||||
children: playlists && genres ? <FullPlaylistBlock {...{playlists, genres}}/> : null
|
||||
children: playlists && genres ? <FullPlaylistBlock playlists={playlists} genres={genres}/> : null
|
||||
};
|
||||
const newSongsTab = {
|
||||
label: 'Новинки',
|
||||
key: 'New',
|
||||
children: songs? <SongsBlock songs={songs}/> : null
|
||||
children: songs? <SongsBlock /> : null
|
||||
};
|
||||
const tabs = [chartTab, playlistsTab, newSongsTab];
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { IGenre, IPlaylist } from "../../models/IModels";
|
||||
import { getPlaylistsByGenre } from "../../API/api";
|
||||
import { getGenres, getPlaylists, getPlaylistsByGenre } from "../../API/api";
|
||||
import { PlaylistsBlock } from "./PlaylistsBlock";
|
||||
import React, { useEffect } from "react";
|
||||
|
||||
export function FullPlaylistBlock({playlists}: {playlists: IPlaylist[]}, {genres}: {genres: IGenre[]}) {
|
||||
|
||||
export function FullPlaylistBlock({playlists, genres}: {playlists: IPlaylist[], genres: IGenre[]}) {
|
||||
|
||||
let genres_list: string[] = [];
|
||||
|
||||
let list_of_playlist_list = [];
|
||||
|
@ -5,9 +5,21 @@ import { Track } from '../songComponents/Track';
|
||||
import axios from 'axios';
|
||||
import { Table, Button, Empty } from 'antd';
|
||||
import { PlayCircleFilled, PlayCircleOutlined } from '@ant-design/icons';
|
||||
import { getSongs } from '../../API/api';
|
||||
|
||||
|
||||
export function SongsBlock({songs}: {songs: ISong[]}) {
|
||||
export function SongsBlock() {
|
||||
|
||||
const [songs, setSongs] = useState<ISong[]>([]);
|
||||
|
||||
const fetchData = async () => {
|
||||
const response = getSongs();
|
||||
setSongs((await response).data);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
@ -50,10 +62,10 @@ export function SongsBlock({songs}: {songs: ISong[]}) {
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="song-block flex bg-white border-solid border-2 border-slate-100">
|
||||
<div className="song-block flex border-slate-100">
|
||||
|
||||
<Table
|
||||
style={{width: '100%' }}
|
||||
style={{width: '100%', backgroundColor: 'transparent'}}
|
||||
className="songs-table menu-block"
|
||||
dataSource={songs.map((s: ISong) => ({...s, play: ''}))}
|
||||
columns={columns}
|
||||
|
@ -1,8 +1,10 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Button, Col, Grid, Row, Table } from 'antd';
|
||||
import { BackwardFilled, FastForwardFilled, FastBackwardFilled, PlayCircleFilled, PlayCircleOutlined, StepBackwardFilled, StepForwardFilled, HeartOutlined, ShareAltOutlined } from '@ant-design/icons';
|
||||
import { BackwardFilled, FastForwardFilled, FastBackwardFilled, PlayCircleFilled, PlayCircleOutlined, StepBackwardFilled, StepForwardFilled, HeartOutlined, ShareAltOutlined, PauseCircleFilled, PauseCircleOutlined } from '@ant-design/icons';
|
||||
import { ISong, SongProps } from '../../models/IModels';
|
||||
import styled from 'styled-components'
|
||||
import useSound from 'use-sound';
|
||||
import { getSongs } from '../../API/api';
|
||||
|
||||
const Song = styled.div`
|
||||
align-items: center;
|
||||
@ -10,16 +12,22 @@ const Song = styled.div`
|
||||
bottom: 0;
|
||||
width: 75%;`
|
||||
|
||||
export function CurrentTrack() {
|
||||
type CurrentSongProps = {
|
||||
song: ISong
|
||||
isPlayingVariable: boolean
|
||||
}
|
||||
|
||||
const song = {
|
||||
export function CurrentTrack({song, isPlayingVariable}: CurrentSongProps) {
|
||||
|
||||
|
||||
song = {
|
||||
"id": "5",
|
||||
"song_name": "Кем я стал",
|
||||
"band_id": "3",
|
||||
"band_name": "DSPD",
|
||||
"albumid": "3",
|
||||
"album_name": "Album 3",
|
||||
"source": "source_path",
|
||||
"source": "../../songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
|
||||
"cover": "https://avatars.yandex.net/get-music-content/6058982/7e431a83.a.23910092-1/m1000x1000?webp=false",
|
||||
"playlists": [
|
||||
"3",
|
||||
@ -28,6 +36,20 @@ export function CurrentTrack() {
|
||||
genre_name: "Rock",
|
||||
|
||||
};
|
||||
|
||||
const [isPlaying, setIsPlaying] = useState(isPlayingVariable);
|
||||
const [play, { pause, duration, sound }] = useSound(song.source, {volume: 0.5});
|
||||
|
||||
|
||||
const playingButton = () => {
|
||||
if (isPlaying) {
|
||||
pause();
|
||||
setIsPlaying(false);
|
||||
} else {
|
||||
play();
|
||||
setIsPlaying(true);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Song >
|
||||
@ -35,7 +57,7 @@ export function CurrentTrack() {
|
||||
<Row className='w-full h-full bg-white opacity-90 rounded' style={{display: 'flex', alignItems: 'center'}}>
|
||||
<Col span={4} className='flex flex-direction-row justify-center'>
|
||||
<Button type='link' icon={<FastBackwardFilled className='player-button' />}></Button>
|
||||
<Button type="link" icon={<PlayCircleOutlined className='player-button' />}></Button>
|
||||
<Button type="link" icon={isPlaying ? <PauseCircleOutlined className='player-button' onClick={playingButton}/> : <PlayCircleOutlined className='player-button' onClick={playingButton}/>}></Button>
|
||||
<Button type="link" icon={<FastForwardFilled className='player-button' style={{fontSize: 30}} />}></Button>
|
||||
</Col>
|
||||
<Col style={{width: 80}}>
|
||||
|
@ -4,15 +4,9 @@
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
font-family: 'Roboto', sans-serif !important;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
background-image: url('https://www.fonstola.ru/images/201301/fonstola.ru_86743.jpg');
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
code {
|
||||
@ -33,4 +27,76 @@ footer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.roboto-thin {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.roboto-light {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.roboto-regular {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.roboto-medium {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.roboto-bold {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.roboto-black {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-weight: 900;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.roboto-thin-italic {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.roboto-light-italic {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.roboto-regular-italic {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.roboto-medium-italic {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.roboto-bold-italic {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.roboto-black-italic {
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-weight: 900;
|
||||
font-style: italic;
|
||||
}
|
@ -24,15 +24,16 @@ export interface IGenre {
|
||||
export interface ISong {
|
||||
id: string
|
||||
song_name: string;
|
||||
band_name: string;
|
||||
cover: string;
|
||||
genreid: string;
|
||||
albumid: string;
|
||||
source: string;
|
||||
band_id: string;
|
||||
band_name: string;
|
||||
albumid: string;
|
||||
album_name: string;
|
||||
genre_name: string;
|
||||
source: string;
|
||||
cover: string;
|
||||
playlists: string[];
|
||||
genreid: string;
|
||||
genre_name: string;
|
||||
|
||||
}
|
||||
|
||||
export interface IPlaylist {
|
||||
|
@ -1,10 +1,45 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { getSongs, getGenres, getPlaylists, getAds } from "../API/api";
|
||||
import { AdBlock } from "../components/layoutComponents/AdBlock";
|
||||
import { MenuBlock } from "../components/layoutComponents/MenuBlock";
|
||||
import { CurrentTrack } from "../components/songComponents/CurrentTrack";
|
||||
import { IPlaylist, ISong, IAlbum, IGenre, IAdvertisement } from "../models/IModels";
|
||||
import { IPlaylist, ISong, IAlbum, IGenre, IAdvertisement, IBand } from "../models/IModels";
|
||||
|
||||
|
||||
export function Homepage() {
|
||||
const [albums, setAlbums] = useState<IAlbum[]>([]);
|
||||
|
||||
const [bands, setBands] = useState<IBand[]>([]);
|
||||
|
||||
const [songs, setSongs] = useState<ISong[]>([]);
|
||||
const [ads, setAds] = useState<IAdvertisement[]>([]);
|
||||
|
||||
|
||||
const [playlists, setPlaylist] = React.useState<IPlaylist[]>([]);
|
||||
const [genres, setGenres] = React.useState<IGenre[]>([]);
|
||||
|
||||
const fetchData = async () => {
|
||||
const [responseSongs, responseAds, responsePlaylists, responseGenres] = await Promise.all([
|
||||
getSongs(),
|
||||
getAds(),
|
||||
getPlaylists(),
|
||||
getGenres(),
|
||||
]);
|
||||
|
||||
setSongs(responseSongs.data);
|
||||
setAds(responseAds.data);
|
||||
setPlaylist(responsePlaylists.data);
|
||||
setGenres(responseGenres.data);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
export function Homepage({playlists, songs, genres, albums, ads}: {playlists: IPlaylist[], songs: ISong[], genres: IGenre[], albums: IAlbum[], ads: IAdvertisement[]}) {
|
||||
return (
|
||||
<><MenuBlock playlists={playlists} songs={songs} albums={albums} genres={genres} /><AdBlock ads={ads} /><CurrentTrack /></>
|
||||
<>
|
||||
<MenuBlock playlists={[]} songs={songs} albums={albums} genres={[]}/><AdBlock ads={ads}/>
|
||||
<CurrentTrack song={songs[0]} isPlayingVariable={false} />
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,32 +1,53 @@
|
||||
import { Form } from 'antd'
|
||||
import { LockOutlined, MailOutlined } from '@ant-design/icons';
|
||||
import { Form, Input, Button, Checkbox } from 'antd'
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
export function Loginpage() {
|
||||
return (
|
||||
<div className="container mx-auto" style={{height: 'auto', width: '100%', display: 'flex', justifyContent: 'center', backgroundImage: "url('https://www.google.com/url?sa=i&url=https%3A%2F%2Fwallpapers.99px.ru%2Fwallpapers%2F32630%2F&psig=AOvVaw1t52LawgmuRVrJhHsKhhe8&ust=1726831156597000&source=images&cd=vfe&opi=89978449&ved=0CBQQjRxqFwoTCNC43L7xzogDFQAAAAAdAAAAABAE')"}}>
|
||||
<div className='sb-login rounded bg-black'>
|
||||
|
||||
<div className="container mx-auto" style={{height: '200%', width: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
|
||||
<div className='login' >
|
||||
<Form>
|
||||
<p>Вход</p>
|
||||
<Form.Item style={{margin: '140px'}}>
|
||||
<p className='text-3xl' style={{ fontFamily: 'Roboto', marginTop: '100px', marginBottom: '50px'}}>Вход</p>
|
||||
<Form.Item style={{marginBottom: '50px'}}>
|
||||
<Form.Item
|
||||
name="username"
|
||||
rules={[{ required: true, message: 'Please input your username!' }]}
|
||||
style={{padding: '20px'}}
|
||||
name="email"
|
||||
rules={[{ required: true, message: 'Введите вашу почту!' }, { type: 'email', message: 'Некорректный формат' }]}
|
||||
style={{ fontFamily: 'Roboto'}}
|
||||
>
|
||||
<input
|
||||
<Input
|
||||
prefix={<MailOutlined className="site-form-item-icon" />}
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
placeholder="Почта"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="password"
|
||||
rules={[{ required: true, message: 'Please input your password!' }]}
|
||||
style={{padding: '20px'}}
|
||||
rules={[{ required: true, message: 'Введите пароль!!' }, { min: 8, message: 'Пароль должен быть длиной минимум 8 символов' }]}
|
||||
style={{ fontFamily: 'Roboto'}}
|
||||
>
|
||||
<input
|
||||
<Input
|
||||
prefix={<LockOutlined className="site-form-item-icon" />}
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
placeholder="Пароль"
|
||||
/>
|
||||
<Button type='link' href=''>Забыли пароль?</Button>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Form.Item name="remember" valuePropName="checked" noStyle />
|
||||
<Button type="primary" className='bg-red-800 login-button hover:bg-transparent' htmlType="submit" style={{marginRight:'10px'}}>
|
||||
Войти
|
||||
</Button>
|
||||
<Checkbox style={{marginLeft:'10px'}}>Запомнить меня</Checkbox>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Form.Item name="submit" noStyle>
|
||||
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Form.Item name="noaccount" noStyle>
|
||||
<Link to={'../register'}>Нет аккаунта?</Link>
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
|
@ -1,7 +1,96 @@
|
||||
import { MailOutlined, LockOutlined } from "@ant-design/icons";
|
||||
import { Form, Input, Button, Checkbox } from "antd";
|
||||
import { Link } from "react-router-dom";
|
||||
import ReCAPTCHA from "react-google-recaptcha";
|
||||
import React, { useState } from "react";
|
||||
import FormItem from "antd/es/form/FormItem";
|
||||
|
||||
export function Registerpage() {
|
||||
const [verified, setVerified] = useState(false);
|
||||
function onChange(value: any) {
|
||||
console.log("Captcha value:", value);
|
||||
setVerified(true);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container mx-auto bg-slate-300" style={{height: 300, width: '75%'}}>
|
||||
<p>Регистрация</p>
|
||||
<div className="container mx-auto" style={{height: '200%', width: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
|
||||
<div className='login' >
|
||||
<Form>
|
||||
<p className='text-3xl' style={{ fontFamily: 'Roboto', marginTop: '100px', marginBottom: '50px'}}>Вход</p>
|
||||
<Form.Item style={{marginBottom: '50px'}}>
|
||||
<Form.Item
|
||||
name="email"
|
||||
rules={[{ required: true, message: 'Введите вашу почту!' }, { type: 'email', message: 'Некорректный формат' }]}
|
||||
style={{ fontFamily: 'Roboto'}}
|
||||
>
|
||||
<Input
|
||||
prefix={<MailOutlined className="site-form-item-icon" />}
|
||||
type="text"
|
||||
placeholder="Почта"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="password"
|
||||
rules={[{ required: true, message: 'Введите пароль!!' }, { min: 8, message: 'Пароль должен быть длиной минимум 8 символов' }]}
|
||||
style={{ fontFamily: 'Roboto'}}
|
||||
>
|
||||
<Input
|
||||
prefix={<LockOutlined className="site-form-item-icon" />}
|
||||
type="password"
|
||||
placeholder="Пароль"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="password2"
|
||||
rules={[{ required: true, message: 'Заполните поле!' }, ({ getFieldValue }) => ({
|
||||
validator(_, value) {
|
||||
if (value === getFieldValue('password')) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject('Пароли должны совпадать!');
|
||||
},
|
||||
})]}
|
||||
style={{ fontFamily: 'Roboto'}}
|
||||
>
|
||||
<Input
|
||||
prefix={<LockOutlined className="site-form-item-icon" />}
|
||||
type="password"
|
||||
placeholder="Повторите пароль"
|
||||
/>
|
||||
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<ReCAPTCHA
|
||||
sitekey={process.env.REACT_APP_RECAPTCHA_SITE_KEY as string}
|
||||
onChange={onChange}
|
||||
style={{marginTop: '10px'}}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Form.Item name="remember" valuePropName="checked" noStyle />
|
||||
<Button type="primary" disabled={!verified} className='bg-red-800 login-button hover:bg-transparent' htmlType="submit" style={{marginRight:'10px'} }>
|
||||
Регистрация
|
||||
</Button>
|
||||
<Checkbox style={{marginLeft:'10px'}}>Запомнить меня</Checkbox>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Form.Item name="submit" noStyle>
|
||||
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Form.Item name="noaccount" noStyle>
|
||||
<Link to={'../login'}>Уже есть аккаунт?</Link>
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
|
||||
</Form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
BIN
src/songs/Blur_-_Song_2_47967381.mp3
Normal file
BIN
src/songs/Blur_-_Song_2_47967381.mp3
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/songs/DSPD_-_Crazy_Frog_75801748.mp3
Normal file
BIN
src/songs/DSPD_-_Crazy_Frog_75801748.mp3
Normal file
Binary file not shown.
BIN
src/songs/Nirvana_-_Smells_Like_Teen_Spirit_75941061.mp3
Normal file
BIN
src/songs/Nirvana_-_Smells_Like_Teen_Spirit_75941061.mp3
Normal file
Binary file not shown.
BIN
src/songs/Noice_MC_-_Rugan_iz-za_steny_63872179.mp3
Normal file
BIN
src/songs/Noice_MC_-_Rugan_iz-za_steny_63872179.mp3
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user