Files
beatconnect_client/src/App/modules/common/Beatmap/index.js
T
2023-01-06 20:28:00 +01:00

167 lines
5.2 KiB
JavaScript

/* eslint-disable camelcase */
import React, { useState, memo, useRef } from 'react';
import { shell } from 'electron';
import { createUseStyles, useTheme } from 'react-jss';
import Cover from './Cover';
import DownloadBeatmapBtn from './DownloadBeatmapBtn';
import PreviewBeatmapBtn from './PreviewBeatmapBtn';
import renderIcons from '../../../helpers/renderIcons';
import getBeatmapInfosUrl from '../../../helpers/getBeatmapInfosUrl';
import Button from '../Button';
import SetWallpaperButton from './SetWallpaperButton';
import Modes from './Modes';
const bpmToBps = bpm => 60 / bpm;
const useStyles = createUseStyles({
Beatmap: {
zIndex: 1,
position: 'relative',
fontSize: '14px',
color: 'white',
width: ({ width }) => width || '80%',
background: ({ theme }) => theme.palette.primary.main,
margin: ({ margin }) => margin || '1.3vh auto',
paddingBottom: '10px',
borderRadius: '5px',
transition: ({ bpm }) => `opacity ${bpmToBps(bpm)}s`,
'&:hover': {
opacity: 1.1,
'&::after': {
opacity: 0.7,
},
},
'& > div': {
justifyContent: 'center',
},
'& p': {
margin: 0,
},
'&::before, &::after': {
zIndex: -1,
position: 'absolute',
content: "''",
height: '100%',
width: '100%',
borderRadius: '8px',
top: '0%',
left: '0%',
boxShadow: '0 0 15px #287ec6',
filter: 'blur(1px)',
animation: ({ bpm, isPlaying }) => (isPlaying ? `$pulse ${bpmToBps(bpm)}s linear infinite` : `none`),
opacity: ({ isPlaying }) => (isPlaying ? 1 : 0),
transitionDuration: '.5s',
transitionDelay: '.2s',
transitionProperty: 'transform, opacity',
transitionTimingFunction: 'ease-out',
},
},
MainInformationsContainer: {
padding: '0 2%',
margin: '7px 0',
},
TextElipsis: {
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
maxWidth: '100%',
},
Row: {
display: 'flex',
alignItems: 'center',
},
'@keyframes pulse': {
'0%': {
opacity: 0.1,
transform: 'scale(.990)',
},
'60%': {
transform: 'scale(0.995)',
opacity: 0.65,
},
'100%': {
transform: 'scale(1.010)',
opacity: 0,
},
},
});
const Beatmap = ({ beatmap, noFade, autoDl, width, ...otherProps }) => {
const ref = useRef();
const theme = useTheme();
const [isPlaying, setIsPLaying] = useState(false);
const { beatmapset_id, id, title, artist, creator, version, bpm, beatconnectDlLink, beatmaps } = beatmap;
// beatmap.beatmap_id only when beatmap comes from mpMatch (for bot displays)
const wallpaperBeatmapId = beatmaps ? beatmaps[Math.max(beatmaps.length - 2, 0)].id : beatmap.beatmap_id;
const classes = useStyles({ width, theme, isPlaying, bpm: beatmap.bpm, ...otherProps });
return (
<div className={classes.Beatmap} ref={ref}>
{beatmap && (
<>
<Cover
url={`https://assets.ppy.sh/beatmaps/${beatmapset_id || id}/covers/cover.jpg`}
height={130}
noFade={noFade}
roundedTop
beatmapSet={beatmap}
parentRef={ref}
/>
<div className="leftContainer" style={{ position: 'absolute', left: '2%', bottom: '3%', maxWidth: '25%' }}>
<p className={classes.Row} title={creator}>
{renderIcons({ name: 'Creator', color: 'white' })}
<span style={{ marginLeft: '2px' }} className={classes.TextElipsis}>
{creator}
</span>
</p>
<p className={classes.Row} style={{ marginLeft: '-2px' }} title={bpm}>
{renderIcons({ name: 'Metronome', color: 'white' })}
<span color="white" style={{ marginLeft: '3px' }}>
{bpm}
</span>
</p>
</div>
<div className={classes.MainInformationsContainer}>
<p title={title} className={classes.TextElipsis}>
{title}
</p>
<p title={artist} className={classes.TextElipsis}>
{artist}
</p>
</div>
{version && <p>{`[${version || ''}]`}</p>}
<PreviewBeatmapBtn
theme={theme}
beatmapSetId={beatmapset_id || id}
setIsPLaying={setIsPLaying}
title={title}
artist={artist}
/>
<DownloadBeatmapBtn autoDl={autoDl} beatmapSet={beatmap} />
<Button
color={theme.palette.primary.accent}
onClick={() => shell.openExternal(getBeatmapInfosUrl(beatmap))}
hidden={!beatmap.title}
>
{renderIcons({ name: 'Search', style: theme.accentContrast })}
</Button>
<SetWallpaperButton beatmapSetId={beatmapset_id || id} beatmapId={wallpaperBeatmapId} />
<Modes ctb={beatmap.mode_ctb} std={beatmap.mode_std} mania={beatmap.mode_mania} taiko={beatmap.mode_taiko} />
</>
)}
</div>
);
};
const areEqual = (prevProps, nextProps) => {
if (prevProps.beatmap.beatmapset_id) {
return prevProps.beatmap.beatmapset_id === nextProps.beatmap.beatmapset_id;
}
if (prevProps.beatmap.id) {
return prevProps.beatmap.id === nextProps.beatmap.id;
}
return false;
};
export default memo(Beatmap, areEqual);