Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ jobs:
if: matrix.platform == 'web'
run: npm run lint

- name: Run TypeScript type checking (Web)
if: matrix.platform == 'web'
run: npm run typecheck

- name: Build Frontend (Web)
if: matrix.platform == 'web'
env:
Expand Down
5 changes: 5 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ export default tseslint.config({
ignores: ["src/livesplit-core/**", "src/type-definitions/**"],
extends: tseslint.configs.recommendedTypeChecked,
rules: {
"@typescript-eslint/consistent-type-exports": "error",
"@typescript-eslint/consistent-type-imports": [
"error",
{ fixStyle: "inline-type-imports" },
],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-floating-promises": "off",
"@typescript-eslint/no-misused-promises": "off",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"build:core:release": "node buildCore.js --release",
"build:core:deploy": "node buildCore.js --max-opt --nightly",
"lint": "eslint src",
"typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.node.json",
"publish": "vite build",
"serve": "vite",
"tauri:icons": "tauri icon src/assets/icon.png",
Expand Down
15 changes: 7 additions & 8 deletions src/api/GameList.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import {
getGameHeaders,
getCategories as apiGetCategories,
Category,
type Category,
getRuns as apiGetRuns,
getPlatforms as apiGetPlatforms,
getRegions as apiGetRegions,
getGame as apiGetGame,
Game,
Run,
PlayersEmbedded,
type Game,
type Run,
type PlayersEmbedded,
} from "./SpeedrunCom";
import { Option } from "../util/OptionUtil";
import { type Option } from "../util/OptionUtil";
import { FuzzyList } from "../livesplit-core";

const gameList: string[] = [];
Expand Down Expand Up @@ -197,11 +197,10 @@ export async function downloadLeaderboard(
if (categories === undefined) {
return;
}
const index = categories.map((c) => c.name).indexOf(categoryName);
if (index < 0) {
const category = categories.find((c) => c.name === categoryName);
if (category === undefined) {
return;
}
const category = categories[index];
const runPages = await apiGetRuns(
true,
category.id,
Expand Down
4 changes: 2 additions & 2 deletions src/api/LiveSplitServer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { toast } from "react-toastify";
import { LSOCommandSink } from "../util/LSOCommandSink";
import { type LSOCommandSink } from "../util/LSOCommandSink";
import { ServerProtocol } from "../livesplit-core/livesplit_core";
import { Event } from "../livesplit-core";
import { type Event } from "../livesplit-core";

export class LiveSplitServer {
private connection: WebSocket;
Expand Down
2 changes: 1 addition & 1 deletion src/api/SpeedrunCom.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Option, map } from "../util/OptionUtil";
import { type Option, map } from "../util/OptionUtil";

const BASE_URI = "https://www.speedrun.com/api/v1/";

Expand Down
10 changes: 5 additions & 5 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ try {
const root = createRoot(container!);
root.render(
<LiveSplit
splits={splits}
layout={layout}
comparison={comparison}
{...(splits === undefined ? {} : { splits })}
{...(layout === undefined ? {} : { layout })}
{...(comparison === undefined ? {} : { comparison })}
timingMethod={timingMethod}
hotkeys={hotkeys}
splitsKey={splitsKey}
{...(hotkeys === undefined ? {} : { hotkeys })}
{...(splitsKey === undefined ? {} : { splitsKey })}
layoutWidth={layoutWidth}
layoutHeight={layoutHeight}
generalSettings={generalSettings}
Expand Down
2 changes: 1 addition & 1 deletion src/localization/chinese-traditional.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Label } from ".";
import { type Label } from ".";
import { resolveChineseSimplified } from "./chinese-simplified";

export function resolveChineseTraditional(text: Label): string {
Expand Down
5 changes: 3 additions & 2 deletions src/platform/CORS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ export async function corsBustingFetch(
signal?: AbortSignal,
): Promise<ArrayBuffer> {
let response: Response | undefined;
const options = signal === undefined ? {} : { signal };
if (window.__TAURI__ != null) {
response = await window.__TAURI__.http.fetch(url, { signal });
response = await window.__TAURI__.http.fetch(url, options);
} else {
response = await fetch(url, { signal });
response = await fetch(url, options);
}
return response.arrayBuffer();
}
2 changes: 1 addition & 1 deletion src/platform/Hotkeys.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CommandSinkRef, HotkeyConfig, HotkeySystem, Language } from "../livesplit-core";
import { type CommandSinkRef, HotkeyConfig, HotkeySystem, type Language } from "../livesplit-core";
import { expect } from "../util/OptionUtil";

export interface HotkeyImplementation {
Expand Down
12 changes: 6 additions & 6 deletions src/storage/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { openDB, IDBPDatabase } from "idb";
import { Option, assert } from "../util/OptionUtil";
import { RunRef, Run, TimingMethod, Language } from "../livesplit-core";
import { openDB, type IDBPDatabase } from "idb";
import { type Option, assert } from "../util/OptionUtil";
import { type RunRef, Run, TimingMethod, type Language } from "../livesplit-core";
import {
GeneralSettings,
type GeneralSettings,
MANUAL_GAME_TIME_SETTINGS_DEFAULT,
THEME_MODE_AUTOMATIC,
} from "../ui/views/MainSettings";
Expand Down Expand Up @@ -35,8 +35,8 @@ function getSplitsInfo(run: RunRef): SplitsInfo {
return {
game: run.gameName(),
category: run.extendedCategoryName(true, true, true),
realTime,
gameTime,
...(realTime === undefined ? {} : { realTime }),
...(gameTime === undefined ? {} : { gameTime }),
};
}

Expand Down
12 changes: 9 additions & 3 deletions src/ui/Embed.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { Option } from "../util/OptionUtil";
import { type Option } from "../util/OptionUtil";

import runEditorClasses from "../css/RunEditor.module.css";

Expand Down Expand Up @@ -29,7 +29,10 @@ function tryYoutubeFromUri(uri: string): Option<React.JSX.Element> {
result = youtubeBase2.exec(uri);
}
if (result !== null) {
return resolveYoutube(result[1]);
const videoId = result[1];
if (videoId !== undefined) {
return resolveYoutube(videoId);
}
}
return null;
}
Expand All @@ -42,7 +45,10 @@ function tryTwitchFromUri(uri: string): Option<React.JSX.Element> {
result = twitchBase2.exec(uri);
}
if (result !== null) {
return resolveTwitch(result[3]);
const videoId = result[3];
if (videoId !== undefined) {
return resolveTwitch(videoId);
}
}
return null;
}
Expand Down
38 changes: 21 additions & 17 deletions src/ui/LiveSplit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import {
RunEditor,
Segment,
Timer,
HotkeyConfig,
type HotkeyConfig,
LayoutState,
LayoutStateJson,
TimingMethod,
TimerPhase,
type LayoutStateJson,
type TimingMethod,
type TimerPhase,
Event,
LayoutRefMut,
Language,
type LayoutRefMut,
type Language,
} from "../livesplit-core";
import { Layout as ShowLayout } from "./components/Layout";
import {
Expand All @@ -25,7 +25,7 @@ import {
openFileAsString,
} from "../util/FileUtil";
import {
Option,
type Option,
assertNull,
expect,
maybeDisposeAndThen,
Expand All @@ -34,14 +34,14 @@ import {
import { LayoutEditor as LayoutEditorComponent } from "./views/LayoutEditor";
import { RunEditor as RunEditorComponent } from "./views/RunEditor";
import {
GeneralSettings,
type GeneralSettings,
MainSettings as SettingsEditorComponent,
THEME_MODE_AUTOMATIC,
THEME_MODE_DARK,
} from "./views/MainSettings";
import { TimerView } from "./views/TimerView";
import { About } from "./views/About";
import { SplitsSelection, EditingInfo } from "./views/SplitsSelection";
import { SplitsSelection, type EditingInfo } from "./views/SplitsSelection";
import { LayoutView } from "./views/LayoutView";
import { ToastContainer, toast } from "react-toastify";
import * as Storage from "../storage";
Expand All @@ -52,10 +52,10 @@ import {
TheRunClient,
WebRenderer,
} from "../livesplit-core/livesplit_core";
import { LiveSplitServer } from "../api/LiveSplitServer";
import { type LiveSplitServer } from "../api/LiveSplitServer";
import { LSOCommandSink } from "../util/LSOCommandSink";
import { DialogContainer } from "./components/Dialog";
import { createHotkeys, HotkeyImplementation } from "../platform/Hotkeys";
import { createHotkeys, type HotkeyImplementation } from "../platform/Hotkeys";
import { Menu } from "lucide-react";
import { createRoot } from "react-dom/client";

Expand Down Expand Up @@ -118,7 +118,11 @@ function isMenuLocked(menuKind: MenuKind) {
type Menu =
| { kind: MenuKind.Timer }
| { kind: MenuKind.Splits }
| { kind: MenuKind.RunEditor; editor: RunEditor; splitsKey?: number }
| {
kind: MenuKind.RunEditor;
editor: RunEditor;
splitsKey: number | undefined;
}
| { kind: MenuKind.Layout }
| { kind: MenuKind.LayoutEditor; editor: LayoutEditor }
| { kind: MenuKind.MainSettings; config: HotkeyConfig }
Expand Down Expand Up @@ -147,7 +151,7 @@ export interface State {
layoutWidth: number;
layoutHeight: number;
menu: Menu;
openedSplitsKey?: number;
openedSplitsKey: number | undefined;
sidebarOpen: boolean;
sidebarTransitionsEnabled: boolean;
storedLayoutWidth: number;
Expand Down Expand Up @@ -323,7 +327,7 @@ export class LiveSplit extends React.Component<Props, State> {
}
}

public componentDidMount() {
public override componentDidMount() {
this.scrollEvent = { handleEvent: (e: WheelEvent) => this.onScroll(e) };
window.addEventListener("wheel", this.scrollEvent);
this.rightClickEvent = {
Expand Down Expand Up @@ -363,11 +367,11 @@ export class LiveSplit extends React.Component<Props, State> {
}
}

public componentDidUpdate() {
public override componentDidUpdate() {
this.handleAutomaticResize();
}

public componentWillUnmount() {
public override componentWillUnmount() {
window.removeEventListener(
"wheel",
expect(
Expand Down Expand Up @@ -416,7 +420,7 @@ export class LiveSplit extends React.Component<Props, State> {
}
}

public render() {
public override render() {
let view: React.JSX.Element | undefined;

if (this.state.menu.kind === MenuKind.RunEditor) {
Expand Down
26 changes: 16 additions & 10 deletions src/ui/components/ColorPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { ChangeEvent, MouseEvent } from "react";
import React, { type ChangeEvent, type MouseEvent } from "react";
import { useEffect, useState } from "react";
import { Color } from "../../livesplit-core";
import { type Color } from "../../livesplit-core";
import { Pipette } from "lucide-react";

import classes from "../../css/ColorPicker.module.css";
Expand Down Expand Up @@ -417,10 +417,10 @@ function Hex({
.toString(16)
.padStart(2, "0")}`.toUpperCase()
}
parse={(value) => {
parse={(value): Color | undefined => {
const parsed = parseHex(value);
if (parsed) {
return [...parsed, a];
return [parsed[0], parsed[1], parsed[2], a];
}
return undefined;
}}
Expand Down Expand Up @@ -541,8 +541,14 @@ function ColorComponent({
);
}

function PredefinedColors({ setColor }: { setColor: (color: Color) => void }) {
const predefinedColors = [
function PredefinedColors({
setColor,
}: {
setColor: (color: Color) => void;
}) {
const predefinedColors: ReadonlyArray<
ReadonlyArray<readonly [string, number, number, number]>
> = [
[
["Red", 244, 67, 54],
["Pink", 233, 30, 99],
Expand Down Expand Up @@ -570,7 +576,7 @@ function PredefinedColors({ setColor }: { setColor: (color: Color) => void }) {
["Black", 0, 0, 0],
["White", 255, 255, 255],
],
] as unknown as [[[string, number, number, number]]];
];

return (
<div className={classes.predefinedColors}>
Expand All @@ -593,7 +599,7 @@ function PredefinedColor({
color: [title, r, g, b],
setColor,
}: {
color: [string, number, number, number];
color: readonly [string, number, number, number];
setColor: (color: Color) => void;
}) {
return (
Expand All @@ -606,7 +612,7 @@ function PredefinedColor({
);
}

function hsvToRgb(h: number, s: number, v: number) {
function hsvToRgb(h: number, s: number, v: number): [number, number, number] {
const xDivC = 1 - Math.abs(((h / 60) % 2) - 1);

const [rc, rx, gc, gx, bc, bx] =
Expand All @@ -633,7 +639,7 @@ function hsvToRgb(h: number, s: number, v: number) {
return [r, g, b];
}

function rgbToHsv(r: number, g: number, b: number) {
function rgbToHsv(r: number, g: number, b: number): [number, number, number] {
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
const delta = max - min;
Expand Down
4 changes: 2 additions & 2 deletions src/ui/components/ContextMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { createContext, useContext, ReactNode } from "react";
import React, { createContext, useContext, type ReactNode } from "react";
import { expect } from "../../util/OptionUtil";

import classes from "../../css/ContextMenu.module.css";
import { Language } from "../../livesplit-core";
import { type Language } from "../../livesplit-core";

export interface Position {
x: number;
Expand Down
Loading