Skip to content

Commit

Permalink
Implement Layout Background Images
Browse files Browse the repository at this point in the history
This adds support for layout background images. This also includes a
bunch of smaller fixes.
  • Loading branch information
CryZe committed Feb 24, 2024
1 parent 23a6357 commit edda89a
Show file tree
Hide file tree
Showing 24 changed files with 2,018 additions and 1,339 deletions.
15 changes: 8 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:

steps:
- name: Checkout commit
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive

Expand All @@ -22,7 +22,7 @@ jobs:
node-version: 'lts/*'

- name: Install Rust
uses: hecrj/setup-rust-action@v1
uses: hecrj/setup-rust-action@v2
with:
rust-version: nightly
components: rust-src
Expand All @@ -49,7 +49,7 @@ jobs:
id: wasm-bindgen

- name: Download wasm-bindgen-cli
uses: robinraju/release-downloader@v1.7
uses: robinraju/release-downloader@v1.9
with:
repository: "rustwasm/wasm-bindgen"
tag: ${{ steps.wasm-bindgen.outputs.version }}
Expand All @@ -73,14 +73,15 @@ jobs:
- name: Set up tslint matcher
run: echo "::add-matcher::.github/workflows/tslint.json"

- name: Run tslint
run: npm run lint
# FIXME: Switch to eslint
# - name: Run tslint
# run: npm run lint

- name: Build Frontend
run: npm run publish

- name: Cache screenshots
uses: actions/cache@v1
uses: actions/cache@v4
with:
path: test/screenshots
key: ${{ runner.os }}-screenshots-${{ hashFiles('test/rendering-test.js') }}
Expand All @@ -93,7 +94,7 @@ jobs:
- name: Upload screenshots
if: success() || failure()
uses: actions/upload-artifact@v1
uses: actions/upload-artifact@v4
with:
name: Screenshots
path: test/screenshots
Expand Down
4 changes: 2 additions & 2 deletions buildCore.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ if (process.argv.some((v) => v === "--max-opt")) {
// Use WASM features that may not be supported by all the browsers.
if (process.argv.some((v) => v === "--unstable")) {
// Extended const is not supported by Safari yet.
// Relaxed SIMD is not supported by any browser yet.
// Tail calls are not supported by Firefox, Safari and wasm-bindgen yet.
// Relaxed SIMD is not supported by Firefox and Safari yet.
// Tail calls are not supported by Safari and wasm-bindgen yet.
rustFlags += ",+extended-const,+relaxed-simd"; //,+tail-call";
}

Expand Down
2 changes: 1 addition & 1 deletion livesplit-core
Submodule livesplit-core updated 127 files
2,753 changes: 1,541 additions & 1,212 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"commonmark": "^0.27.0",
"commonmark-react-renderer": "^4.3.5",
"fast-deep-equal": "^3.1.3",
"idb": "^7.1.1",
"idb": "^8.0.0",
"react": "^16.14.0",
"react-color": "^2.19.3",
"react-contextmenu": "^2.14.0",
Expand All @@ -45,7 +45,7 @@
"devDependencies": {
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
"@types/node": "^20.4.9",
"chromedriver": "^119.0.1",
"chromedriver": "^122.0.3",
"clean-webpack-plugin": "^4.0.0",
"css-loader": "^6.7.3",
"favicons-webpack-plugin": "^6.0.0",
Expand All @@ -62,17 +62,18 @@
"pixelmatch": "^5.3.0",
"pngjs": "^7.0.0",
"react-refresh-typescript": "^2.0.7",
"sass": "^1.57.1",
"sass-loader": "^13.2.0",
"sass": "^1.57.1",
"selenium-webdriver": "^4.7.1",
"sharp": "^0.33.2",
"source-map-loader": "^4.0.1",
"style-loader": "^3.3.1",
"ts-loader": "^9.4.2",
"tslint": "^6.1.3",
"typescript": "^5.3.2",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.11.1",
"webpack": "^5.75.0",
"workbox-webpack-plugin": "^7.0.0"
}
}
11 changes: 8 additions & 3 deletions src/api/SpeedrunCom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,13 @@ export class Page<T> {
const elements = this.elements;
let next = this.next;
while (next != null) {
const page = await next();
elements.push(...page.elements);
next = page.next;
try {
const page = await next();
elements.push(...page.elements);
next = page.next;
} catch {
break;
}
}
return elements;
}
Expand Down Expand Up @@ -410,6 +414,7 @@ export async function getRuns(
if (status !== undefined) {
parameters.push(`status=${status}`);
}
parameters.push("orderby=submitted", "direction=desc");
const uri = getRunsUri(evaluateParameters(parameters));
return executePaginatedRequest<Run<PlayersEmbedded | PlayersNotEmbedded>>(uri);
}
Expand Down
3 changes: 3 additions & 0 deletions src/layout/AutoRefreshLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import * as React from "react";
import { LayoutStateJson } from "../livesplit-core";
import AutoRefresh from "../util/AutoRefresh";
import Layout from "./Layout";
import { UrlCache } from "../util/UrlCache";

