mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
Merge branch 'master' into feature/launch-bs-from-shortcut
This commit is contained in:
+1
-1
@@ -19,7 +19,7 @@ We'd also love PRs. If you're thinking of a large PR, we advise opening up an is
|
||||
|
||||
1. [Fork][fork] and clone the repository.
|
||||
1. Configure and install the dependencies: `npm install`.
|
||||
1. Create a new branch following naming convention: `git checkout -b (feature|bufix|hotfix)/(short-description)(/issue-id)`.
|
||||
1. Create a new branch following naming convention: `git checkout -b (feature|bugfix|hotfix|chore)/(short-description)(/issue-id)`.
|
||||
1. Make your change, test, and make sure BSManager work fine.
|
||||
1. Push to your fork and [submit a pull request][pr].
|
||||
1. Pat your self on the back and wait for your pull request to be reviewed and merged.
|
||||
|
||||
@@ -9,5 +9,6 @@
|
||||
{"username": "Adam"},
|
||||
{"username": "Cabalia"},
|
||||
{"username": "Anonymously42", "type": "diamond", "link": "https://www.twitch.tv/anonymously42tv"},
|
||||
{"username": "En4Yuz"}
|
||||
{"username": "En4Yuz"},
|
||||
{"username": "AndyIsHereBoi", "type": "gold"}
|
||||
]
|
||||
Generated
+591
-552
File diff suppressed because it is too large
Load Diff
+4
-3
@@ -151,6 +151,7 @@
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.3.0",
|
||||
"@types/archiver": "^5.3.1",
|
||||
"@types/color": "^3.0.3",
|
||||
"@types/dateformat": "^5.0.0",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "17.0.23",
|
||||
@@ -178,7 +179,7 @@
|
||||
"css-minimizer-webpack-plugin": "^4.1.0",
|
||||
"detect-port": "^1.3.0",
|
||||
"electron": "^24.3.1",
|
||||
"electron-builder": "^23.6.0",
|
||||
"electron-builder": "^24.4.0",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"electron-notarize": "^1.2.1",
|
||||
"electron-rebuild": "^3.2.9",
|
||||
@@ -230,7 +231,6 @@
|
||||
"dependencies": {
|
||||
"@node-steam/vdf": "^2.2.0",
|
||||
"@tippyjs/react": "^4.2.6",
|
||||
"@types/color": "^3.0.3",
|
||||
"archiver": "^5.3.1",
|
||||
"color": "^4.2.3",
|
||||
"dateformat": "^5.0.3",
|
||||
@@ -238,7 +238,7 @@
|
||||
"electron-debug": "^3.2.0",
|
||||
"electron-log": "^4.4.8",
|
||||
"electron-store": "^8.1.0",
|
||||
"electron-updater": "^6.0.3",
|
||||
"electron-updater": "^6.1.1",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"framer-motion": "^10.12.16",
|
||||
"fs-extra": "^11.1.1",
|
||||
@@ -248,6 +248,7 @@
|
||||
"md5-file": "^5.0.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"node-stream-zip": "^1.15.0",
|
||||
"ps-list": "^7.2.0",
|
||||
"react": "^18.2.0",
|
||||
"react-colorful": "^5.6.1",
|
||||
"react-dom": "^18.2.0",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ipcMain } from 'electron';
|
||||
import { ipcMain, shell } from 'electron';
|
||||
import { UtilsService } from '../services/utils.service';
|
||||
import { BSVersionLibService } from '../services/bs-version-lib.service'
|
||||
import { BSVersion } from 'shared/bs-version.interface';
|
||||
@@ -38,7 +38,9 @@ ipcMain.on('bs-version.installed-versions', async (event, req: IpcRequest<void>)
|
||||
ipcMain.on("bs-version.open-folder", async (event, req: IpcRequest<BSVersion>) => {
|
||||
const localVersionService = BSLocalVersionService.getInstance();
|
||||
const versionFolder = await localVersionService.getVersionPath(req.args);
|
||||
(await pathExist(versionFolder)) && exec(`start "" "${versionFolder}"`);
|
||||
if (!(await pathExist(versionFolder)))
|
||||
return;
|
||||
shell.openPath(versionFolder);
|
||||
});
|
||||
|
||||
ipcMain.on("bs-version.edit", async (event, req: IpcRequest<{version: BSVersion, name: string, color: string}>) => {
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ const installExtensions = async () => {
|
||||
const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
|
||||
const extensions = ['REACT_DEVELOPER_TOOLS'];
|
||||
|
||||
return installer.default(extensions.map((name) => installer[name]), forceDownload).catch(console.log);
|
||||
return installer.default(extensions.map((name) => installer[name]), forceDownload).catch(console.error);
|
||||
};
|
||||
|
||||
const createWindow = async (window: AppWindow = "launcher.html") => {
|
||||
|
||||
@@ -66,9 +66,12 @@ export class BSInstallerService{
|
||||
return new Promise(resolve => {
|
||||
if(this.downloadProcess?.killed && !this.downloadProcess?.pid){ return resolve(false); }
|
||||
|
||||
this.downloadProcess.once('exit', () => resolve(true));
|
||||
|
||||
ctrlc(this.downloadProcess.pid);
|
||||
this.downloadProcess?.once('exit', () => resolve(true));
|
||||
if (process.platform === 'win32') {
|
||||
ctrlc(this.downloadProcess.pid);
|
||||
} else {
|
||||
this.downloadProcess.kill();
|
||||
}
|
||||
setTimeout(() => resolve(false), 3000);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -55,14 +55,14 @@ export class BSLauncherService{
|
||||
return rename(steamVrFolder + ".bak", steamVrFolder).catch(log.error);
|
||||
}
|
||||
|
||||
public isBsRunning(): boolean{
|
||||
return this.bsProcess?.connected || this.utilsService.taskRunning(BS_EXECUTABLE) === true;
|
||||
public async isBsRunning(): Promise<boolean> {
|
||||
return this.bsProcess?.connected || await this.utilsService.taskRunning(BS_EXECUTABLE) === true;
|
||||
}
|
||||
|
||||
// TODO : Rework with shortcuts implementation
|
||||
public async launch(launchOptions: LaunchOption): Promise<LaunchResult>{
|
||||
if(this.isBsRunning() === true){ return "BS_ALREADY_RUNNING" }
|
||||
if(launchOptions.version.oculus && this.oculusService.oculusRunning() === false){ return "OCULUS_NOT_RUNNING" }
|
||||
if(await this.isBsRunning() === true){ return "BS_ALREADY_RUNNING" }
|
||||
if(launchOptions.version.oculus && await this.oculusService.oculusRunning() === false){ return "OCULUS_NOT_RUNNING" }
|
||||
|
||||
const steamRunning = await this.steamService.steamRunning().catch(() => true); // True if error (error not not means that steam is not running)
|
||||
if(!launchOptions.version.oculus && !steamRunning){
|
||||
@@ -167,7 +167,7 @@ export class BSLauncherService{
|
||||
return obs.error({type: BSLaunchErrorType.BS_ALREADY_RUNNING} as BSLaunchErrorEvent);
|
||||
}
|
||||
|
||||
if(launchOptions.version.oculus && this.oculusService.oculusRunning() === false){
|
||||
if(launchOptions.version.oculus && (await this.oculusService.oculusRunning()) === false){
|
||||
return obs.error({type: BSLaunchErrorType.OCULUS_NOT_RUNNING} as BSLaunchErrorEvent);
|
||||
}
|
||||
|
||||
@@ -214,4 +214,4 @@ export class BSLauncherService{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export class OculusService {
|
||||
this.utils = UtilsService.getInstance();
|
||||
}
|
||||
|
||||
public oculusRunning(): boolean | null{
|
||||
public async oculusRunning(): Promise<boolean> {
|
||||
return this.utils.taskRunning("OculusClient.exe");
|
||||
}
|
||||
|
||||
@@ -64,4 +64,4 @@ export class OculusService {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import { readFile } from "fs/promises";
|
||||
import { spawn } from "child_process";
|
||||
import { pathExist } from "../helpers/fs.helpers";
|
||||
import log from "electron-log";
|
||||
import psList from 'ps-list';
|
||||
import { app } from "electron";
|
||||
|
||||
export class SteamService{
|
||||
|
||||
@@ -25,40 +27,47 @@ export class SteamService{
|
||||
return SteamService.instance;
|
||||
}
|
||||
|
||||
public async getActiveUser(): Promise<number>{
|
||||
const res = await regedit.promisified.list(["HKCU\\Software\\Valve\\Steam\\ActiveProcess"]);
|
||||
const keys = res?.["HKCU\\Software\\Valve\\Steam\\ActiveProcess"];
|
||||
public async getActiveUser(): Promise<number>{
|
||||
const res = await regedit.promisified.list(["HKCU\\Software\\Valve\\Steam\\ActiveProcess"]);
|
||||
const keys = res?.["HKCU\\Software\\Valve\\Steam\\ActiveProcess"];
|
||||
if(!keys?.exists){ throw "Key \"HKCU\\Software\\Valve\\Steam\\ActiveProcess\" not exist"; }
|
||||
return (keys.values?.ActiveUser.value || undefined) as number;
|
||||
}
|
||||
|
||||
if(!keys?.exists){ throw "Key \"HKCU\\Software\\Valve\\Steam\\ActiveProcess\" not exist"; }
|
||||
|
||||
return (keys.values?.ActiveUser.value || undefined) as number;
|
||||
}
|
||||
|
||||
public steamRunning(): Promise<boolean>{
|
||||
return this.getActiveUser()
|
||||
.then(userId => !!userId)
|
||||
.catch(e => {log.error(e); throw e})
|
||||
public async steamRunning(): Promise<boolean>{
|
||||
if (process.platform === 'win32') {
|
||||
return !!(await this.getActiveUser());
|
||||
}
|
||||
return await psList()
|
||||
.then(processes => !!processes.find(process => process.cmd.includes('steam')))
|
||||
.catch(e => {log.error(e); throw e})
|
||||
}
|
||||
|
||||
public async getSteamPath(): Promise<string>{
|
||||
|
||||
if(!!this.steamPath){ return this.steamPath; }
|
||||
if(this.steamPath){ return this.steamPath; }
|
||||
|
||||
switch (process.platform) {
|
||||
case "linux":
|
||||
this.steamPath = path.join(app.getPath('home'), '.steam', "steam");
|
||||
return this.steamPath;
|
||||
case "win32":
|
||||
const [win32Res, win64Res] = await Promise.all([
|
||||
regedit.promisified.list(['HKLM\\SOFTWARE\\Valve\\Steam']),
|
||||
regedit.promisified.list(['HKLM\\SOFTWARE\\WOW6432Node\\Valve\\Steam'])
|
||||
regedit.promisified.list(['HKLM\\SOFTWARE\\Valve\\Steam']),
|
||||
regedit.promisified.list(['HKLM\\SOFTWARE\\WOW6432Node\\Valve\\Steam'])
|
||||
]);
|
||||
|
||||
const [win32, win64] = [win32Res["HKLM\\SOFTWARE\\Valve\\Steam"], win64Res["HKLM\\SOFTWARE\\WOW6432Node\\Valve\\Steam"]];
|
||||
|
||||
|
||||
let res = '';
|
||||
|
||||
if(win64.exists && win64?.values?.InstallPath?.value){ res = win64.values.InstallPath.value as string; }
|
||||
else if(win32.exists && win32?.values?.InstallPath?.value){ res = win32.values.InstallPath.value as string; }
|
||||
|
||||
this.steamPath = res;
|
||||
return this.steamPath;
|
||||
return res;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async getGameFolder(gameId: string, gameFolder?: string): Promise<string>{
|
||||
try{
|
||||
@@ -88,7 +97,7 @@ export class SteamService{
|
||||
const process = spawn("start", ["steam://open/games"], {shell: true});
|
||||
|
||||
process.on("error", log.error);
|
||||
|
||||
|
||||
return new Promise(async (resolve, reject) => {
|
||||
// Every 3 seconds check if steam is running
|
||||
const interval = setInterval(async () => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { app, BrowserWindow } from "electron";
|
||||
import { IpcResponse } from "shared/models/ipc";
|
||||
import log from "electron-log";
|
||||
import { AppWindow } from "shared/models/window-manager/app-window.model";
|
||||
import psList from "ps-list";
|
||||
|
||||
|
||||
// TODO : REFACTOR
|
||||
@@ -33,10 +34,10 @@ export class UtilsService{
|
||||
public setMainWindows(windows: Map<AppWindow, BrowserWindow>){ this.windows = windows; }
|
||||
public getMainWindows(win: AppWindow){ return this.windows.get(win); }
|
||||
|
||||
public taskRunning(task: string): boolean | null{
|
||||
public async taskRunning(task: string): Promise<boolean> {
|
||||
try{
|
||||
const tasks = spawnSync('tasklist').stdout;
|
||||
return tasks.toString().includes(task);
|
||||
const processes = await psList();
|
||||
return !!processes.find(process => process.cmd.includes(task));
|
||||
}
|
||||
catch(error){
|
||||
log.error(error);
|
||||
|
||||
+18
-10
@@ -4,7 +4,6 @@ import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useSta
|
||||
import { BsmLocalMap } from "shared/models/maps/bsm-local-map.interface"
|
||||
import { Subscription } from "rxjs"
|
||||
import { MapFilter } from "shared/models/maps/beat-saver.model"
|
||||
import { useInView } from "framer-motion"
|
||||
import { MapsDownloaderService } from "renderer/services/maps-downloader.service"
|
||||
import { VariableSizeList } from "react-window"
|
||||
import { MapsRow } from "./maps-row.component"
|
||||
@@ -18,16 +17,18 @@ import BeatConflict from "../../../../assets/images/apngs/beat-conflict.png"
|
||||
import { BsmImage } from "../shared/bsm-image.component"
|
||||
import { BsmButton } from "../shared/bsm-button.component"
|
||||
import TextProgressBar from "../progress-bar/text-progress-bar.component"
|
||||
import { useChangeOnce } from "renderer/hooks/use-change-once.hook"
|
||||
|
||||
type Props = {
|
||||
version: BSVersion,
|
||||
className?: string,
|
||||
filter?: MapFilter
|
||||
search?: string,
|
||||
linked?: boolean
|
||||
linked?: boolean,
|
||||
isActive?: boolean
|
||||
}
|
||||
|
||||
export const LocalMapsListPanel = forwardRef(({version, className, filter, search, linked} : Props, forwardRef) => {
|
||||
export const LocalMapsListPanel = forwardRef(({version, className, filter, search, linked, isActive} : Props, forwardRef) => {
|
||||
|
||||
const mapsManager = MapsManagerService.getInstance();
|
||||
const mapsDownloader = MapsDownloaderService.getInstance();
|
||||
@@ -35,13 +36,13 @@ export const LocalMapsListPanel = forwardRef(({version, className, filter, searc
|
||||
const os = OsDiagnosticService.getInstance();
|
||||
|
||||
const t = useTranslation();
|
||||
const ref = useRef(null)
|
||||
const isVisible = useInView(ref, {once: true, amount: .5});
|
||||
const ref = useRef(null);
|
||||
const [maps, setMaps] = useState<BsmLocalMap[]>(null);
|
||||
const [subs] = useState<Subscription[]>([]);
|
||||
const [selectedMaps$] = useState(new BehaviorSubject<BsmLocalMap[]>([]));
|
||||
const [itemPerRow, setItemPerRow] = useState(2);
|
||||
const [listHeight, setListHeight] = useState(0);
|
||||
const isActiveOnce = useChangeOnce(isActive, true);
|
||||
|
||||
const [loadPercent$] = useState(new BehaviorSubject(0));
|
||||
|
||||
@@ -64,7 +65,7 @@ export const LocalMapsListPanel = forwardRef(({version, className, filter, searc
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if(isVisible){
|
||||
if(isActiveOnce){
|
||||
loadMaps();
|
||||
mapsDownloader.addOnMapDownloadedListener((map, targerVersion) => {
|
||||
if(targerVersion !== version){ return; }
|
||||
@@ -78,11 +79,11 @@ export const LocalMapsListPanel = forwardRef(({version, className, filter, searc
|
||||
subs.forEach(s => s.unsubscribe());
|
||||
mapsDownloader.removeOnMapDownloadedListener(loadMaps);
|
||||
}
|
||||
}, [isVisible, version, linked]);
|
||||
}, [isActiveOnce, version, linked]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if(!isVisible){ return () => {}; }
|
||||
if(!isActiveOnce){ return; }
|
||||
|
||||
const updateItemPerRow = (listWidth: number) => {
|
||||
const newPerRow = Math.min(Math.floor(listWidth / 400), 3);
|
||||
@@ -106,7 +107,7 @@ export const LocalMapsListPanel = forwardRef(({version, className, filter, searc
|
||||
sub.unsubscribe();
|
||||
}
|
||||
|
||||
}, [isVisible, itemPerRow])
|
||||
}, [isActiveOnce, itemPerRow])
|
||||
|
||||
const loadMaps = () => {
|
||||
|
||||
@@ -136,10 +137,17 @@ export const LocalMapsListPanel = forwardRef(({version, className, filter, searc
|
||||
const removeMapsFromList = (mapsToRemove: BsmLocalMap[]) => {
|
||||
const filtredMaps = maps.filter(map => !mapsToRemove.some(toDeleteMaps => map.hash === toDeleteMaps.hash));
|
||||
setMaps(() => filtredMaps);
|
||||
|
||||
const filtredSelectedMaps = selectedMaps$.value.filter(map => !mapsToRemove.some(toDeleteMaps => map.hash === toDeleteMaps.hash));
|
||||
selectedMaps$.next(filtredSelectedMaps);
|
||||
};
|
||||
|
||||
const handleDelete = useCallback((map: BsmLocalMap) => {
|
||||
mapsManager.deleteMaps([map], version).then(res => res && removeMapsFromList([map]));
|
||||
mapsManager.deleteMaps([map], version).then(res => {
|
||||
if(!res){ return; }
|
||||
removeMapsFromList([map]);
|
||||
|
||||
});
|
||||
}, [version, maps]);
|
||||
|
||||
const onMapSelected = useCallback((map: BsmLocalMap) => {
|
||||
|
||||
+5
-4
@@ -21,10 +21,11 @@ import { VersionFolderLinkerService, VersionLinkerActionListener } from "rendere
|
||||
|
||||
|
||||
type Props = {
|
||||
version?: BSVersion
|
||||
version?: BSVersion,
|
||||
isActive?: boolean
|
||||
}
|
||||
|
||||
export function MapsPlaylistsPanel({version}: Props) {
|
||||
export function MapsPlaylistsPanel({version, isActive}: Props) {
|
||||
|
||||
const mapsService = MapsManagerService.getInstance();
|
||||
const mapsDownloader = MapsDownloaderService.getInstance();
|
||||
@@ -63,7 +64,7 @@ export function MapsPlaylistsPanel({version}: Props) {
|
||||
linker.removeVersionFolderUnlinkedListener(onMapsLinked);
|
||||
}
|
||||
|
||||
}, [version]);
|
||||
}, [version, isActive]);
|
||||
|
||||
const loadMapIsLinked = () => {
|
||||
mapsService.versionHaveMapsLinked(version).then(setMapsLinked);
|
||||
@@ -160,7 +161,7 @@ export function MapsPlaylistsPanel({version}: Props) {
|
||||
<div className="w-full h-full flex flex-col bg-light-main-color-3 dark:bg-main-color-2 rounded-md shadow-black shadow-md overflow-hidden">
|
||||
<TabNavBar className="!rounded-none shadow-sm" tabIndex={tabIndex} tabsText={["misc.maps", "misc.playlists"]} onTabChange={setTabIndex} renderTab={renderTab}/>
|
||||
<div className="w-full grow min-h-0 flex flex-row items-center transition-transform duration-300" style={{transform: `translate(${-(tabIndex * 100)}%, 0)`}}>
|
||||
<LocalMapsListPanel ref={mapsRef} className="w-full h-full shrink-0 flex flex-col" version={version} filter={mapFilter} search={mapSearch} linked={mapsLinked}/>
|
||||
<LocalMapsListPanel isActive={isActive && tabIndex === 0} ref={mapsRef} className="w-full h-full shrink-0 flex flex-col" version={version} filter={mapFilter} search={mapSearch} linked={mapsLinked}/>
|
||||
<div className="w-full h-full shrink-0 flex flex-col justify-center items-center content-center gap-2 overflow-hidden text-gray-800 dark:text-gray-200">
|
||||
<BsmImage className="rounded-md" image={wipGif}/>
|
||||
<span>Coming soon</span>
|
||||
|
||||
@@ -41,7 +41,6 @@ export function BsmButton({className, style, imgClassName, iconClassName, icon,
|
||||
|
||||
const textColor = (() => {
|
||||
if(primaryColor){
|
||||
console.log(getCorrectTextColor(primaryColor), text);
|
||||
return getCorrectTextColor(primaryColor);
|
||||
}
|
||||
return typeColor ? "white" : undefined;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import equal from "fast-deep-equal";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
export function useChangeOnce<T = unknown>(initialValue: T, onlyFirstIfTruthy?: boolean): T {
|
||||
const [trackedValue, setTrackedValue] = useState<T>(initialValue);
|
||||
const didChangeOnceRef = useRef<boolean>(onlyFirstIfTruthy ? !!initialValue : false);
|
||||
|
||||
useEffect(() => {
|
||||
if(didChangeOnceRef.current || equal(initialValue, trackedValue)){ return; }
|
||||
|
||||
setTrackedValue(() => initialValue);
|
||||
didChangeOnceRef.current = true;
|
||||
|
||||
}, [initialValue]);
|
||||
|
||||
return trackedValue;
|
||||
}
|
||||
@@ -3,12 +3,9 @@ import { MapsPlaylistsPanel } from "renderer/components/maps-mangement-component
|
||||
import { ModelsPanel } from "renderer/components/models-management/models-panel.component";
|
||||
import { TabNavBar } from "renderer/components/shared/tab-nav-bar.component";
|
||||
import { Slideshow } from "renderer/components/slideshow/slideshow.component";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
|
||||
export function SharedContentsPage() {
|
||||
|
||||
const t = useTranslation();
|
||||
|
||||
const [tabIndex, setTabIndex] = useState(0);
|
||||
|
||||
return (
|
||||
@@ -17,7 +14,7 @@ export function SharedContentsPage() {
|
||||
<TabNavBar className='my-4' tabIndex={tabIndex} tabsText={["misc.maps", "misc.models"]} onTabChange={setTabIndex}/>
|
||||
<div className='w-full min-h-0 grow flex transition-transform duration-300' style={{transform: `translate(${-(tabIndex * 100)}%, 0)`}}>
|
||||
<div className="w-full shrink-0 px-3 pb-3 flex flex-col items-center">
|
||||
<MapsPlaylistsPanel/>
|
||||
<MapsPlaylistsPanel isActive={tabIndex === 0}/>
|
||||
</div>
|
||||
<div className="w-full shrink-0 px-3 pb-3 flex flex-col items-center">
|
||||
<ModelsPanel isActive={tabIndex === 1}/>
|
||||
|
||||
@@ -80,7 +80,7 @@ export function VersionViewer() {
|
||||
<div className='w-full min-h-0 grow flex transition-transform duration-300' style={{transform: `translate(${-(currentTabIndex * 100)}%, 0)`}}>
|
||||
<LaunchSlide version={state}/>
|
||||
<div className="w-full shrink-0 px-3 pb-3 flex flex-col items-center">
|
||||
<MapsPlaylistsPanel version={state}/>
|
||||
<MapsPlaylistsPanel version={state} isActive={currentTabIndex === 1}/>
|
||||
</div>
|
||||
<div className="w-full shrink-0 px-3 pb-3 flex flex-col items-center">
|
||||
<ModelsPanel version={state} isActive={currentTabIndex === 2} goToMods={() => setCurrentTabIndex(() => 3)}/>
|
||||
|
||||
@@ -86,7 +86,7 @@ export class MapsManagerService {
|
||||
|
||||
public async deleteMaps(maps: BsmLocalMap[], version?: BSVersion): Promise<boolean>{
|
||||
|
||||
const versionLinked = await this.versionHaveMapsLinked(version);
|
||||
const versionLinked = !version || await this.versionHaveMapsLinked(version);
|
||||
|
||||
const askModal = maps.length > 1 || !this.config.get<boolean>(MapsManagerService.REMEMBER_CHOICE_DELETE_MAP_KEY);
|
||||
|
||||
|
||||
+8
-1
@@ -1,5 +1,12 @@
|
||||
const colors = require('tailwindcss/colors');
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
|
||||
// Suppress deprecation warnings during build
|
||||
delete colors.lightBlue;
|
||||
delete colors.warmGray;
|
||||
delete colors.trueGray;
|
||||
delete colors.coolGray;
|
||||
delete colors.blueGray;
|
||||
|
||||
module.exports = {
|
||||
darkMode: 'class',
|
||||
content: ['./src/renderer/**/*.{js,jsx,ts,tsx,ejs}'],
|
||||
|
||||
Reference in New Issue
Block a user