missing icons and add difficulties

This commit is contained in:
MathieuG-P
2022-11-13 02:14:53 +01:00
parent 4c36f2321a
commit 8217a577a0
14 changed files with 197 additions and 31 deletions
@@ -4,7 +4,7 @@ import VisibilitySensor from "react-visibility-sensor"
import { useEffect, useState } from "react"
import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface"
import { Subscription } from "rxjs"
import { MapItem, MapItemProps } from "./map-item.component"
import { MapItem, MapItemProps, ParsedMapDiff } from "./map-item.component"
import { BsvMapCharacteristic, BsvMapDifficultyType } from "shared/models/maps/beat-saver.model"
type Props = {
@@ -30,12 +30,12 @@ export function LocalMapsListPanel({version, className} : Props) {
return () => { subs.forEach(s => s.unsubscribe()); }
}, [isVisible])
const extractMapDiffs = (map: BsmLocalMap): Map<BsvMapCharacteristic, BsvMapDifficultyType[]> => {
const res = new Map<BsvMapCharacteristic, BsvMapDifficultyType[]>();
const extractMapDiffs = (map: BsmLocalMap): Map<BsvMapCharacteristic, ParsedMapDiff[]> => {
const res = new Map<BsvMapCharacteristic, ParsedMapDiff[]>();
map.rawInfo._difficultyBeatmapSets.forEach(set => {
set._difficultyBeatmaps.forEach(diff => {
const arr = res.get(set._beatmapCharacteristicName) || [];
arr.push(diff._difficulty);
arr.push({name: diff._customData?._difficultyLabel || diff._difficulty, type: diff._difficulty, stars: null});
res.set(set._beatmapCharacteristicName, arr);
})
})
@@ -4,7 +4,7 @@ import { useThemeColor } from "renderer/hooks/use-theme-color.hook";
import { BsmLink } from "../shared/bsm-link.component";
import { BsmIcon } from "../svgs/bsm-icon.component";
import { BsmButton } from "../shared/bsm-button.component";
import { motion } from "framer-motion";
import { AnimatePresence, motion } from "framer-motion";
import { useState } from "react";
import { LinkOpenerService } from "renderer/services/link-opener.service";
import dateFormat from "dateformat";
@@ -12,6 +12,8 @@ import { AudioPlayerService } from "renderer/services/audio-player.service";
import { useObservable } from "renderer/hooks/use-observable.hook";
import { map } from "rxjs/operators";
export type ParsedMapDiff = {type: BsvMapDifficultyType, name: string, stars: number}
export type MapItemProps = {
hash: string,
title: string,
@@ -21,7 +23,7 @@ export type MapItemProps = {
songUrl: string,
autorId: number,
mapId: string,
diffs: Map<BsvMapCharacteristic, BsvMapDifficultyType[]>,
diffs: Map<BsvMapCharacteristic, ParsedMapDiff[]>,
qualified: boolean,
ranked: boolean,
bpm: number,
@@ -40,8 +42,10 @@ 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 songPlaying = useObservable(audioPlayer.playing$.pipe(map(playing => playing && audioPlayer.src === songUrl ? true : false)));
const songPlaying = useObservable(audioPlayer.playing$.pipe(map(playing => playing && audioPlayer.src === songUrl)));
const zipUrl = `https://r2cdn.beatsaver.com/${hash}.zip`;
const previewUrl = `https://skystudioapps.com/bs-viewer/?url=${zipUrl}`;
@@ -57,13 +61,7 @@ export function MapItem({hash, title, autor, songAutor, coverUrl, songUrl, autor
return duration > 3600 ? dateFormat(date, "h:MM:ss") : dateFormat(date, "MM:ss");
})()
console.log(hash);
const openMapPage = () => {
if(mapUrl){
linkOpener.open(mapUrl)
}
}
console.log(bottomBarHovered, diffsPanelHovered);
const openPreview = () => linkOpener.open(previewUrl, true);
const copyBsr = () => navigator.clipboard.writeText(`!bsr ${mapId}`);
@@ -76,42 +74,86 @@ export function MapItem({hash, title, autor, songAutor, coverUrl, songUrl, autor
}
audioPlayer.play(songUrl, bpm);
}
const renderDiffPreview = () => {
const diffSets = Array.from(diffs.entries());
if(diffSets.length === 1){
const [diffType, diffSet] = diffSets[0];
return (
<>
<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]}}/>
))}
</div>
</>
)
}
if(diffSets.length > 1){
return diffSets.map(([diffType, diffSet]) => (
<>
<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>
</>
));
}
}
console.log(coverUrl);
return (
<motion.li className="h-[100px] min-w-[400px] shrink grow basis-0 text-white group cursor-pointer" onHoverStart={() => setHovered(true)} onHoverEnd={() => setHovered(false)} onClick={openMapPage}>
<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}}>
<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>
)}
</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">
<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="play"/>
<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] relative rounded-md overflow-hidden -translate-x-1">
<BsmImage className="absolute w-full h-full object-cover" image={coverUrl}/>
<div className="absolute py-1 pl-2 pr-7 top-0 left-0 w-full h-full bg-gray-600 bg-opacity-80 flex flex-col 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">{title}</h1>
<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="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>
<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">mappée par <BsmLink href={authorUrl} className="brightness-150 saturate-50 hover:underline" style={{color}}>{autor}</BsmLink></h3>
<div className="w-full h-[15px] text-xs gap-2 hidden group-hover:flex">
<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">
{likesText && (
<div className="h-full flex items-center">
<BsmIcon className="h-[12px] w-fit shrink-0 mr-1" icon="trash"/>
<BsmIcon className="h-full py-[2px] w-fit shrink-0 mr-1" icon="thumbUpFill"/>
<span className="mb-[2px]">{likesText}</span>
</div>
)}
{durationText && (
<div className="h-full flex items-center">
<BsmIcon className="h-[12px] w-fit shrink-0 mr-1" icon="trash"/>
<BsmIcon className="h-full py-[2px] w-fit shrink-0 mr-1" icon="timerFill"/>
<span className="mb-[2px]">{durationText}</span>
</div>
)}
{createdAt && (
<div className="h-full flex items-center">
<BsmIcon className="h-[12px] w-fit shrink-0 mr-1" icon="trash"/>
<BsmIcon className="h-full py-[2px] w-fit shrink-0 mr-1" icon="checkCircleIcon"/>
<time className="mb-[2px]">{createdDate}</time>
</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>
<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"}}>
@@ -125,7 +167,6 @@ export function MapItem({hash, title, autor, songAutor, coverUrl, songUrl, autor
</div>
</motion.div>
</div>
</motion.li>
)
}
@@ -28,10 +28,21 @@ import { BsMapDifficultyIcon } from "./icons/bs-map-difficulty-icon.component";
import { TwitchIcon } from "./icons/twitch-icon.component";
import EyeIcon from "./icons/eye-icon.component";
import { PlayIcon } from "./icons/play-icon.component";
import { ThumbUpFillIcon } from "./icons/thumb-up-fill-icon.component";
import { TimerFillIcon } from "./icons/timer-fill.component";
import { CheckCircleIcon } from "./icons/check-circle-icon.component";
import { PauseIcon } from "./icons/pause-icon.component";
import { BsvMapCharacteristic } from "shared/models/maps/beat-saver.model";
import { LightshowIcon } from "./icons/lightshow-icon.component";
import { LawlessIcon } from "./icons/lawless-icon.component";
import { NoArrowIcon } from "./icons/no-arrow-icon.component";
import { OneSaberIcon } from "./icons/one-saber-icon.component";
import { NinetyDregreeIcon } from "./icons/ninety-dregree-icon.component";
import { ThreeSixtyDegreeIcon } from "./icons/three-sixty-degree-icon.component";
export type BsmIconType = (
"settings"|"trash"|"favorite"|"folder"|"bsNote"|"check"|"three-dots"|"twitch"|"eye"|"play"|
"terminal"|"desktop"|"oculus"|"add"|"cross"|"task"|"github"|"close"|
export type BsmIconType = BsvMapCharacteristic | (
"settings"|"trash"|"favorite"|"folder"|"bsNote"|"check"|"three-dots"|"twitch"|"eye"|"play"|"checkCircleIcon"|
"terminal"|"desktop"|"oculus"|"add"|"cross"|"task"|"github"|"close"|"thumbUpFill"|"timerFill"|"pause"|
"copy"|"steam"|"edit"|"export"|"patreon"|"search"|"bsMapDifficulty"|
"fr-FR-flag"|"es-ES-flag"|"en-US-flag"|"en-EN-flag"
);
@@ -64,10 +75,20 @@ export const BsmIcon = memo(({className, icon, style}: {className?: string, icon
if(icon === "three-dots"){ return <ThreeDotsIcon className={className} style={style}/> }
if(icon === "github"){ return <GitHubIcon className={className} style={style}/> }
if(icon === "close"){ return <CloseIcon className={className} style={style}/> }
if(icon === "bsMapDifficulty"){ return <BsMapDifficultyIcon className={className} style={style}/> }
if(icon === "bsMapDifficulty" || icon === "Standard"){ return <BsMapDifficultyIcon className={className} style={style}/> }
if(icon === "twitch"){ return <TwitchIcon className={className} style={style}/> }
if(icon === "eye"){ return <EyeIcon className={className} style={style}/> }
if(icon === "play"){ return <PlayIcon className={className} style={style}/> }
if(icon === "thumbUpFill"){ return <ThumbUpFillIcon className={className} style={style}/> }
if(icon === "timerFill"){ return <TimerFillIcon className={className} style={style}/> }
if(icon === "checkCircleIcon"){ return <CheckCircleIcon className={className} style={style}/> }
if(icon === "pause"){ return <PauseIcon className={className} style={style}/> }
if(icon === "Lawless"){ return <LawlessIcon className={className} style={style}/> }
if(icon === "NoArrows"){ return <NoArrowIcon className={className} style={style}/> }
if(icon === "OneSaber"){ return <OneSaberIcon className={className} style={style}/> }
if(icon === "Lightshow"){ return <LightshowIcon className={className} style={style}/> }
if(icon === "90Degree"){ return <NinetyDregreeIcon className={className} style={style}/> }
if(icon === "360Degree"){ return <ThreeSixtyDegreeIcon className={className} style={style}/> }
return <TrashIcon className={className} style={style}/>
}
@@ -0,0 +1,9 @@
import { CSSProperties } from "react";
export function CheckCircleIcon(props: {className?: string, style?: CSSProperties}) {
return (
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" height="40" width="40" viewBox="0 0 40 40" fill="currentColor">
<path d="m17.542 23.25-3.709-3.708q-.458-.459-1.104-.459-.646 0-1.104.459-.458.458-.458 1.146 0 .687.416 1.145l4.875 4.834q.417.416 1.084.416.666 0 1.125-.416l9.708-9.709q.417-.458.417-1.104 0-.646-.459-1.104-.458-.458-1.145-.458-.688 0-1.146.458ZM20 36.958q-3.583 0-6.667-1.312-3.083-1.313-5.375-3.604-2.291-2.292-3.604-5.375Q3.042 23.583 3.042 20q0-3.542 1.312-6.646 1.313-3.104 3.604-5.375 2.292-2.271 5.375-3.604Q16.417 3.042 20 3.042q3.542 0 6.646 1.333t5.375 3.604q2.271 2.271 3.604 5.375 1.333 3.104 1.333 6.646 0 3.583-1.333 6.667-1.333 3.083-3.604 5.375-2.271 2.291-5.375 3.604-3.104 1.312-6.646 1.312Z"/>
</svg>
)
}
@@ -0,0 +1,10 @@
import { CSSProperties } from 'react'
export function LawlessIcon(props: {className?: string, style?: CSSProperties}) {
return (
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="1280" height="1280" viewBox="0 0 1280 1280" fill="currentColor">
<path d="M639.63,931.84c-32.42,0-64.85,0.01-97.27,0c-49.35-0.02-91.47-40.08-94.1-89.41 c-0.23-4.24-0.68-8.49-1.24-12.7c-2.09-15.62-8.63-23.1-24.53-24.41c-22.41-1.84-43.94-5.51-62.46-19.39 c-25.42-19.04-40.52-43.98-39.39-76.17c0.66-18.65-4.31-34.83-11.99-51.32c-26.74-57.41-47.22-117.1-51.51-180.6 c-6.77-100.1,19.79-189.66,91.12-263.06c67.86-69.83,152.88-103.69,247.85-113.16c97.36-9.71,189.34,9.89,272.44,62.65 c101.84,64.65,154.46,157.75,155.77,279.06c0.74,69.03-18.74,133.48-44.27,196.55c-5.26,13-12.77,25.23-16.73,38.57 c-3.05,10.29-2.68,21.75-2.92,32.7c-0.47,22.04-6.94,41.84-20.71,59.07c-17.3,21.65-40.59,31.48-67.65,33.62 c-0.85,0.07-1.71-0.01-2.56,0.02c-27.51,1.05-35.9,8.81-37.05,36.03c-0.87,20.78-7.73,39.17-20.44,55.24 c-18.74,23.7-43.11,36.72-73.81,36.72C705.33,931.84,672.48,931.84,639.63,931.84z M480.05,675.84c54.01,0,96.15-41.51,96.22-94.81 c0.08-54.41-41.23-95.84-93.84-97.55c-53.66-1.74-99.41,45.06-98.41,95.82C385.11,633.95,425.78,675.84,480.05,675.84z M800.21,483.84c-53.87,0-95.87,41.64-95.93,95.11c-0.06,54.3,41.34,95.6,94.14,97.25c53.21,1.66,99.2-44.9,98.12-96.11 C895.39,525.54,854.69,483.84,800.21,483.84z M640.62,775.21c3.39,5.64,6,11.05,9.59,15.72c9.19,11.96,24.81,16.36,37.63,11.13 c11.95-4.87,18.72-15.54,16.14-31.29c-6.07-37-23.41-67.85-53.77-90.78c-6.73-5.08-12.97-5.26-19.7-0.1 c-30.87,23.65-49.06,54.84-53.97,93.24c-1.86,14.55,4.56,24.54,16.05,28.77c12.63,4.65,24.61,2.59,34.06-7.2 C631.85,789.29,635.55,782.41,640.62,775.21z"/>
<path d="M1236.1,788.03L1236.1,788.03c-10.85-23.21-38.46-33.24-61.67-22.39l-533.92,249.47L106.75,766.76 c-23.23-10.81-50.82-0.74-61.63,22.49l0,0c-10.81,23.23-0.74,50.82,22.49,61.63l463.17,215.5l-12.54,5.86l-2.58-5.53L290.31,1172 l43.52,93.13l225.34-105.29l-1.66-3.55l83.09-38.82l82.58,38.42l-1.96,4.21l225.51,104.93l43.37-93.2l-225.51-104.93l-2.27,4.87 l-11.98-5.57l463.37-216.51C1236.92,838.85,1246.95,811.24,1236.1,788.03z"/>
</svg>
)
}
@@ -0,0 +1,10 @@
import { CSSProperties } from 'react'
export function LightshowIcon(props: {className?: string, style?: CSSProperties}) {
return (
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="1280" height="1280" viewBox="0 0 1280 1280" fill='currentColor'>
<path d="M1214.77,1060.46L345.4,323.04c-10.53-8.93-26.3-7.63-35.23,2.89l0,0c-8.93,10.53-7.63,26.3,2.89,35.23 l760.31,644.9C1001.05,989.8,914.14,981,823,981c-112.48,0-218.54,13.4-298.65,37.72c-46.18,14.02-81.2,30.97-104.39,50.3 L231.57,407.7c-3.78-13.28-17.61-20.97-30.89-17.19c-13.28,3.78-20.97,17.61-17.19,30.89l200.62,704.3c0.58,2.03,1.39,3.92,2.4,5.67 c0.77,45.1,48.38,83.26,137.83,110.42c80.11,24.32,186.17,37.72,298.65,37.72s218.54-13.4,298.65-37.72 c90.18-27.38,137.85-65.95,137.85-111.53C1259.5,1104.5,1244.28,1080.98,1214.77,1060.46z M1107.71,1195.85 C1032,1218.84,930.88,1231.5,823,1231.5s-209-12.66-284.71-35.65c-71.7-21.77-103.79-48.63-103.79-65.6s32.09-43.83,103.79-65.6 C614,1041.66,715.12,1029,823,1029s209,12.66,284.71,35.65c28.28,8.59,50.4,17.97,66.82,27.22l16.4,13.91 c3,2.55,6.43,4.26,10.01,5.16c7.13,7.14,10.57,13.75,10.57,19.3C1211.5,1147.22,1179.41,1174.08,1107.71,1195.85z"/>
<path d="M314.38,157.41l-68.74-4.95l-63.09-91.22c-10.96-15.12-28.15-24.07-46.59-27.02 c-18.44-2.95-36.92,1.47-52.04,12.42l-41.81,30.3C10.9,99.56,3.9,143.36,26.52,174.58l58.98,83.44l-22.94,71 c-4.11,12.71,2.87,26.35,15.58,30.46h0c12.71,4.11,26.35-2.87,30.46-15.58l19.07-59.03l17.54,38.17c3.17,6.88,9.46,12.2,16.83,14.24 c2.25,0.62,4.53,0.93,6.8,0.93c5,0,9.91-1.48,14.12-4.36l85.76-58.73c8.29-6.13,12.84-7.92,15.24-13.3l0.98-2.22 c3.7-8.37,1.51-18.17-5.4-24.17l-1.31-1.13l-34.56-33.48l67.24,4.84c13.32,0.96,24.9-9.07,25.86-22.39v0 C337.73,169.95,327.71,158.37,314.38,157.41z M70.24,115.78l41.81-30.3c3.79-2.75,8.25-4.18,12.84-4.18c1.16,0,2.34,0.09,3.51,0.28 c5.79,0.92,10.88,4.05,14.32,8.8l50.4,73.24l-74.59,56.23l-53.19-73.4C58.24,136.64,60.44,122.88,70.24,115.78z M177.86,279.16 l-13.44-29.26l35.11-25l23.84,23.09L177.86,279.16z"/>
</svg>
)
}
@@ -0,0 +1,12 @@
import { CSSProperties } from 'react'
export function NinetyDregreeIcon(props: {className?: string, style?: CSSProperties}) {
return (
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="1280" height="1280" viewBox="0 0 1280 1280" fill="currentColor">
<g>
<path d="M386.25,168.31h112.6c72.4,0,108.61,49.2,108.61,147.59v645.51c0,98.39-36.21,147.59-108.61,147.59H390.23 c-72.41,0-108.61-49.2-108.61-147.59V819.79h112.6v117.77c0,15.91,1.99,26.6,5.98,32.05c3.99,5.47,11.29,8.2,21.92,8.2h44.84 c10.62,0,17.94-2.73,21.92-8.2c3.99-5.45,5.98-16.14,5.98-32.05V730.34H386.25c-72.41,0-108.61-49.2-108.61-147.59V315.9 C277.64,217.51,313.84,168.31,386.25,168.31z M418.14,606.6h76.73V339.75c0-15.89-1.99-26.58-5.98-32.05 c-3.99-5.45-11.3-8.2-21.92-8.2h-48.83c-10.63,0-17.94,2.75-21.92,8.2c-3.99,5.47-5.98,16.17-5.98,32.05v226.6 c0,15.91,1.99,26.6,5.98,32.05C400.2,603.88,407.5,606.6,418.14,606.6z"/>
<path d="M1013,315.9v645.51c0,98.39-36.21,147.59-108.61,147.59H788.8c-72.41,0-108.61-49.2-108.61-147.59V315.9 c0-98.39,36.2-147.59,108.61-147.59h115.59C976.79,168.31,1013,217.51,1013,315.9z M898.41,937.56V339.75 c0-15.89-1.99-26.58-5.98-32.05c-3.98-5.45-11.63-8.2-22.92-8.2h-45.84c-10.63,0-17.94,2.75-21.92,8.2 c-3.98,5.47-5.98,16.17-5.98,32.05v597.81c0,15.91,1.99,26.6,5.98,32.05c3.99,5.47,11.29,8.2,21.92,8.2h45.84 c11.29,0,18.93-2.73,22.92-8.2C896.42,964.16,898.41,953.47,898.41,937.56z"/>
</g>
</svg>
)
}
@@ -0,0 +1,9 @@
import { CSSProperties } from 'react'
export function NoArrowIcon(props: {className?: string, style?: CSSProperties}) {
return (
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="1280" height="1280" viewBox="0 0 1280 1280" fill="currentColor">
<path d="M926.33,200H353.67C268.8,200,200,268.8,200,353.67v572.67c0,84.87,68.8,153.67,153.67,153.67h572.67 c84.87,0,153.67-68.8,153.67-153.67V353.67C1080,268.8,1011.2,200,926.33,200z M640,824c-100.52,0-182-81.48-182-182 s81.48-182,182-182s182,81.48,182,182S740.52,824,640,824z"/>
</svg>
)
}
@@ -0,0 +1,9 @@
import { CSSProperties } from "react";
export function OneSaberIcon(props: {className?: string, style?: CSSProperties}) {
return (
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="1280" height="1280" viewBox="0 0 1280 1280" fill="currentColor">
<path d="M1219.85,1045.85l-224.8-83.69L854,850V645.44l317.06,43.14c33.1,4.5,63.58-18.68,68.08-51.77v0 c4.5-33.1-18.68-63.58-51.77-68.08l-434.95-59.19C792.87,491.12,821,450.35,821,403c0-64.62-52.38-117-117-117s-117,52.38-117,117 c0,51.94,33.85,95.97,80.69,111.25l-378.02-43.52c-2.67-0.31-5.31-0.42-7.92-0.38c4.76-10.41,4.8-22.84-0.97-33.74L80.93,59.64 c-9.87-18.61-32.95-25.7-51.56-15.83v0c-18.61,9.87-25.7,32.95-15.83,51.56l199.84,376.98c5.13,9.68,13.83,16.23,23.62,18.91 c-7.69,8.88-12.89,20.09-14.34,32.64v0c-3.82,33.18,19.98,63.18,53.17,67l323.91,37.29l0,0L598,810c0,0-128,2-189,5 c-53,3-75,65-46.05,106.24c0.05-0.24,136.94,189.62,136.94,189.62c19.6,26.61,57.05,32.29,83.66,12.69l0,0 c26.61-19.6,32.29-57.05,12.69-83.66L542,941l201-6l205.66,137.35l4.64,1.96l224.8,83.69c30.97,11.53,65.42-4.23,76.95-35.2v0 C1266.57,1091.83,1250.82,1057.38,1219.85,1045.85z"/>
</svg>
)
}
@@ -0,0 +1,9 @@
import { CSSProperties } from "react";
export function PauseIcon(props: {className?: string, style?: CSSProperties}) {
return (
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" height="40" width="40" viewBox="0 0 40 40" fill="currentColor">
<path d="M24.958 32.167q-1.291 0-2.229-.917-.937-.917-.937-2.25V11q0-1.333.937-2.25.938-.917 2.229-.917H29q1.333 0 2.25.917t.917 2.25v18q0 1.333-.917 2.25t-2.25.917Zm-13.958 0q-1.333 0-2.25-.917T7.833 29V11q0-1.333.917-2.25T11 7.833h4.042q1.291 0 2.229.917.937.917.937 2.25v18q0 1.333-.937 2.25-.938.917-2.229.917Z"/>
</svg>
)
}
@@ -0,0 +1,13 @@
import { CSSProperties } from "react";
export function ThreeSixtyDegreeIcon(props: {className?: string, style?: CSSProperties}) {
return (
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="1280" height="1280" viewBox="0 0 1280 1280" fill="currentColor">
<g>
<path d="M197.39,338.14v127.8H83V314.09c0-99.23,36.13-148.87,108.43-148.87h100.46 c72.28,0,108.43,49.63,108.43,148.87v202.98c0,62.16-13.93,100.25-41.77,114.28c27.84,14.03,41.77,50.12,41.77,108.26v225.55 c0,99.23-36.15,148.85-108.43,148.85H191.43C119.13,1114,83,1064.38,83,965.15V814.78h114.39v126.3c0,16.06,1.99,26.83,5.96,32.34 s11.27,8.27,21.89,8.27h33.82c10.6,0,17.9-2.76,21.88-8.27c3.97-5.51,5.98-16.28,5.98-32.34V738.1c0-16.03-1.83-27.05-5.48-33.07 s-11.1-9.03-22.37-9.03h-76.6V569.69h76.6c10.6,0,17.9-2.76,21.88-8.27c3.97-5.51,5.98-16.28,5.98-32.32V338.14 c0-16.03-2-26.81-5.98-32.32c-3.97-5.51-11.27-8.28-21.88-8.28h-33.82c-10.62,0-17.92,2.77-21.89,8.28S197.39,322.12,197.39,338.14 z"/>
<path d="M584.33,562.18h108.43c72.28,0,108.43,49.62,108.43,148.85v254.12c0,99.23-36.15,148.85-108.43,148.85 H579.36c-72.29,0-108.43-49.62-108.43-148.85V314.09c0-99.23,36.13-148.87,108.43-148.87h108.43 c72.28,0,108.43,49.63,108.43,148.87v145.84h-112.4V338.14c0-16.03-2-26.81-5.98-32.32s-11.27-8.28-21.88-8.28h-43.77 c-10.62,0-17.92,2.77-21.89,8.28c-3.97,5.51-5.96,16.3-5.96,32.32V562.18z M688.78,941.08v-209c0-16.03-2-26.81-5.98-32.32 c-3.97-5.51-11.6-8.27-22.87-8.27h-75.6v249.59c0,16.06,1.99,26.83,5.96,32.34c3.97,5.51,11.27,8.27,21.89,8.27h47.75 c11.27,0,18.9-2.76,22.87-8.27S688.78,957.14,688.78,941.08z"/>
<path d="M1199.04,314.09v651.07c0,99.23-36.15,148.85-108.43,148.85H975.24c-72.29,0-108.43-49.62-108.43-148.85 V314.09c0-99.23,36.13-148.87,108.43-148.87h115.38C1162.9,165.22,1199.04,214.85,1199.04,314.09z M1084.66,941.08V338.14 c0-16.03-2-26.81-5.98-32.32s-11.6-8.28-22.87-8.28h-45.76c-10.62,0-17.92,2.77-21.89,8.28c-3.97,5.51-5.96,16.3-5.96,32.32v602.94 c0,16.06,1.99,26.83,5.96,32.34c3.97,5.51,11.27,8.27,21.89,8.27h45.76c11.27,0,18.9-2.76,22.87-8.27 S1084.66,957.14,1084.66,941.08z"/>
</g>
</svg>
)
}
@@ -0,0 +1,9 @@
import { CSSProperties } from "react";
export function ThumbUpFillIcon(props: {className?: string, style?: CSSProperties}) {
return (
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" height="40" width="40" viewBox="0 0 40 40" fill="currentColor">
<path d="M14.417 35.458q-1.334 0-2.25-.916-.917-.917-.917-2.209V15q0-.625.229-1.188.229-.562.688-1.02l8.208-8.5q.708-.667 1.625-.834.917-.166 1.75.292.833.417 1.229 1.271.396.854.188 1.771l-1.542 6.916h11.75q1.25 0 2.208.98.959.979.959 2.187v2.875q0 .458-.104.979-.105.521-.271.938l-4.959 11.5q-.375.958-1.354 1.625-.979.666-2.021.666Zm-8.709 0q-1.125 0-1.937-.791-.813-.792-.813-1.959v-16.25q0-1.125.792-1.937.792-.813 1.917-.813h.041q1.125 0 1.938.813.812.812.812 1.937v16.25q0 1.167-.812 1.959-.813.791-1.938.791Z"/>
</svg>
)
}
@@ -0,0 +1,9 @@
import { CSSProperties } from "react";
export function TimerFillIcon(props: {className?: string, style?: CSSProperties}) {
return (
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" height="40" width="40" viewBox="0 0 40 40" fill="currentColor">
<path d="M16.25 4.458q-.625 0-1.062-.437-.438-.438-.438-1.104 0-.625.438-1.063.437-.437 1.062-.437h7.5q.625 0 1.062.437.438.438.438 1.063 0 .666-.438 1.104-.437.437-1.062.437ZM20 23.208q.625 0 1.062-.437.438-.438.438-1.104v-6.709q0-.625-.438-1.062-.437-.438-1.062-.438t-1.062.438q-.438.437-.438 1.062v6.709q0 .666.438 1.104.437.437 1.062.437Zm0 13.959q-3.167 0-5.938-1.209-2.77-1.208-4.854-3.291-2.083-2.084-3.291-4.855-1.209-2.77-1.209-5.937 0-3.167 1.209-5.937 1.208-2.771 3.291-4.855Q11.292 9 14.062 7.792 16.833 6.583 20 6.583q2.75 0 5.188.896 2.437.896 4.437 2.521l1.25-1.208q.417-.459 1.042-.459T33 8.792q.458.458.458 1.104 0 .646-.458 1.062l-1.208 1.209q1.541 1.833 2.52 4.229.98 2.396.98 5.479 0 3.167-1.209 5.937-1.208 2.771-3.291 4.855-2.084 2.083-4.854 3.291-2.771 1.209-5.938 1.209Z"/>
</svg>
)
}
+6 -1
View File
@@ -30,5 +30,10 @@ export interface RawMapDifficulty {
_difficultyRank: string,
_beatmapFilename: string,
_noteJumpMovementSpeed: number,
_noteJumpStartBeatOffset: number
_noteJumpStartBeatOffset: number,
_customData?: RawMapDifficultyCustomData
}
export interface RawMapDifficultyCustomData {
_difficultyLabel?: string
}