export interface Props {
getState: () => LayoutStateJson,
layoutUrlCache: UrlCache,
allowResize: boolean,
width: number,
onResize(width: number): void,
Expand Down Expand Up @@ -34,6 +36,7 @@ export default class AutoRefreshLayout extends React.Component<Props, State> {
<AutoRefresh update={() => this.refreshLayout()} >
<Layout
state={this.state.layoutState}
layoutUrlCache={this.props.layoutUrlCache}
allowResize={this.props.allowResize}
width={this.props.width}
onResize={this.props.onResize}
Expand Down
9 changes: 8 additions & 1 deletion src/layout/Component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import Splits from "./Splits";
import Text from "./Text";
import Timer from "./Timer";
import Title from "./Title";
import { UrlCache } from "../util/UrlCache";

export interface Props {
state: ComponentStateJson,
layoutUrlCache: UrlCache,
layoutWidth: number,
componentId: string,
}
Expand All @@ -28,6 +30,7 @@ export default class Component extends React.Component<Props> {
} else if ("DetailedTimer" in state) {
return <DetailedTimer
state={state.DetailedTimer}
layoutUrlCache={this.props.layoutUrlCache}
layoutWidth={this.props.layoutWidth}
/>;
} else if ("Graph" in state) {
Expand All @@ -38,6 +41,7 @@ export default class Component extends React.Component<Props> {
} else if ("Splits" in state) {
return <Splits
state={state.Splits}
layoutUrlCache={this.props.layoutUrlCache}
/>;
} else if ("Text" in state) {
return <Text
Expand All @@ -50,7 +54,10 @@ export default class Component extends React.Component<Props> {
componentId={this.props.componentId}
/>;
} else if ("Title" in state) {
return <Title state={state.Title} />;
return <Title
state={state.Title}
layoutUrlCache={this.props.layoutUrlCache}
/>;
} else if ("Separator" in state) {
return <Separator />;
} else if ("BlankSpace" in state) {
Expand Down
14 changes: 5 additions & 9 deletions src/layout/DetailedTimer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,25 @@ import { renderToSVG } from "./Timer";
import "../css/DetailedTimer.scss";
import variables from "../css/variables.scss";
import { map } from "../util/OptionUtil";
import { UrlCache } from "../util/UrlCache";

const fontSizeToLineHeightRatio = parseFloat(variables.fontSizeToLineHeightRatio);
const lineHeightToComponentHeightRatio = parseFloat(variables.lineHeightToComponentHeightRatio);
const sidePadding = parseFloat(variables.sidePadding);

export interface Props {
state: LiveSplit.DetailedTimerComponentStateJson,
layoutUrlCache: UrlCache,
layoutWidth: number,
}

export default class DetailedTimer extends React.Component<Props> {
private icon: string;

constructor(props: Props) {
super(props);
this.icon = "";
}

public render() {
const iconChange = this.props.state.icon_change;
if (iconChange !== null) {
this.icon = iconChange;
}
const icon = this.props.layoutUrlCache.cache(this.props.state.icon);

const totalHeight = this.props.state.timer.height + this.props.state.segment_timer.height;
const topRowHeight = totalHeight * 0.55;
Expand Down Expand Up @@ -63,10 +59,10 @@ export default class DetailedTimer extends React.Component<Props> {
}
<div className="detailed-timer-left-side">
{
this.icon &&
icon !== undefined &&
<div className="detailed-timer-icon-container" style={{ width: totalHeight }}>
<div className="detailed-timer-icon-inner-container">
<img className="detailed-timer-icon" src={this.icon} />
<img className="detailed-timer-icon" src={icon} />
</div>
</div>
}
Expand Down
20 changes: 18 additions & 2 deletions src/layout/DragAutoRefreshLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import * as React from "react";
import { LayoutStateJson } from "../livesplit-core";
import AutoRefresh from "../util/AutoRefresh";
import { colorToCss, gradientToCss } from "../util/ColorUtil";
import { backgroundToCss, colorToCss } from "../util/ColorUtil";
import { Option } from "../util/OptionUtil";
import Component from "./Component";
import { getLayoutStateStyle } from "./Layout";
import { UrlCache } from "../util/UrlCache";

export interface Props {
getState: () => LayoutStateJson,
layoutUrlCache: UrlCache,
layoutWidth: number,
onClick: (componentIndex: number) => void,
onDrag: (componentIndex: number) => void,
Expand Down Expand Up @@ -44,16 +46,29 @@ export default class DragAutoRefreshLayout extends React.Component<Props, State>
const layoutStateStyle = getLayoutStateStyle(layoutState);
const counts = new Map<string, number>();

const background = backgroundToCss(
layoutState.background,
this.props.layoutUrlCache,
this.props.layoutWidth,
);

const dragLayout = (
<div
className="layout"
style={{
background: gradientToCss(layoutState.background),
overflow: "hidden",
color: colorToCss(layoutState.text_color),
width: this.props.layoutWidth,
...layoutStateStyle
}}
>
<div style={{
position: "absolute",
width: "100%",
height: "100%",
zIndex: -1,
...background,
}} />
{
layoutState.components.map((c, i) => {
const componentType = Object.keys(c)[0];
Expand Down Expand Up @@ -112,6 +127,7 @@ export default class DragAutoRefreshLayout extends React.Component<Props, State>
}
<Component
state={c}
layoutUrlCache={this.props.layoutUrlCache}
layoutWidth={this.props.layoutWidth}
componentId={key}
/>
Expand Down
20 changes: 18 additions & 2 deletions src/layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as React from "react";
import { Font, FontStretch, FontStyle, FontWeight, LayoutStateJson } from "../livesplit-core";
import { colorToCss, gradientToCss } from "../util/ColorUtil";
import { backgroundToCss, colorToCss } from "../util/ColorUtil";
import Component from "./Component";
import { ResizableBox, ResizeCallbackData } from "react-resizable";

import "../css/Layout.scss";
import { UrlCache } from "../util/UrlCache";

interface LayoutStateStyle {
"--thin-separators-color": string,
Expand All @@ -28,6 +29,7 @@ interface LayoutStateStyle {

export interface Props {
state: LayoutStateJson,
layoutUrlCache: UrlCache,
allowResize: boolean,
width: number,
onResize(width: number): void,
Expand All @@ -38,16 +40,29 @@ export default class Layout extends React.Component<Props> {
const layoutState = getLayoutStateStyle(this.props.state);
const counts = new Map<string, number>();

const background = backgroundToCss(
this.props.state.background,
this.props.layoutUrlCache,
this.props.width,
);

return (
<div
className="layout"
style={{
background: gradientToCss(this.props.state.background),
overflow: "hidden",
color: colorToCss(this.props.state.text_color),
width: this.props.width,
...layoutState
}}
>
<div style={{
position: "absolute",
width: "100%",
height: "100%",
zIndex: -1,
...background,
}} />
{this.props.allowResize &&
<ResizableBox
className="resizable-layout"
Expand Down Expand Up @@ -75,6 +90,7 @@ export default class Layout extends React.Component<Props> {
return <Component
key={key}
state={c}
layoutUrlCache={this.props.layoutUrlCache}
componentId={key}
layoutWidth={this.props.width}
/>;
Expand Down
Loading

0 comments on commit edda89a

Please sign in to comment.