[chore] fix lint errors

This commit is contained in:
MathieuG-P
2023-07-01 03:01:38 +02:00
parent 7addb57613
commit d62727c3f9
55 changed files with 176 additions and 181 deletions
@@ -52,6 +52,7 @@ export const AvailableVersionItem = memo(function AvailableVersionItem(props: {v
<span className="text-sm text-gray-700 dark:text-gray-400">{formatedDate}</span>
</div>
{ props.version.ReleaseURL && (
// eslint-disable-next-line jsx-a11y/anchor-is-valid -- link will be reworked
<a onClickCapture={e => { e.stopPropagation(); openReleasePage(); }} className="flex flex-row justify-between items-center rounded-full bg-black bg-opacity-30 text-white pb-px hover:bg-opacity-50">
<BsmIcon icon="steam" className="w-[25px] h-[25px] transition-transform group-hover:rotate-[-360deg] duration-300"/>
<span className="relative -left-px text-sm w-fit max-w-0 text-center overflow-hidden h-full whitespace-nowrap pb-[3px] transition-all group-hover:max-w-[200px] group-hover:px-1 duration-300">{t("pages.available-versions.steam-release")}</span>
@@ -18,8 +18,8 @@ export function AvailableVersionsSlide(props: {year: string}) {
return (
<ol className="w-full flex items-start justify-center gap-6 shrink-0 content-start flex-wrap p-4 overflow-x-hidden overflow-y-scroll scrollbar-thin scrollbar-thumb-rounded-full scrollbar-thumb-neutral-900">
{availableVersions.map((version, index) =>
<AvailableVersionItem key={index} version={version}></AvailableVersionItem>
{availableVersions.map((version) =>
<AvailableVersionItem key={version.BSManifest} version={version}/>
)}
</ol>
)
@@ -4,7 +4,7 @@ import { MutableRefObject, useEffect, useRef, useState} from "react"
import { MAP_TYPES } from "renderer/partials/maps/map-tags/map-types"
import { MAP_STYLES } from "renderer/partials/maps/map-tags/map-styles"
import { BsmCheckbox } from "../shared/bsm-checkbox.component"
import { min_to_s } from "renderer/helpers/time-utils"
import { minToS } from "renderer/helpers/time-utils"
import dateFormat from "dateformat"
import { BsmRange } from "../shared/bsm-range.component"
import { useTranslation } from "renderer/hooks/use-translation.hook"
@@ -38,7 +38,7 @@ export function FilterPanel({className, ref, playlist = false, filter, onChange,
const MAX_NPS = 17;
const MIN_DURATION = 0;
const MAX_DURATION = min_to_s(30);
const MAX_DURATION = minToS(30);
const npss = [filter?.minNps || MIN_NPS, filter?.maxNps || MAX_NPS];
const durations = [filter?.minDuration || MIN_DURATION, filter?.maxDuration || MAX_DURATION];
@@ -80,7 +80,7 @@ export function FilterPanel({className, ref, playlist = false, filter, onChange,
}
const renderLabel = (text: unknown, isMax: boolean): JSX.Element => {
const renderLabel = (text: string|number, isMax: boolean): JSX.Element => {
return (
<span className={`bg-inherit absolute top-[calc(100%+4px)] h-5 font-bold rounded-md shadow-center shadow-black px-1 flex items-center ${isMax ? "text-lg" : "text-sm"}`}>
{text}
@@ -91,10 +91,10 @@ export function FilterPanel({className, ref, playlist = false, filter, onChange,
const onNpssChange = ([min, max]: number[]) => {
const newFilter: MapFilter = {...filter, minNps: min, maxNps: max};
if(max === MAX_NPS){
delete newFilter["maxNps"];
delete newFilter.maxNps;
}
if(min === MIN_NPS){
delete newFilter["minNps"];
delete newFilter.minNps;
}
onChange(newFilter);
}
@@ -102,10 +102,10 @@ export function FilterPanel({className, ref, playlist = false, filter, onChange,
const onDurationsChange = ([min, max]: number[]) => {
const newFilter: MapFilter = {...filter, minDuration: min, maxDuration: max};
if(max === MAX_DURATION){
delete newFilter["maxDuration"];
delete newFilter.maxDuration;
}
if(min === MIN_DURATION){
delete newFilter["minDuration"];
delete newFilter.minDuration;
}
onChange(newFilter);
}
@@ -129,11 +129,11 @@ export function FilterPanel({className, ref, playlist = false, filter, onChange,
const newFilter = {...filter, enabledTags, excludedTags};
if(newFilter.enabledTags.size === 0){
delete newFilter["enabledTags"];
delete newFilter.enabledTags;
}
if(newFilter.excludedTags.size === 0){
delete newFilter["excludedTags"];
delete newFilter.excludedTags;
}
onChange(newFilter);
@@ -2,12 +2,11 @@ import { MapsManagerService } from "renderer/services/maps-manager.service"
import { BSVersion } from "shared/bs-version.interface"
import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react"
import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface"
import { Subscription } from "rxjs"
import { Subscription, BehaviorSubject } from "rxjs"
import { MapFilter } from "shared/models/maps/beat-saver.model"
import { MapsDownloaderService } from "renderer/services/maps-downloader.service"
import { VariableSizeList } from "react-window"
import { MapsRow } from "./maps-row.component"
import { BehaviorSubject } from "rxjs"
import { debounceTime, last, mergeMap, tap } from "rxjs/operators"
import { BeatSaverService } from "renderer/services/thrird-partys/beat-saver.service"
import { OsDiagnosticService } from "renderer/services/os-diagnostic.service"
@@ -121,7 +120,7 @@ export const LocalMapsListPanel = forwardRef(({version, className, filter, searc
last(),
mergeMap(async progress => {
if(os.isOffline){ return progress.maps; }
const maps = progress.maps;
const { maps } = progress;
const details = await bsaver.getMapDetailsFromHashs(maps.map(map => map.hash));
return maps.map(map => {
map.bsaverInfo = details.find(d => d.versions.at(0).hash === map.hash);
@@ -330,7 +329,7 @@ export const LocalMapsListPanel = forwardRef(({version, className, filter, searc
return (
<div ref={ref} className={className}>
<VariableSizeList className="p-0 scrollbar-thin scrollbar-thumb-rounded-full scrollbar-thumb-neutral-900" width={"100%"} height={listHeight} itemSize={() => 108} itemCount={preppedMaps.length} itemData={preppedMaps} layout="vertical" style={{scrollbarGutter: "stable both-edges"}} itemKey={(i, data) => data[i].map(map => map.hash).join()}>
<VariableSizeList className="p-0 scrollbar-thin scrollbar-thumb-rounded-full scrollbar-thumb-neutral-900" width="100%" height={listHeight} itemSize={() => 108} itemCount={preppedMaps.length} itemData={preppedMaps} layout="vertical" style={{scrollbarGutter: "stable both-edges"}} itemKey={(i, data) => data[i].map(map => map.hash).join()}>
{(props) => <MapsRow maps={props.data[props.index]} style={props.style} selectedMaps$={selectedMaps$} onMapSelect={onMapSelected} onMapDelete={handleDelete}/>}
</VariableSizeList>
</div>
@@ -1,11 +0,0 @@
type Props = {
className?: string
}
export function MapsToolbar({className}: Props) {
return (
<div className={className}>
</div>
)
}
@@ -9,7 +9,6 @@ import { useObservable } from "renderer/hooks/use-observable.hook";
import { BSV_SORT_ORDER } from "renderer/partials/beat-saver/sort-order";
import { BeatSaverService } from "renderer/services/thrird-partys/beat-saver.service";
import { MapsDownloaderService } from "renderer/services/maps-downloader.service";
import { MapsManagerService } from "renderer/services/maps-manager.service";
import { ModalComponent } from "renderer/services/modale.service";
import { BSVersion } from "shared/bs-version.interface";
import { BsvMapCharacteristic, BsvMapDetail, MapFilter, SearchOrder, SearchParams } from "shared/models/maps/beat-saver.model";
@@ -21,7 +20,7 @@ import { useTranslation } from "renderer/hooks/use-translation.hook";
import { OsDiagnosticService } from "renderer/services/os-diagnostic.service";
import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface";
export const DownloadMapsModal: ModalComponent<void, {version: BSVersion, ownedMaps: BsmLocalMap[]}> = ({resolver, data: { ownedMaps, version }}) => {
export const DownloadMapsModal: ModalComponent<void, {version: BSVersion, ownedMaps: BsmLocalMap[]}> = ({ data: { ownedMaps, version } }) => {
const beatSaver = BeatSaverService.getInstance();
const mapsDownloader = MapsDownloaderService.getInstance();
@@ -173,7 +172,11 @@ export const DownloadMapsModal: ModalComponent<void, {version: BSVersion, ownedM
{maps.length === 0 ? (
<div className="w-full h-full flex flex-col items-center justify-center">
<img className={`w-32 h-32 ${loading && "spin-loading"}`} src={loading ? BeatWaitingImg : BeatConflictImg} alt=" "/>
<span className="text-lg">{t(loading ? "modals.download-maps.loading-maps" : isOnline ? "modals.download-maps.no-maps-found" : "modals.download-maps.no-internet")}</span>
<span className="text-lg">{(() => {
if(loading){ return t("modals.download-maps.loading-maps"); }
if(isOnline){ return t("modals.download-maps.no-maps-found"); }
return t("modals.download-maps.no-internet");
})()}</span>
</div>
) : (
<>
@@ -25,7 +25,11 @@ export const DeleteModelsModal: ModalComponent<void, {models: BsmLocalModel[], l
const title = useConstant(() => isMultiple ? t("models.modals.delete-models.title") : t("models.modals.delete-model.title"));
const desc = useConstant(() => isMultiple ? t("models.modals.delete-models.desc", {nb: `${data.models.length}`}) : t("models.modals.delete-model.desc", {modelName: data.models[0].model?.name ?? data.models[0].fileName}));
const linkedAnnotation = useConstant(() => data.linked ? (isMultiple ? t("models.modals.delete-models.linked-annotation") : t("models.modals.delete-model.linked-annotation")) : undefined);
const linkedAnnotation = useConstant(() => (() => {
if(!data.linked) return null;
if(isMultiple) return t("models.modals.delete-models.linked-annotation");
return t("models.modals.delete-model.linked-annotation");
})());
return (
<form className="text-gray-800 dark:text-gray-200">
@@ -157,7 +157,7 @@ export const DownloadModelsModal: ModalComponent<void, {version: BSVersion, type
<BsmSelect className="bg-light-main-color-1 dark:bg-main-color-1 rounded-full px-1 pb-0.5 text-center capitalize" options={modelTypesOptions} selected={currentType} onChange={(value) => currentType$.next(value)}/>
<div className="h-ful grow relative flex justify-center items-center">
<input className="h-full w-full bg-light-main-color-1 dark:bg-main-color-1 rounded-full px-2 pb-0.5" type="text" name="" id="" placeholder={t("models.modals.download-models.search-placeholder")} value={searhInput} onChange={e => searhInput$.next(e.target.value)}/>
<Tippy placement="bottom" content={renderFilterTips} allowHTML={true} maxWidth={Infinity}>
<Tippy placement="bottom" content={renderFilterTips} allowHTML maxWidth={Infinity}>
<div className="absolute right-0 h-full w-fit p-1 cursor-pointer">
<BsmButton className="h-full rounded-full p-1 aspect-square" typeColor="primary" icon="info" withBar={false}/>
</div>
@@ -75,7 +75,7 @@ export const ShareFoldersModal: ModalComponent<void, BSVersion> = ({ data }) =>
<p className="my-3">{t("modals.shared-folders.description")}</p>
<ul className="flex flex-col gap-1 mb-2 h-[300px] max-h-[300px] overflow-scroll scrollbar-thin scrollbar-thumb-rounded-full scrollbar-thumb-neutral-900 px-1">
{folders.map((folder, index) => (
<FolderItem key={index} version={data} relativeFolder={folder} onDelete={() => {removeFolder(index)}}/>
<FolderItem key={folder} version={data} relativeFolder={folder} onDelete={() => {removeFolder(index)}}/>
))}
</ul>
<div className="grid grid-flow-col gap-3 grid-cols-2">
@@ -151,16 +151,15 @@ const FolderItem = ({version, relativeFolder, onDelete}: FolderProps) => {
<Tippy placement="left" content={t(`modals.shared-folders.buttons.${linked ? "unlink-folder" : "link-folder"}`)} arrow={false}>
<LinkButton variants={variants} linked={linked} disabled={linkDisabled} whileHover="hover" whileTap="tap" className="p-0.5 h-7 shrink-0 aspect-square blur-0 cursor-pointer hover:brightness-75" onClick={onClickLink}/>
</Tippy>
{!processing ? (
!pending ? (
<BsmButton className="aspect-square h-7 rounded-md p-1" icon={"trash"} withBar={false} onClick={e => {e.preventDefault(); onDelete?.()}}/>
) : (
<BsmButton className="aspect-square h-7 rounded-md p-1" icon={"cross"} withBar={false} onClick={e => {e.preventDefault(); cancelLink()}}/>
)
) : (
<BsmBasicSpinner className="aspect-square h-7 rounded-md p-1 dark:bg-main-color-2" thikness="3.5px" style={{color}}/>
)}
{(() => {
if(processing){
return <BsmBasicSpinner className="aspect-square h-7 rounded-md p-1 dark:bg-main-color-2" thikness="3.5px" style={{color}}/>;
}
if(pending){
return <BsmButton className="aspect-square h-7 rounded-md p-1" icon="cross" withBar={false} onClick={e => {e.preventDefault(); cancelLink()}}/>;
}
return <BsmButton className="aspect-square h-7 rounded-md p-1" icon="trash" withBar={false} onClick={e => {e.preventDefault(); onDelete?.()}}/>;
})()}
</div>
</li>
)
@@ -1,9 +1,8 @@
import { BsmButton } from "renderer/components/shared/bsm-button.component";
import { useTranslation } from "renderer/hooks/use-translation.hook";
import { LinkOpenerService } from "renderer/services/link-opener.service";
import { ModalComponent, ModalExitCode } from "renderer/services/modale.service"
import { ModalComponent } from "renderer/services/modale.service"
export const WhyCredentialsModal: ModalComponent<void> = ({resolver}) => {
export const WhyCredentialsModal: ModalComponent<void> = () => {
const t = useTranslation();
const linkOpener = LinkOpenerService.getInstance();
@@ -17,6 +16,7 @@ export const WhyCredentialsModal: ModalComponent<void> = ({resolver}) => {
<h1 className="text-3xl mb-2 uppercase tracking-wide w-full text-center text-gray-800 dark:text-gray-200">{t("modals.steam-credentials.title")}</h1>
<p>{t("modals.steam-credentials.p-1")}</p>
{ /* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
<a onClick={e => {e.preventDefault; openTutorial()}} className="underline text-blue-600 hover:text-blue-900 dark:text-blue-400 dark:hover:text-blue-600 mb-2 block cursor-pointer">
https://steamcommunity.com/sharedfiles/filedetails/?id=1805934840
</a>
@@ -23,7 +23,7 @@ export function Modal() {
resolver?.(ModalExitCode.NO_CHOICE);
}
if(!!ModalComponent){
if(ModalComponent){
window.addEventListener("keyup", onEscape)
}
else{
@@ -32,7 +32,7 @@ type Props<T> = {
onDoubleClick?: (value: T) => void
} & Partial<MSModel> & Partial<BsmLocalModel> & Omit<React.ComponentProps<"li">, "id" | "onDoubleClick">
function modelItem<T = unknown>(props: Props<T>) {
function ModelItemElement<T = unknown>(props: Props<T>) {
const t = useTranslation();
const color = useThemeColor("first-color");
@@ -66,7 +66,7 @@ function modelItem<T = unknown>(props: Props<T>) {
if(!props.thumbnail){ return null; }
if(isValidUrl(props.thumbnail)){ return props.thumbnail; }
const [file, ext] = props.thumbnail.split(".");
return props.download.split("/").slice(0, -1).join("/") + `/${file}.${ext.toLowerCase()}`;
return `${props.download.split("/").slice(0, -1).join("/")}/${file}.${ext.toLowerCase()}`
})();
const modelTags = (() => {
@@ -74,19 +74,19 @@ function modelItem<T = unknown>(props: Props<T>) {
return [...new Set(props.tags)];
})();
const actionButtons = (): {icon: BsmIconType, action: () => void, iconColor?: string}[] => {
const buttons: {icon: BsmIconType, action: () => void, iconColor?: string}[] = [];
const actionButtons = (): {id: number, icon: BsmIconType, action: () => void, iconColor?: string}[] => {
const buttons: {id: number, icon: BsmIconType, action: () => void, iconColor?: string}[] = [];
if(props.onDownload && !props.onCancelDownload){
buttons.push({ icon: "download", action: () => props.onDownload(props.callbackValue) });
buttons.push({id: 0, icon: "download", action: () => props.onDownload(props.callbackValue) });
}
if(props.onDelete){
buttons.push({ icon: "trash", action: () => props.onDelete(props.callbackValue) });
buttons.push({ id: 1,icon: "trash", action: () => props.onDelete(props.callbackValue) });
}
if(props.onCancelDownload){
buttons.push({ icon: "cross", action: () => props.onCancelDownload(props.callbackValue), iconColor: "red" });
buttons.push({ id: 2,icon: "cross", action: () => props.onCancelDownload(props.callbackValue), iconColor: "red" });
}
return buttons;
@@ -105,12 +105,12 @@ function modelItem<T = unknown>(props: Props<T>) {
<GlowEffect visible={props.selected || hovered}/>
<div className="absolute top-0 left-0 w-full h-full rounded-lg overflow-hidden blur-none bg-black shadow-sm shadow-black">
<div ref={ref} className="contents">
<BsmImage className={`absolute top-0 left-0 w-full h-full object-cover brightness-50 scale-[200%] blur-md`} image={thumbnailUrl} placeholder={defaultImage} loading="lazy"/>
<BsmImage className={`absolute top-0 left-1/2 -translate-x-1/2 max-w-[20rem] w-full h-full object-cover`} image={thumbnailUrl} placeholder={defaultImage} loading="lazy"/>
<BsmImage className="absolute top-0 left-0 w-full h-full object-cover brightness-50 scale-[200%] blur-md" image={thumbnailUrl} placeholder={defaultImage} loading="lazy"/>
<BsmImage className="absolute top-0 left-1/2 -translate-x-1/2 max-w-[20rem] w-full h-full object-cover" image={thumbnailUrl} placeholder={defaultImage} loading="lazy"/>
<div className="absolute top-0 right-0 h-full w-0 flex flex-col items-end gap-1 pt-1.5 pr-1.5">
{!props.isDownloading ? (
actionButtons().map((button, index) => (
<BsmButton key={index} className="w-8 h-8 p-1 rounded-md transition-transform duration-150 shadow-black shadow-sm" style={{transitionDelay: `${index * 50}ms`, transform: hovered ? "translate(0%)" : "translate(150%)"}} icon={button.icon} iconColor={button.iconColor} onClick={e => {e.stopPropagation(); e.preventDefault(); button.action();}} withBar={false}/>
<BsmButton key={button.id} className="w-8 h-8 p-1 rounded-md transition-transform duration-150 shadow-black shadow-sm" style={{transitionDelay: `${index * 50}ms`, transform: hovered ? "translate(0%)" : "translate(150%)"}} icon={button.icon} iconColor={button.iconColor} onClick={e => {e.stopPropagation(); e.preventDefault(); button.action();}} withBar={false}/>
))
): (
<BsmBasicSpinner className="w-7 h-7 p-1 rounded-md bg-main-color-2 flex items-center justify-center shadow-black shadow-sm" spinnerClassName="brightness-200" thikness="3.5px" style={{color}}/>
@@ -157,4 +157,4 @@ function modelItem<T = unknown>(props: Props<T>) {
const typedMemo: <T, P>(c: T, propsAreEqual?: (prevProps: Readonly<P>, nextProps: Readonly<P>) => boolean) => T = memo;
export const ModelItem = typedMemo(modelItem, equal);
export const ModelItem = typedMemo(ModelItemElement, equal);
@@ -13,7 +13,7 @@ import { useOnUpdate } from "renderer/hooks/use-on-update.hook";
import { NotificationService } from "renderer/services/notification.service";
import { ConfigurationService } from "renderer/services/configuration.service";
import { useTranslation } from "renderer/hooks/use-translation.hook";
import { gte, lt } from "semver";
import { lt } from "semver";
export function ModelsPanel({version, isActive, goToMods}: {version?: BSVersion, isActive: boolean, goToMods?: () => void}) {
@@ -85,7 +85,7 @@ export function ModelsPanel({version, isActive, goToMods}: {version?: BSVersion,
<BsmDropdownButton items={threeDotsItems} className="h-full flex aspect-square relative rounded-full z-[1] bg-light-main-color-1 dark:bg-main-color-3" buttonClassName="rounded-full h-full w-full p-[6px]" icon="three-dots" withBar={false} menuTranslationY="6px" align="center"/>
</div>
<div className="w-full h-full flex flex-row bg-light-main-color-3 dark:bg-main-color-2 rounded-md shadow-black shadow-md overflow-hidden">
<ModelsTabsNavbar className="flex-shrink-0" version={version} tabIndex={currentTabIndex} onTabChange={(index, tab) => {setModelTypeTab(() => tab.extra), setCurrentTabIndex(() => index)}}/>
<ModelsTabsNavbar className="flex-shrink-0" version={version} tabIndex={currentTabIndex} onTabChange={(index, tab) => {setModelTypeTab(() => tab.extra); setCurrentTabIndex(() => index)}}/>
<div className="flex-grow h-full flex flex-col transition-all duration-300" style={{translate: `0 ${0 - currentTabIndex * 100}%`}}>
<ModelsGrid ref={modelsGridRefs[0]} version={version} type={MSModelType.Avatar} active={isActive && modelTypeTab === MSModelType.Avatar} search={search} downloadModels={openDownloadModal}/>
@@ -13,7 +13,7 @@ export const BsManagerIcon = memo(({className}: {className?: string}) => {
const {firstColor, secondColor} = useThemeColor();
const playing= useObservable(audioPlayer.playing$);
const bpm = audioPlayer.bpm;
const { bpm } = audioPlayer;
const transitions: Variants = {
playing: {
@@ -34,7 +34,7 @@ export function BsmProgressBar() {
<span className="absolute w-full text-center text-white -top-[3px] left-0 text-[10px]">{progressLabel}</span>
</div>
)}
{ !progressValue && <img className="w-12 h-12 spin-loading" src={BeatWaitingImg}></img> }
{ !progressValue && <img className="w-12 h-12 spin-loading" src={BeatWaitingImg}/> }
</div>
</motion.div>
} </AnimatePresence>
@@ -21,13 +21,13 @@ export function SupporterItem({supporter, delay}: Props) {
})();
const renderSpan = () => {
return <motion.span className={`text-2xl font-bold px-3 pb-1 ${supporter.link && "cursor-pointer underline"}`} style={additionnalStyles} onClick={openSupporterLink} initial={{y: "100%", opacity: 0}} animate={{y: 0, opacity: 1}} transition={{delay: delay}}>{supporter.username}</motion.span>;
return <motion.span className={`text-2xl font-bold px-3 pb-1 ${supporter.link && "cursor-pointer underline"}`} style={additionnalStyles} onClick={openSupporterLink} initial={{y: "100%", opacity: 0}} animate={{y: 0, opacity: 1}} transition={{delay}}>{supporter.username}</motion.span>;
}
const renderItem = () => {
if(supporter.type !== "sponsor"){ return renderSpan(); }
return (
<motion.div className={`flex flex-col justify-center items-center mx-4 ${supporter.link && "cursor-pointer underline"}`} onClick={openSupporterLink} initial={{y: "100%", opacity: 0}} animate={{y: 0, opacity: 1}} transition={{delay: delay}}>
<motion.div className={`flex flex-col justify-center items-center mx-4 ${supporter.link && "cursor-pointer underline"}`} onClick={openSupporterLink} initial={{y: "100%", opacity: 0}} animate={{y: 0, opacity: 1}} transition={{delay}}>
<img className="max-w-xs max-h-52 mb-2" src={supporter.img}/>
{renderSpan()}
</motion.div>
@@ -32,8 +32,8 @@ export function SupportersView({isVisible, setVisible}: Props) {
<AnimatePresence>
({isVisible &&
<motion.div className="fixed top-0 left-0 w-full h-full bg-black bg-opacity-90 z-40 text-gray-200" transition={{duration: .3}} initial={{opacity: 0, y: "-100%"}} animate={{opacity: 1, y: "0%"}} exit={{opacity: 0, y: "-100%"}}>
<BsmButton className="absolute right-10 top-10 !bg-transparent w-7 h-7" icon="cross" withBar={false} onClick={() => setVisible(false)}></BsmButton>
{(!!sponsors.length || !!supporters.length) && <img className="absolute bottom-5 right-5 rotate-45 w-32 h-32" src={ManheraChanGif}/>}
<BsmButton className="absolute right-10 top-10 !bg-transparent w-7 h-7" icon="cross" withBar={false} onClick={() => setVisible(false)}/>
{(!!sponsors.length || !!supporters.length) && <img className="absolute bottom-5 right-5 rotate-45 w-32 h-32" src={ManheraChanGif}/>}
<div className="w-full h-full overflow-y-scroll">
{!!sponsors.length && <SupportersBlock className="mt-12" title="pages.settings.patreon.view.sponsors" supporters={sponsors}/>}
{!!supporters.length && <SupportersBlock className="mt-12" title="pages.settings.patreon.view.supporters" supporters={supporters}/>}
@@ -24,7 +24,7 @@ export function BsContentNavBar<T>({className, tabIndex, tabs, renderTab, onTabC
return (
<nav className={`h-full grid grid-flow-row ${className ?? ""}`}>
{tabs.map((tab, i) => (
<Fragment key={i}>
<Fragment key={JSON.stringify(tab)}>
{ renderTab({onClick: () => handleTabClick(i)}, tab, tabs[tabIndex]) }
</Fragment>
))}
@@ -20,8 +20,8 @@ type Props = {
active?: boolean,
withBar?: boolean,
disabled?: boolean,
onClickOutside?: (e: MouseEvent) => void,
onClick?: (e: React.MouseEvent) => void,
onClickOutside?: React.ComponentProps<"div">["onClick"],
onClick?: React.ComponentProps<"div">["onClick"],
typeColor?:BsmButtonType,
color?: string,
title?: string,
@@ -37,7 +37,11 @@ export function BsmButton({className, style, imgClassName, iconClassName, icon,
useClickOutside(ref, onClickOutside);
const primaryColor = typeColor === "primary" ? firstColor : typeColor === "secondary" ? secondColor : undefined;
const primaryColor = (() => {
if(typeColor === "primary"){ return firstColor; }
if(typeColor === "secondary"){ return secondColor; }
return undefined;
})();
const textColor = (() => {
if(primaryColor){
@@ -54,7 +58,7 @@ export function BsmButton({className, style, imgClassName, iconClassName, icon,
return "";
})();
const handleClick = (e: MouseEvent) => !disabled && onClick?.(e);
const handleClick = (e: MouseEvent<HTMLDivElement>) => !disabled && onClick?.(e);
return (
<div ref={ref} onClick={handleClick} title={t(title)} className={`${className} overflow-hidden cursor-pointer group ${(!withBar && !disabled && (!!typeColor || !!color)) && "hover:brightness-[1.15]"} ${disabled && "brightness-75 cursor-not-allowed"} ${renderTypeColor}`} style={{...style, backgroundColor: primaryColor || color}}>
@@ -1,4 +1,4 @@
import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react"
import { forwardRef, useImperativeHandle, useRef, useState } from "react"
import { BsmIconType, BsmIcon } from "../svgs/bsm-icon.component"
import { BsmButton } from "./bsm-button.component"
import { useTranslation } from "renderer/hooks/use-translation.hook"
@@ -52,8 +52,7 @@ export const BsmDropdownButton = forwardRef(({className, items, align, withBar =
})()
return (
// @ts-ignore
<div ref={ref} className={className}>
<div ref={ref as unknown as React.LegacyRef<HTMLDivElement>} className={className}>
<BsmButton onClick={() => setExpanded(!expanded)} className={buttonClassName ?? defaultButtonClassName} icon={icon} active={expanded} onClickOutside={handleClickOutside} withBar={withBar} text={text}/>
<div className={`py-1 w-fit absolute cursor-pointer top-[calc(100%-4px)] rounded-md bg-inherit text-sm text-gray-800 dark:text-gray-200 shadow-md shadow-black transition-[scale] ease-in-out ${alignClass}`} style={{scale: expanded ? "1" : "0", translate: `0 ${menuTranslationY}`}}>
{ items?.map((i) => i && (
@@ -36,7 +36,6 @@ export const BsmImage = forwardRef(({className, image, errorImage, placeholder,
}
return (
// @ts-ignore
<img ref={ref} title={title} className={className} src={image} loading={loading} onLoad={handleLoaded} onError={handleError} style={styles} onClick={(e) => onClick?.(e)} alt=" " decoding="async"/>
)
})
@@ -18,6 +18,7 @@ export function BsmLink({className, href, children, style, internal}: Props) {
}
return (
// eslint-disable-next-line jsx-a11y/anchor-is-valid -- Will be reworked later
<a className={`${className} ${href && "cursor-pointer"}`} onClick={e => {e.stopPropagation(); openLink()}} style={style}>{children}</a>
)
}
@@ -20,7 +20,7 @@ export function BsmSelect<T = unknown>(props: Props<T>) {
return (
<select {...props} onChange={handleChange} defaultValue={props.options?.findIndex(opt => equal(opt.value, props.selected))}>
{props.options && props.options.map((option, index) => (
<option key={index} value={index}>{t(option.text)}</option>
<option key={JSON.stringify(option)} value={index}>{t(option.text)}</option>
))}
</select>
)
@@ -3,7 +3,7 @@ import { CSSProperties } from 'react'
export function GitHubIcon(props: {className?: string, style?: CSSProperties}) {
return (
<svg className={props.className} style={props.style} viewBox="0 0 16 16" width="16" height="16">
<path fill="currentColor" fillRule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path>
<path fill="currentColor" fillRule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/>
</svg>
)
}
@@ -3,15 +3,15 @@ import { CSSProperties } from "react";
export function Mee6Icon(props: {className?: string, style?: CSSProperties}) {
return (
<svg className={props.className} style={props.style} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 40 40">
<path fill="#60D1F6" d="M20 40c11.046 0 20-8.954 20-20S31.046 0 20 0 0 8.954 0 20s8.954 20 20 20z"></path>
<path fill="#17181E" fill-rule="evenodd" d="M13.636 25.394c1.85-.538 4.03-.848 6.365-.848 2.333 0 4.512.31 6.363.847-.472 3.123-3.141 5.516-6.364 5.516s-5.893-2.393-6.364-5.515z" clip-rule="evenodd"></path>
<path fill="#60D1F6" d="M20 40c11.046 0 20-8.954 20-20S31.046 0 20 0 0 8.954 0 20s8.954 20 20 20z"/>
<path fill="#17181E" fillRule="evenodd" d="M13.636 25.394c1.85-.538 4.03-.848 6.365-.848 2.333 0 4.512.31 6.363.847-.472 3.123-3.141 5.516-6.364 5.516s-5.893-2.393-6.364-5.515z" clipRule="evenodd"/>
<mask id="mask0" width="14" height="7" x="13" y="24" maskUnits="userSpaceOnUse">
<path fill="#fff" fill-rule="evenodd" d="M13.636 25.394c1.85-.538 4.03-.848 6.365-.848 2.333 0 4.512.31 6.363.847-.472 3.123-3.141 5.516-6.364 5.516s-5.893-2.393-6.364-5.515z" clip-rule="evenodd"></path>
<path fill="#fff" fillRule="evenodd" d="M13.636 25.394c1.85-.538 4.03-.848 6.365-.848 2.333 0 4.512.31 6.363.847-.472 3.123-3.141 5.516-6.364 5.516s-5.893-2.393-6.364-5.515z" clipRule="evenodd"/>
</mask>
<g mask="url(#mask0)">
<path fill="#F90043" d="M20 35.151c2.929 0 5.303-1.662 5.303-3.712 0-2.05-2.374-3.712-5.303-3.712s-5.303 1.662-5.303 3.712c0 2.05 2.374 3.712 5.303 3.712z"></path>
<path fill="#F90043" d="M20 35.151c2.929 0 5.303-1.662 5.303-3.712 0-2.05-2.374-3.712-5.303-3.712s-5.303 1.662-5.303 3.712c0 2.05 2.374 3.712 5.303 3.712z"/>
</g>
<path fill="#17181E" d="M13.182 18.182a2.273 2.273 0 100-4.546 2.273 2.273 0 000 4.546zM26.818 18.182a2.273 2.273 0 100-4.546 2.273 2.273 0 000 4.546z"></path>
<path fill="#17181E" d="M13.182 18.182a2.273 2.273 0 100-4.546 2.273 2.273 0 000 4.546zM26.818 18.182a2.273 2.273 0 100-4.546 2.273 2.273 0 000 4.546z"/>
</svg>
)
}
@@ -3,7 +3,7 @@ import { CSSProperties } from "react";
export function ModelTypeBloqIcon(props: {className?: string, style?: CSSProperties}) {
return (
<svg xmlns="http://www.w3.org/2000/svg" id="Bloq" viewBox="0 0 300 300" {...props} fill="currentColor">
<path d="M264,0H36.05A36,36,0,0,0,0,36.05V264A36,36,0,0,0,36.05,300H264A36,36,0,0,0,300,264V36.05A36,36,0,0,0,264,0Zm2.38,52.68a5.86,5.86,0,0,1-3.53,5.37L152.08,106a5.87,5.87,0,0,1-4.7,0L39.19,58.07a5.87,5.87,0,0,1-3.48-5.35V36.46a5.85,5.85,0,0,1,5.86-5.85H260.48a5.85,5.85,0,0,1,5.85,5.85Z"></path>
<path d="M264,0H36.05A36,36,0,0,0,0,36.05V264A36,36,0,0,0,36.05,300H264A36,36,0,0,0,300,264V36.05A36,36,0,0,0,264,0Zm2.38,52.68a5.86,5.86,0,0,1-3.53,5.37L152.08,106a5.87,5.87,0,0,1-4.7,0L39.19,58.07a5.87,5.87,0,0,1-3.48-5.35V36.46a5.85,5.85,0,0,1,5.86-5.85H260.48a5.85,5.85,0,0,1,5.85,5.85Z"/>
</svg>
)
}
@@ -3,7 +3,7 @@ import { GlowEffect } from "renderer/components/shared/glow-effect.component";
import { BsmIcon, BsmIconType } from "renderer/components/svgs/bsm-icon.component"
import { useTranslation } from "renderer/hooks/use-translation.hook";
type props = {
type Props = {
onClick: (active: boolean) => void,
active: boolean,
text: string,
@@ -11,7 +11,7 @@ type props = {
infoText?: string,
}
export function LaunchModToogle({onClick, active, text, icon, infoText}: props) {
export function LaunchModToogle({onClick, active, text, icon, infoText}: Props) {
const t = useTranslation();
+1 -1
View File
@@ -1,7 +1,7 @@
import { BsvMapDetail } from "shared/models/maps";
export function getMapZipUrlFromMapDetails(map: BsvMapDetail){
const hash = map.versions.at(0).hash;
const { hash } = map.versions.at(0);
return getMapZipUrlFromHash(hash);
}
+4 -4
View File
@@ -1,14 +1,14 @@
const SECONDS_IN_MINUTE = 60;
const MINUTES_IN_HOUR = 60;
export function min_to_s(minutes: number): number{
export function minToS(minutes: number): number{
return minutes * SECONDS_IN_MINUTE;
}
export function hour_to_min(hours: number): number{
export function hourToMin(hours: number): number{
return hours * MINUTES_IN_HOUR;
}
export function hour_to_s(hours: number): number{
return hours * min_to_s(MINUTES_IN_HOUR);
export function hourToS(hours: number): number{
return hours * minToS(MINUTES_IN_HOUR);
}
+1 -1
View File
@@ -1,6 +1,6 @@
import { MutableRefObject, useEffect } from "react";
export function useClickOutside(ref: MutableRefObject<any>, handler: (e: MouseEvent) => void) {
export function useClickOutside(ref: MutableRefObject<any>, handler: React.ComponentProps<any>["onClick"]) {
useEffect(() => {
@@ -1,11 +1,9 @@
import { UninstallAllModsModal } from "renderer/components/modal/modal-types/uninstall-all-mods-modal.component";
import { UninstallModModal } from "renderer/components/modal/modal-types/uninstall-mod-modal.component";
import { Observable } from "rxjs";
import { BehaviorSubject } from "rxjs";
import { Observable, BehaviorSubject } from "rxjs";
import { map } from "rxjs/operators";
import { BSVersion } from "shared/bs-version.interface";
import { InstallModsResult, UninstallModsResult } from "shared/models/mods";
import { Mod, ModInstallProgression } from "shared/models/mods";
import { InstallModsResult, UninstallModsResult, Mod, ModInstallProgression } from "shared/models/mods";
import { ProgressionInterface } from "shared/models/progress-bar";
import { IpcService } from "./ipc.service";
import { ModalExitCode, ModalService } from "./modale.service";
@@ -57,10 +55,10 @@ export class BsModsManagerService {
title: "notifications.shared.errors.titles.no-internet",
desc: "notifications.shared.errors.msg.no-internet"
});
return new Promise(res => res());
return Promise.resolve();
}
if(!this.progressBar.require()){ return new Promise(res => res()); }
if(!this.progressBar.require()){ return Promise.resolve(); }
const progress$: Observable<ProgressionInterface> = this.ipcService.watch<ModInstallProgression>("mod-installed").pipe(map(res => {
return {progression: res.data.progression, label: res.data.name} as ProgressionInterface
@@ -1,11 +1,10 @@
import { BSVersion } from 'shared/bs-version.interface';
import { BehaviorSubject } from "rxjs";
import { BehaviorSubject, Observable } from "rxjs";
import { IpcService } from "./ipc.service";
import { ModalExitCode, ModalService } from './modale.service';
import { NotificationService } from './notification.service';
import { ProgressBarService } from './progress-bar.service';
import { EditVersionModal } from 'renderer/components/modal/modal-types/edit-version-modal.component';
import { Observable } from 'rxjs';
export class BSVersionManagerService {
@@ -1,13 +1,13 @@
import { BehaviorSubject, Observable, shareReplay } from "rxjs";
import { BehaviorSubject, Observable } from "rxjs";
import { DefaultConfigKey, defaultConfiguration } from "renderer/config/default-configuration.config";
export class ConfigurationService {
private static instance: ConfigurationService;
private observers: Map<string, BehaviorSubject<any>>;
private observers: Map<string, BehaviorSubject<unknown>>;
private constructor(){
this.observers = new Map<string, BehaviorSubject<any>>();
this.observers = new Map<string, BehaviorSubject<unknown>>();
}
private emitChange(key: string){
if(this.observers.has(key)){
@@ -29,7 +29,7 @@ export class ConfigurationService {
return t;
}
public set(key: string, value: any, persistant = true){
public set(key: string, value: unknown, persistant = true){
this.getPropperStorage(persistant).setItem(key, JSON.stringify(value));
this.emitChange(key);
}
@@ -41,8 +41,8 @@ export class ConfigurationService {
}
public watch<T>(key: DefaultConfigKey | string): Observable<T>{
if(this.observers.has(key)){ return this.observers.get(key); }
if(this.observers.has(key)){ return this.observers.get(key).asObservable() as Observable<T>; }
this.observers.set(key, new BehaviorSubject(this.get(key)));
return this.observers.get(key).asObservable();
return this.observers.get(key).asObservable() as Observable<T>;
}
}
+1 -1
View File
@@ -16,7 +16,7 @@ export class I18nService {
private readonly configService: ConfigurationService;
private dictionary: Object;
private dictionary = {};
public static getInstance(): I18nService{
if(!I18nService.instance){ I18nService.instance = new I18nService(); }
+3 -4
View File
@@ -1,7 +1,6 @@
import { defaultIfEmpty, share, shareReplay } from "rxjs/operators";
import { Observable } from "rxjs";
import { defaultIfEmpty, shareReplay } from "rxjs/operators";
import { Observable, identity } from "rxjs";
import { IpcRequest, IpcResponse } from "shared/models/ipc";
import { identity } from "rxjs";
export class IpcService{
@@ -31,7 +30,7 @@ export class IpcService{
return promise;
}
public sendLazy<T = any>(channel: string, request?: IpcRequest<T>): void{
public sendLazy<T = unknown>(channel: string, request?: IpcRequest<T>): void{
window.electron.ipcRenderer.sendMessage(channel, request);
}
+1 -2
View File
@@ -1,5 +1,4 @@
import { Observable } from "rxjs";
import { Subject } from "rxjs";
import { Observable, Subject } from "rxjs";
import { IpcService } from "./ipc.service";
export class LinkOpenerService{
+8 -9
View File
@@ -1,5 +1,4 @@
import { Observable } from "rxjs";
import { BehaviorSubject } from "rxjs";
import { Observable, BehaviorSubject } from "rxjs";
import { timeout } from "rxjs/operators";
export class ModalService{
@@ -7,8 +6,8 @@ export class ModalService{
private static instance: ModalService;
private _modalToShow$: BehaviorSubject<ModalComponent> = new BehaviorSubject(null);
private modalData: any = null;
private resolver: any;
private modalData: unknown = null;
private resolver: (value: ModalResponse| PromiseLike<ModalResponse>) => void = null;;
private constructor(){}
@@ -23,7 +22,7 @@ export class ModalService{
}
public getModalData<Type>(): Type{
return this.modalData;
return this.modalData as Type;
}
public getResolver(): any{
@@ -36,9 +35,9 @@ export class ModalService{
public async openModal<T, K>(modal: ModalComponent<T, K>, data?: K): Promise<ModalResponse<T>>{
this.close();
await timeout(100); //Must wait resolve
const promise = new Promise<ModalResponse<T>>((resolve) => { this.resolver = resolve; });
this._modalToShow$.next(modal);
await timeout(100); // Must wait resolve
const promise = new Promise<ModalResponse<T>>((resolve) => { this.resolver = resolve as (value: ModalResponse| PromiseLike<ModalResponse>) => void; });
this._modalToShow$.next(modal as ModalComponent);
promise.then(() => this.close());
if(data){ this.modalData = data; }
else{ this.modalData = null; }
@@ -51,7 +50,7 @@ export class ModalService{
}
export type ModalComponent<Return = unknown, Receive = any> = ({resolver, data}: {resolver : (x: ModalResponse<Return>) => void, data?: Receive}) => JSX.Element;
export type ModalComponent<Return = unknown, Receive = unknown> = ({resolver, data}: {resolver : (x: ModalResponse<Return>) => void, data?: Receive}) => JSX.Element;
export const enum ModalExitCode {
NO_CHOICE = -1,
@@ -2,7 +2,7 @@ import { MSModelType } from "shared/models/models/model-saber.model";
import { IpcService } from "../ipc.service";
import { VersionFolderLinkerService, VersionLinkerActionListener, VersionLinkerActionType } from "../version-folder-linker.service";
import { MODEL_TYPE_FOLDERS } from "shared/models/models/constants";
import { Observable, distinctUntilChanged, lastValueFrom, map, mergeMap, share } from "rxjs";
import { Observable, lastValueFrom, map } from "rxjs";
import { BSVersion } from "shared/bs-version.interface";
import { ModalExitCode, ModalService } from "../modale.service";
import { LinkModelsModal } from "renderer/components/modal/modal-types/models/link-models-modal.component";
@@ -12,7 +12,6 @@ import { BsmLocalModel } from "shared/models/models/bsm-local-model.interface";
import { ProgressBarService } from "../progress-bar.service";
import { OpenSaveDialogOption } from "shared/models/os/dialog.model";
import { ProgressionInterface } from "shared/models/progress-bar";
import { ArchiveProgress } from "shared/models/archive.interface";
import { NotificationService } from "../notification.service";
import { ConfigurationService } from "../configuration.service";
import { DeleteModelsModal } from "renderer/components/modal/modal-types/models/delete-models-modal.component";
@@ -120,7 +119,7 @@ export class ModelsManagerService {
lastValueFrom(exportProgress$).then(() => {
this.notifications.notifySuccess({title: "models.notifications.export-success.title", duration: 3000});
}).catch(e => {
}).catch(() => {
this.notifications.notifyError({title: "notifications.types.error", desc: "notifications.common.msg.error-occurred", duration: 3000});
}).finally(() => {
this.progressBar.hide(true);
@@ -24,7 +24,7 @@ export class NotificationService{
// TODO : Make actions work and adapt with "watch" remork
this.ipc.watch<Notification>("show-notification").subscribe(notification => {
this.notify(notification as any as Notification);
this.notify(notification as unknown as Notification);
});
}
@@ -1,5 +1,5 @@
import { BsvMapDetail } from "shared/models/maps";
import { BsvPlaylist, BsvPlaylistPage, SearchParams } from "shared/models/maps/beat-saver.model";
import { BsvPlaylist, SearchParams } from "shared/models/maps/beat-saver.model";
import { IpcService } from "../ipc.service";
export class BeatSaverService {
@@ -1,5 +1,5 @@
import { LinkOptions, UnlinkOptions } from "main/services/folder-linker.service";
import { map, distinctUntilChanged, filter, mergeMap, share, shareReplay } from "rxjs/operators";
import { map, distinctUntilChanged, filter, mergeMap, shareReplay } from "rxjs/operators";
import { BehaviorSubject, Observable } from "rxjs";
import { BSVersion } from "shared/bs-version.interface";
import { IpcService } from "./ipc.service";
+1 -1
View File
@@ -46,7 +46,7 @@ export default function Launcher() {
<div className="relative flex flex-col items-center justify-center pt-10">
<motion.div ref={constraintsRef}>
<motion.div drag dragConstraints={constraintsRef} animate={{rotate: [0, 10, 0]}} transition={{ duration: .6, repeat: Infinity, repeatDelay: 1.6 }}>
<BsManagerIcon className={"w-52 cursor-pointer"}/>
<BsManagerIcon className="w-52 cursor-pointer"/>
</motion.div>
</motion.div>
<span className="relative text-lg mt-16 mb-24 uppercase italic text-main-color-1 dark:text-gray-200">{t(text)}</span>