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
+19 -14
View File
@@ -1713,7 +1713,7 @@
},
"@types/plist": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@types%2fplist/-/plist-3.0.2.tgz",
"resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.2.tgz",
"integrity": "sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==",
"dev": true,
"optional": true,
@@ -1878,7 +1878,7 @@
},
"@types/verror": {
"version": "1.10.6",
"resolved": "https://registry.npmjs.org/@types%2fverror/-/verror-1.10.6.tgz",
"resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.6.tgz",
"integrity": "sha512-NNm+gdePAX1VGvPcGZCDKQZKYSiAWigKhKaz5KF94hG6f2s8de9Ow5+7AbXoeKxL8gavZfk4UquSAygOF2duEQ==",
"dev": true,
"optional": true
@@ -2721,7 +2721,7 @@
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
"dev": true,
"optional": true
},
@@ -3146,13 +3146,13 @@
"buffer-equal": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz",
"integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=",
"integrity": "sha512-tcBWO2Dl4e7Asr9hTGcpVrCe+F7DubpmqWCTbj4FHLmjqO2hIaC383acQubWtRJhdceqs5uBHs6Es+Sk//RKiQ==",
"dev": true
},
"buffer-fill": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
"integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=",
"integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==",
"dev": true
},
"buffer-from": {
@@ -3449,7 +3449,7 @@
"chromium-pickle-js": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz",
"integrity": "sha1-BKEGZywYsIWrd02YPfo+oTjyIgU=",
"integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==",
"dev": true
},
"ci-info": {
@@ -3615,7 +3615,7 @@
"colors": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
"integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=",
"integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==",
"dev": true
},
"combined-stream": {
@@ -3642,7 +3642,7 @@
"compare-version": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz",
"integrity": "sha1-AWLsLZNR9d3VmpICy6k1NmpyUIA=",
"integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==",
"dev": true
},
"compress-brotli": {
@@ -4440,7 +4440,7 @@
"commander": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
"integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
"integrity": "sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A==",
"dev": true,
"requires": {
"graceful-readlink": ">= 1.0.0"
@@ -4893,7 +4893,7 @@
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"dev": true
}
}
@@ -6865,7 +6865,7 @@
"graceful-readlink": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
"integrity": "sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==",
"dev": true
},
"grapheme-splitter": {
@@ -12257,7 +12257,7 @@
"truncate-utf8-bytes": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
"integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=",
"integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==",
"dev": true,
"requires": {
"utf8-byte-length": "^1.0.1"
@@ -12558,6 +12558,11 @@
"prepend-http": "^2.0.0"
}
},
"use-delayed-state": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/use-delayed-state/-/use-delayed-state-1.2.0.tgz",
"integrity": "sha512-i/7nyyHZsJ+2qGwbb9XGTViBDs43j/57pxdbhbyhTD6XNTzqCvaZQSfIa/SLAGR7eFPK9+UV62Dfzia/aYdwPw=="
},
"use-double-click": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/use-double-click/-/use-double-click-1.0.5.tgz",
@@ -12566,7 +12571,7 @@
"utf8-byte-length": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",
"integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E=",
"integrity": "sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA==",
"dev": true
},
"util-deprecate": {
@@ -12635,7 +12640,7 @@
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
"dev": true,
"optional": true
}
+1
View File
@@ -248,6 +248,7 @@
"semver": "^7.3.8",
"tailwind-scrollbar-hide": "^1.1.7",
"tailwindcss-scoped-groups": "^2.0.0",
"use-delayed-state": "^1.2.0",
"use-double-click": "^1.0.5",
"uuid": "^9.0.0"
},
@@ -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"
}