mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
[chore] fix lint errors
This commit is contained in:
@@ -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);
|
||||
|
||||
+3
-4
@@ -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">
|
||||
|
||||
+1
-1
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
+2
-2
@@ -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,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,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>;
|
||||
}
|
||||
}
|
||||
@@ -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(); }
|
||||
|
||||
@@ -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,5 +1,4 @@
|
||||
import { Observable } from "rxjs";
|
||||
import { Subject } from "rxjs";
|
||||
import { Observable, Subject } from "rxjs";
|
||||
import { IpcService } from "./ipc.service";
|
||||
|
||||
export class LinkOpenerService{
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user