add info and optimize rendering

This commit is contained in:
MathieuG-P
2022-11-14 00:24:43 +01:00
parent ef000b7eda
commit 5ba670505b
3 changed files with 87 additions and 43 deletions
@@ -5,12 +5,14 @@ import { BsmLink } from "../shared/bsm-link.component";
import { BsmIcon } from "../svgs/bsm-icon.component";
import { BsmButton } from "../shared/bsm-button.component";
import { AnimatePresence, motion } from "framer-motion";
import { useState } from "react";
import { useState, Fragment } from "react";
import { LinkOpenerService } from "renderer/services/link-opener.service";
import dateFormat from "dateformat";
import { AudioPlayerService } from "renderer/services/audio-player.service";
import { useObservable } from "renderer/hooks/use-observable.hook";
import { map } from "rxjs/operators";
import useDelayedState from "use-delayed-state";
import { v4 as uuidv4 } from 'uuid';
export type ParsedMapDiff = {type: BsvMapDifficultyType, name: string, stars: number}
@@ -42,8 +44,8 @@ export function MapItem({hash, title, autor, songAutor, coverUrl, songUrl, autor
const color = useThemeColor("first-color");
const [hovered, setHovered] = useState(false);
const [bottomBarHovered, setBottomBarHovered] = useState(false);
const [diffsPanelHovered, setDiffsPanelHoverd] = useState(false);
const [bottomBarHovered, setBottomBarHovered, cancelBottomBarHovered] = useDelayedState(false);
const [diffsPanelHovered, setDiffsPanelHovered] = useState(false);
const songPlaying = useObservable(audioPlayer.playing$.pipe(map(playing => playing && audioPlayer.src === songUrl)));
@@ -59,9 +61,12 @@ export function MapItem({hash, title, autor, songAutor, coverUrl, songUrl, autor
const date = new Date(0);
date.setSeconds(duration);
return duration > 3600 ? dateFormat(date, "h:MM:ss") : dateFormat(date, "MM:ss");
})()
})();
console.log(bottomBarHovered, diffsPanelHovered);
const parseDiffLabel = (diffLabel: string) => {
if(diffLabel === "ExpertPlus"){ return "Expert+" }
return diffLabel;
}
const openPreview = () => linkOpener.open(previewUrl, true);
const copyBsr = () => navigator.clipboard.writeText(`!bsr ${mapId}`);
@@ -75,6 +80,20 @@ export function MapItem({hash, title, autor, songAutor, coverUrl, songUrl, autor
audioPlayer.play(songUrl, bpm);
}
const bottomBarHoverStart = () => {
cancelBottomBarHovered();
setBottomBarHovered(true, (diffsPanelHovered || bottomBarHovered) ? 0 : 300);
}
const bottomBarHoverEnd = () => {
cancelBottomBarHovered();
setBottomBarHovered(false, 100);
}
const diffsPanelHoverStart = () => setDiffsPanelHovered(true);
const diffsPanelHoverEnd = () => setDiffsPanelHovered(false);
const renderDiffPreview = () => {
const diffSets = Array.from(diffs.entries());
@@ -87,7 +106,7 @@ export function MapItem({hash, title, autor, songAutor, coverUrl, songUrl, autor
<BsmIcon className="h-4 w-4 mr-px" icon="bsMapDifficulty"/>
<div className="flex py-[2px] gap-[1px] h-full">
{diffSet.map(diff => (
<span key={diff.type} className="h-full w-[6px] brightness-200 saturate-150 rounded-full" style={{backgroundColor: diffColors[diff.type]}}/>
<span key={diff.type} className="h-full w-[6px] rounded-full" style={{backgroundColor: diffColors[diff.type]}}/>
))}
</div>
</>
@@ -95,35 +114,52 @@ export function MapItem({hash, title, autor, songAutor, coverUrl, songUrl, autor
}
if(diffSets.length > 1){
return diffSets.map(([diffType, diffSet]) => (
<>
<Fragment key={uuidv4()}>
<BsmIcon className="h-full w-fit mr-px" icon={diffType}/>
<span className="mr-2 font-bold text-[15px] h-full flex items-center pb-px">{diffSet.length}</span>
</>
</Fragment>
));
}
}
console.log(coverUrl);
return (
<motion.li className="relative h-[100px] min-w-[400px] shrink grow basis-0 text-white group" onHoverStart={() => setHovered(true)} onHoverEnd={() => setHovered(false)} style={{zIndex: (bottomBarHovered || diffsPanelHovered) && 5}}>
<motion.li className="relative h-[100px] min-w-[400px] shrink grow basis-0 text-white group" onHoverStart={() => setHovered(true)} onHoverEnd={() => setHovered(false)} style={{zIndex: hovered && 5}}>
<AnimatePresence>
{(diffsPanelHovered || bottomBarHovered) && (
<motion.div className="absolute w-full top-[calc(100%-10px)] h-fit bg-main-color-3 brightness-125 rounded-md pointer-events-auto" onHoverStart={() => setDiffsPanelHoverd(true)} onHoverEnd={() => setDiffsPanelHoverd(false)}>
aaeaze<br/>azeaze
</motion.div>
<motion.ul key={hash} className="absolute top-[calc(100%-10px)] w-full h-fit max-h-[200%] pt-4 pb-2 px-2 overflow-y-scroll bg-main-color-3 brightness-125 rounded-md flex flex-col gap-3 scrollbar-thin scrollbar-thumb-rounded-full scrollbar-thumb-neutral-900 shadow-sm shadow-black" initial={{opacity: 0}} animate={{opacity: 1}} exit={{opacity: 0}} transition={{duration: .15}} onHoverStart={diffsPanelHoverStart} onHoverEnd={diffsPanelHoverEnd}>
{Array.from(diffs.entries()).map(([charac, diffSet]) => (
<ol key={uuidv4()} className="flex flex-col w-full gap-1">
{diffSet.map(({type, name, stars}) => (
<li key={`${type}${name}${stars}`} className="w-full h-4 flex items-center gap-1">
<BsmIcon className="h-full w-fit p-px" icon={charac}/>
<span className="h-full px-2 flex items-center text-xs font-bold bg-current rounded-full" style={{color: diffColors[type]}}>
{
stars ? (
<span className="h-full block brightness-[.25]"> {stars}</span>
) : (
<span className="h-full brightness-[.25] leading-4 pb-[2px]">{parseDiffLabel(type)}</span>
)
}
</span>
<span className="text-sm leading-4 pb-[2px]">{parseDiffLabel(name)}</span>
</li>
))}
</ol>
))}
</motion.ul>
)}
</AnimatePresence>
<div className="h-full w-full relative pl-[100px] rounded-md overflow-hidden flex flex-row justify-end">
<div className="absolute top-0 left-0 h-full aspect-square">
<div className="absolute top-0 left-0 h-full aspect-square cursor-pointer">
<BsmImage image={coverUrl}/>
<span className="absolute flex justify-center items-center w-full h-full pr-1 bg-transparent top-0 left-0 group-hover:bg-black group-hover:bg-opacity-40" style={{color}} onClick={(e) => {e.stopPropagation(); toogleMusic()}}>
<BsmIcon className="w-full h-full p-7 opacity-0 group-hover:opacity-100 text-white hover:text-current" icon={songPlaying ? "pause" : "play"}/>
</span>
</div>
<div className="h-full w-full z-[1] rounded-md overflow-hidden -translate-x-1" style={{backgroundImage: `url('${coverUrl}')`, backgroundPosition: "center", backgroundSize: "cover"}}>
<div className="relative h-full w-full z-[1] rounded-md overflow-hidden -translate-x-1">
<BsmImage className="absolute top-0 left-0 w-full h-full -z-[1] object-cover" image={coverUrl}/>
<div className="pt-1 pl-2 pr-7 top-0 left-0 w-full h-full bg-gray-600 bg-opacity-80 flex flex-col justify-between group-hover:bg-main-color-1 group-hover:bg-opacity-80">
<h1 className="font-bold whitespace-nowrap text-ellipsis overflow-hidden w-full leading-5 tracking-wide text-lg"><BsmLink className="hover:underline" href={mapUrl}>{title}</BsmLink></h1>
<h1 className="font-bold whitespace-nowrap text-ellipsis overflow-hidden w-full leading-5 tracking-wide text-lg" title={title}><BsmLink className="hover:underline" href={mapUrl}>{title}</BsmLink></h1>
<h2 className="font-bold whitespace-nowrap text-ellipsis overflow-hidden w-full text-sm mb-[3px]">par {songAutor}</h2>
<h3 className="font-bold whitespace-nowrap text-ellipsis overflow-hidden w-full text-xs">{autor && (<> mappée par <BsmLink href={authorUrl} className="brightness-150 saturate-50 hover:underline" style={{color}}>{autor}</BsmLink></>)}</h3>
<div className="w-full h-4 text-xs gap-2 flex opacity-0 group-hover:opacity-100">
@@ -146,35 +182,37 @@ export function MapItem({hash, title, autor, songAutor, coverUrl, songUrl, autor
</div>
)}
</div>
<motion.div className="w-full h-5 pb-1 pr-7 flex items-center gap-1" onHoverStart={() => setBottomBarHovered(true)} onHoverEnd={() => setBottomBarHovered(false)}>
<div className="text-yellow-300 bg-current rounded-full px-1 h-full flex items-center justify-center">
<span className="uppercase text-xs font-bold tracking-wide brightness-[.25]">classée</span>
</div>
<motion.div className="w-full h-5 pb-1 pr-7 flex items-center gap-1" onHoverStart={bottomBarHoverStart} onHoverEnd={bottomBarHoverEnd}>
{ranked && (
<div className="text-yellow-300 bg-current rounded-full px-1 h-full flex items-center justify-center">
<span className="uppercase text-xs font-bold tracking-wide brightness-[.25]">classée</span>
</div>
)}
<div className="h-full grow flex items-start content-start">
{renderDiffPreview()}
</div>
</motion.div>
</div>
</div>
<motion.div className="absolute bg-main-color-3 top-0 right-0 h-full z-[1]" initial={{width: "8px"}} animate={{width: hovered ? "30px" : "8px"}}>
<div className="absolute bg-main-color-3 top-0 right-0 h-full z-[1] w-[30px] translate-x-5 group-hover:translate-x-0 transition-transform">
<span className="absolute w-[10px] h-[10px] top-0 right-full bg-inherit" style={{clipPath: 'path("M11 -1 L11 10 L10 10 A10 10 0 0 0 0 0 L0 -1 Z")'}}/>
<span className="absolute w-[10px] h-[10px] bottom-0 right-full bg-inherit" style={{clipPath: 'path("M11 11 L11 0 L10 0 A10 10 0 0 1 0 10 L 0 11 Z")'}}/>
<div className="flex flex-col justify-center items-center gap-1 w-full h-full overflow-hidden transition-opacity" style={{opacity: hovered ? 1 : 0}}>
<div className="flex flex-col justify-center items-center gap-1 w-full h-full overflow-hidden transition-opacity opacity-0 group-hover:opacity-100">
{onDelete && <BsmButton className="w-6 h-6 p-[2px] rounded-md !bg-inherit hover:!bg-main-color-2" iconClassName="w-full h-full brightness-150 saturate-50" iconColor={color} icon="trash" withBar={false} onClick={e => {e.stopPropagation(); openPreview()}}/>}
<BsmButton className="w-6 h-6 p-[2px] rounded-md !bg-inherit hover:!bg-main-color-2" iconClassName="w-full h-full brightness-150 saturate-50" iconColor={color} icon="eye" withBar={false} onClick={e => {e.stopPropagation(); openPreview()}}/>
{mapId && <BsmButton className="w-6 h-6 p-1 rounded-md !bg-inherit hover:!bg-main-color-2" iconClassName="w-full h-full brightness-150 saturate-50" iconColor={color} icon="twitch" withBar={false} onClick={e => {e.stopPropagation(); copyBsr()}}/>}
</div>
</motion.div>
</div>
</div>
</motion.li>
)
}
const diffColors: Record<BsvMapDifficultyType, string> = {
Easy: "#008055",
Normal: "#1268a1",
Hard: "#bd5500",
Expert: "#b52a1c",
ExpertPlus: "#7646af"
Easy: "#00FF9E",
Normal: "#00FFFF",
Hard: "#FFA700",
Expert: "#FF4319",
ExpertPlus: "#FF7EFF"
}