Add docker and WIP refactor front-end
This commit is contained in:
parent
8a7816f9f4
commit
1d17714274
16 changed files with 299 additions and 249 deletions
4
backend/Cargo.lock
generated
4
backend/Cargo.lock
generated
|
@ -1217,9 +1217,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "usdpl-back"
|
name = "usdpl-back"
|
||||||
version = "0.7.2"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "58928ed65332c30b9b9be5140fcdab97e45db679a5845d829aa26492765272e5"
|
checksum = "e2ff8cc372a3b876bdbad212a398b06127bdb67603bce621d4148a50f1195372"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
|
|
@ -8,7 +8,7 @@ license = "MIT"
|
||||||
repository = "https://github.com/NGnius/kaylon"
|
repository = "https://github.com/NGnius/kaylon"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
usdpl-back = { version = "0.7.2"}
|
usdpl-back = { version = "0.8.0"}
|
||||||
|
|
||||||
clap = { version = "3.2", features = ["derive", "std"], default-features = false }
|
clap = { version = "3.2", features = ["derive", "std"], default-features = false }
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ log = { version = "0.4" }
|
||||||
simplelog = { version = "0.12" }
|
simplelog = { version = "0.12" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["decky"]
|
default = []
|
||||||
decky = ["usdpl-back/decky"]
|
decky = ["usdpl-back/decky"]
|
||||||
encrypt = ["usdpl-back/encrypt"]
|
encrypt = ["usdpl-back/encrypt"]
|
||||||
|
|
||||||
|
|
19
backend/build-docker-debug.sh
Executable file
19
backend/build-docker-debug.sh
Executable file
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo " --- Rust version info ---"
|
||||||
|
rustup --version
|
||||||
|
rustc --version
|
||||||
|
cargo --version
|
||||||
|
|
||||||
|
echo " --- Building plugin backend ---"
|
||||||
|
cargo build --release --features decky
|
||||||
|
mkdir -p out
|
||||||
|
cp target/release/caylon out/backend
|
||||||
|
|
||||||
|
echo " --- Cleaning up backend ---"
|
||||||
|
# remove root-owned target folder
|
||||||
|
cargo clean
|
||||||
|
|
||||||
|
echo " --- Building plugin frontend WASM ---"
|
||||||
|
# TODO allow Dockerfile in root so that it can access src/usdpl_front and rebuild it
|
||||||
|
cd ../src/usdpl_front && ./rebuild.sh decky && cd ../../backend
|
|
@ -8,7 +8,7 @@ rustc --version
|
||||||
cargo --version
|
cargo --version
|
||||||
|
|
||||||
echo " --- Building plugin backend ---"
|
echo " --- Building plugin backend ---"
|
||||||
cargo build --release --features encrypt
|
cargo build --release --features decky,encrypt
|
||||||
mkdir -p out
|
mkdir -p out
|
||||||
cp target/release/caylon out/backend
|
cp target/release/caylon out/backend
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
#cargo build --release --target x86_64-unknown-linux-musl --features encrypt
|
#cargo build --release --target x86_64-unknown-linux-musl --features encrypt
|
||||||
cargo build --target x86_64-unknown-linux-musl --features encrypt
|
cargo build --target x86_64-unknown-linux-musl --features $1
|
||||||
#cross build --release --features encrypt
|
#cross build --release --features encrypt
|
||||||
|
|
||||||
mkdir -p ../bin
|
mkdir -p ../bin
|
||||||
|
|
8
backend/entrypoint-debug.sh
Executable file
8
backend/entrypoint-debug.sh
Executable file
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "Container's IP address: `awk 'END{print $1}' /etc/hosts`"
|
||||||
|
|
||||||
|
cd /caylon/backend
|
||||||
|
|
||||||
|
sudo bash ./build-docker-debug.sh
|
7
backend/run_docker_debug.sh
Executable file
7
backend/run_docker_debug.sh
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# run docker container locally (for testing)
|
||||||
|
# assumes you're running in the backend/ dir of the project
|
||||||
|
|
||||||
|
docker run -i --entrypoint /caylon/backend/entrypoint-debug.sh -v $PWD/../:/caylon caylon_backend
|
||||||
|
mkdir -p ../bin
|
||||||
|
cp ./out/backend ../bin
|
9
build-debug.sh
Executable file
9
build-debug.sh
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd ./backend && ./build.sh decky && cd ..
|
||||||
|
|
||||||
|
cd ./src/usdpl_front && ./rebuild.sh decky && cd ../..
|
||||||
|
|
||||||
|
npm install && npm run build
|
||||||
|
|
||||||
|
unset USDPL_ENCRYPTION_KEY
|
2
build.sh
2
build.sh
|
@ -3,7 +3,7 @@
|
||||||
export USDPL_ENCRYPTION_KEY=$(openssl enc -aes-256-cbc -k caylon -pbkdf2 -P -md sha1 | awk -F= '{if ($1 == "key") print $2}')
|
export USDPL_ENCRYPTION_KEY=$(openssl enc -aes-256-cbc -k caylon -pbkdf2 -P -md sha1 | awk -F= '{if ($1 == "key") print $2}')
|
||||||
echo USDPL key: $USDPL_ENCRYPTION_KEY
|
echo USDPL key: $USDPL_ENCRYPTION_KEY
|
||||||
|
|
||||||
cd ./backend && ./build.sh && cd ..
|
cd ./backend && ./build.sh decky,encrypt && cd ..
|
||||||
|
|
||||||
cd ./src/usdpl_front && ./rebuild.sh decky encrypt && cd ../..
|
cd ./src/usdpl_front && ./rebuild.sh decky encrypt && cd ../..
|
||||||
|
|
||||||
|
|
2
main.py
2
main.py
|
@ -11,6 +11,6 @@ class Plugin:
|
||||||
# Asyncio-compatible long-running code, executed in a task when the plugin is loaded
|
# Asyncio-compatible long-running code, executed in a task when the plugin is loaded
|
||||||
async def _main(self):
|
async def _main(self):
|
||||||
# startup
|
# startup
|
||||||
self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend", "--config", ""])
|
self.backend_proc = subprocess.Popen([PARENT_DIR + "/bin/backend", "--config", "./caylon.json"])
|
||||||
while True:
|
while True:
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
92
src/components/about.tsx
Normal file
92
src/components/about.tsx
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
import {Component} from "react";
|
||||||
|
import {
|
||||||
|
Field,
|
||||||
|
PanelSectionRow,
|
||||||
|
staticClasses,
|
||||||
|
} from "decky-frontend-lib";
|
||||||
|
import * as backend from "../backend";
|
||||||
|
|
||||||
|
export class About extends Component<{about: backend.CAbout | null}> {
|
||||||
|
render() {
|
||||||
|
return buildAbout(this.props.about);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildAbout(about: backend.CAbout | null) {
|
||||||
|
if (about == null) {
|
||||||
|
return [];
|
||||||
|
} else {
|
||||||
|
let elements = [
|
||||||
|
<div className={staticClasses.PanelSectionTitle}>
|
||||||
|
About
|
||||||
|
</div>,
|
||||||
|
<PanelSectionRow>
|
||||||
|
<Field label="Name">
|
||||||
|
{about.name}
|
||||||
|
</Field>
|
||||||
|
</PanelSectionRow>,
|
||||||
|
<PanelSectionRow>
|
||||||
|
<Field label="Version">
|
||||||
|
{about.version}
|
||||||
|
</Field>
|
||||||
|
</PanelSectionRow>,
|
||||||
|
<PanelSectionRow>
|
||||||
|
<Field label="Description">
|
||||||
|
{about.description}
|
||||||
|
</Field>
|
||||||
|
</PanelSectionRow>
|
||||||
|
];
|
||||||
|
if (about.url != null) {
|
||||||
|
elements.push(
|
||||||
|
<PanelSectionRow>
|
||||||
|
<Field label="URL">
|
||||||
|
{about.url}
|
||||||
|
</Field>
|
||||||
|
</PanelSectionRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (about.authors.length > 1) {
|
||||||
|
let authors = about.authors.map((elem, i) => {
|
||||||
|
if (i == about!.authors.length - 1) {
|
||||||
|
return <p>{elem}</p>;
|
||||||
|
} else {
|
||||||
|
return <span>{elem}</span>;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
elements.push(
|
||||||
|
<PanelSectionRow>
|
||||||
|
<Field label="Authors">
|
||||||
|
{authors}
|
||||||
|
</Field>
|
||||||
|
</PanelSectionRow>
|
||||||
|
);
|
||||||
|
} else if (about.authors.length == 1) {
|
||||||
|
elements.push(
|
||||||
|
<PanelSectionRow>
|
||||||
|
<Field label="Author">
|
||||||
|
{about.authors[0]}
|
||||||
|
</Field>
|
||||||
|
</PanelSectionRow>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
elements.push(
|
||||||
|
<PanelSectionRow>
|
||||||
|
<Field label="Author">
|
||||||
|
NGnius
|
||||||
|
</Field>
|
||||||
|
</PanelSectionRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (about.license != null) {
|
||||||
|
elements.push(
|
||||||
|
<PanelSectionRow>
|
||||||
|
<Field label="License">
|
||||||
|
{about.license}
|
||||||
|
</Field>
|
||||||
|
</PanelSectionRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
}
|
125
src/components/elements.tsx
Normal file
125
src/components/elements.tsx
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
import { Component, useState } from "react";
|
||||||
|
import {
|
||||||
|
ButtonItem,
|
||||||
|
PanelSectionRow,
|
||||||
|
SliderField,
|
||||||
|
ToggleField,
|
||||||
|
Field,
|
||||||
|
} from "decky-frontend-lib";
|
||||||
|
|
||||||
|
import { get_value, set_value } from "usdpl-front";
|
||||||
|
import {DISPLAY_KEY, VALUE_KEY} from "../consts";
|
||||||
|
import * as backend from "../backend";
|
||||||
|
|
||||||
|
export class Elements extends Component<{items: backend.CElement[]}> {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const [triggerInternal, updateInternal] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const update = () => {
|
||||||
|
updateInternal(!triggerInternal);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateIdc(_: any) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.props.items.map(
|
||||||
|
(elem, i) => {
|
||||||
|
return (<PanelSectionRow>{buildHtmlElement(elem, i, updateIdc)}</PanelSectionRow>);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildHtmlElement(element: backend.CElement, index: number, updateIdc: any) {
|
||||||
|
switch (element.element) {
|
||||||
|
case "button":
|
||||||
|
return buildButton(element as backend.CButton, index, updateIdc);
|
||||||
|
case "slider":
|
||||||
|
return buildSlider(element as backend.CSlider, index, updateIdc);
|
||||||
|
case "toggle":
|
||||||
|
return buildToggle(element as backend.CToggle, index, updateIdc);
|
||||||
|
case "reading":
|
||||||
|
return buildReading(element as backend.CReading, index, updateIdc);
|
||||||
|
case "result-display":
|
||||||
|
return buildResultDisplay(element as backend.CResultDisplay, index, updateIdc);
|
||||||
|
case "event-display":
|
||||||
|
return buildEventDisplay(element as backend.CEventDisplay, index, updateIdc);
|
||||||
|
}
|
||||||
|
console.error("CAYLON: Unsupported element", element);
|
||||||
|
backend.log(backend.CLogLevel.ERROR, "Unsupported element " + element.element);
|
||||||
|
return (<div>Unsupported</div>);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildButton(element: backend.CButton, index: number, updateIdc: any) {
|
||||||
|
return (
|
||||||
|
<ButtonItem
|
||||||
|
layout="below"
|
||||||
|
onClick={() => {backend.resolve(backend.onUpdate(index, null), updateIdc)}}>
|
||||||
|
{element.title}
|
||||||
|
</ButtonItem>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildSlider(element: backend.CSlider, index: number, updateIdc: any) {
|
||||||
|
const KEY = VALUE_KEY + index.toString();
|
||||||
|
if (get_value(KEY) == null) {
|
||||||
|
set_value(KEY, element.min);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<SliderField
|
||||||
|
label={element.title}
|
||||||
|
value={get_value(KEY)}
|
||||||
|
max={element.max}
|
||||||
|
min={element.min}
|
||||||
|
showValue={true}
|
||||||
|
onChange={(value: number) => {
|
||||||
|
backend.resolve(backend.onUpdate(index, value), updateIdc);
|
||||||
|
set_value(KEY, value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildToggle(element: backend.CToggle, index: number, updateIdc: any) {
|
||||||
|
const KEY = VALUE_KEY + index.toString();
|
||||||
|
if (get_value(KEY) == null) {
|
||||||
|
set_value(KEY, false);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<ToggleField
|
||||||
|
checked={get_value(KEY)}
|
||||||
|
label={element.title}
|
||||||
|
description={element.description!}
|
||||||
|
onChange={(value: boolean) => {
|
||||||
|
backend.resolve(backend.onUpdate(index, value), updateIdc);
|
||||||
|
set_value(KEY, value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildReading(element: backend.CReading, index: number, _updateIdc: any) {
|
||||||
|
return (
|
||||||
|
<Field label={element.title}>
|
||||||
|
{get_value(DISPLAY_KEY + index.toString())}
|
||||||
|
</Field>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildResultDisplay(element: backend.CResultDisplay, index: number, _updateIdc: any) {
|
||||||
|
return (
|
||||||
|
<Field label={element.title}>
|
||||||
|
{get_value(DISPLAY_KEY + index.toString())}
|
||||||
|
</Field>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildEventDisplay(element: backend.CEventDisplay, index: number, _updateIdc: any) {
|
||||||
|
return (
|
||||||
|
<Field label={element.title}>
|
||||||
|
{get_value(DISPLAY_KEY + index.toString())}
|
||||||
|
</Field>
|
||||||
|
);
|
||||||
|
}
|
9
src/consts.ts
Normal file
9
src/consts.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import {
|
||||||
|
gamepadDialogClasses,
|
||||||
|
joinClassNames,
|
||||||
|
} from "decky-frontend-lib";
|
||||||
|
|
||||||
|
export const DISPLAY_KEY = "display";
|
||||||
|
export const VALUE_KEY = "value";
|
||||||
|
|
||||||
|
export const FieldWithSeparator = joinClassNames(gamepadDialogClasses.Field, gamepadDialogClasses.WithBottomSeparatorStandard);
|
231
src/index.tsx
231
src/index.tsx
|
@ -10,23 +10,16 @@ import {
|
||||||
ServerAPI,
|
ServerAPI,
|
||||||
//showContextMenu,
|
//showContextMenu,
|
||||||
staticClasses,
|
staticClasses,
|
||||||
SliderField,
|
|
||||||
ToggleField,
|
|
||||||
//NotchLabel
|
|
||||||
gamepadDialogClasses,
|
|
||||||
joinClassNames,
|
|
||||||
} from "decky-frontend-lib";
|
} from "decky-frontend-lib";
|
||||||
import { VFC, useState } from "react";
|
import { VFC, useState } from "react";
|
||||||
import { GiWashingMachine } from "react-icons/gi";
|
import { GiWashingMachine } from "react-icons/gi";
|
||||||
|
|
||||||
import { get_value, set_value } from "usdpl-front";
|
import { set_value } from "usdpl-front";
|
||||||
import * as backend from "./backend";
|
import * as backend from "./backend";
|
||||||
import {register_for_steam_events, unregister_for_steam_events} from "./steam_events";
|
import {register_for_steam_events, unregister_for_steam_events} from "./steam_events";
|
||||||
|
import {DISPLAY_KEY} from "./consts";
|
||||||
const FieldWithSeparator = joinClassNames(gamepadDialogClasses.Field, gamepadDialogClasses.WithBottomSeparatorStandard);
|
import {Elements} from "./components/elements";
|
||||||
|
import {About} from "./components/about";
|
||||||
const DISPLAY_KEY = "display";
|
|
||||||
const VALUE_KEY = "value";
|
|
||||||
|
|
||||||
let items: backend.CElement[] = [];
|
let items: backend.CElement[] = [];
|
||||||
let about: backend.CAbout | null = null;
|
let about: backend.CAbout | null = null;
|
||||||
|
@ -167,10 +160,6 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
|
||||||
updateInternal(!triggerInternal);
|
updateInternal(!triggerInternal);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateIdc(_: any) {
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
// perform tasks (like updating display elements) only while rendering the plugin
|
// perform tasks (like updating display elements) only while rendering the plugin
|
||||||
let taskItem = updateTasks.pop();
|
let taskItem = updateTasks.pop();
|
||||||
while (taskItem != undefined) {
|
while (taskItem != undefined) {
|
||||||
|
@ -180,12 +169,8 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PanelSection>
|
<PanelSection>
|
||||||
{items.map(
|
<Elements items={items}/>
|
||||||
(elem, i) => {
|
<About about={about}/>
|
||||||
return <PanelSectionRow>{buildHtmlElement(elem, i, updateIdc)}</PanelSectionRow>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
{ about != null && buildAbout() }
|
|
||||||
<PanelSectionRow>
|
<PanelSectionRow>
|
||||||
<ButtonItem
|
<ButtonItem
|
||||||
layout="below"
|
layout="below"
|
||||||
|
@ -219,210 +204,6 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function buildHtmlElement(element: backend.CElement, index: number, updateIdc: any) {
|
|
||||||
switch (element.element) {
|
|
||||||
case "button":
|
|
||||||
return buildButton(element as backend.CButton, index, updateIdc);
|
|
||||||
case "slider":
|
|
||||||
return buildSlider(element as backend.CSlider, index, updateIdc);
|
|
||||||
case "toggle":
|
|
||||||
return buildToggle(element as backend.CToggle, index, updateIdc);
|
|
||||||
case "reading":
|
|
||||||
return buildReading(element as backend.CReading, index, updateIdc);
|
|
||||||
case "result-display":
|
|
||||||
return buildResultDisplay(element as backend.CResultDisplay, index, updateIdc);
|
|
||||||
case "event-display":
|
|
||||||
return buildEventDisplay(element as backend.CEventDisplay, index, updateIdc);
|
|
||||||
}
|
|
||||||
console.error("CAYLON: Unsupported element", element);
|
|
||||||
backend.log(backend.CLogLevel.ERROR, "Unsupported element " + element.element);
|
|
||||||
return <div>Unsupported</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildButton(element: backend.CButton, index: number, updateIdc: any) {
|
|
||||||
return (
|
|
||||||
<ButtonItem
|
|
||||||
layout="below"
|
|
||||||
onClick={() => {backend.resolve(backend.onUpdate(index, null), updateIdc)}}>
|
|
||||||
{element.title}
|
|
||||||
</ButtonItem>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildSlider(element: backend.CSlider, index: number, updateIdc: any) {
|
|
||||||
const KEY = VALUE_KEY + index.toString();
|
|
||||||
if (get_value(KEY) == null) {
|
|
||||||
set_value(KEY, element.min);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<SliderField
|
|
||||||
label={element.title}
|
|
||||||
value={get_value(KEY)}
|
|
||||||
max={element.max}
|
|
||||||
min={element.min}
|
|
||||||
showValue={true}
|
|
||||||
onChange={(value: number) => {
|
|
||||||
backend.resolve(backend.onUpdate(index, value), updateIdc);
|
|
||||||
set_value(KEY, value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildToggle(element: backend.CToggle, index: number, updateIdc: any) {
|
|
||||||
const KEY = VALUE_KEY + index.toString();
|
|
||||||
if (get_value(KEY) == null) {
|
|
||||||
set_value(KEY, false);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<ToggleField
|
|
||||||
checked={get_value(KEY)}
|
|
||||||
label={element.title}
|
|
||||||
description={element.description!}
|
|
||||||
onChange={(value: boolean) => {
|
|
||||||
backend.resolve(backend.onUpdate(index, value), updateIdc);
|
|
||||||
set_value(KEY, value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildReading(element: backend.CReading, index: number, _updateIdc: any) {
|
|
||||||
return (
|
|
||||||
<div className={FieldWithSeparator}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabel}>{element.title}</div>
|
|
||||||
<div className={gamepadDialogClasses.FieldChildren}>{get_value(DISPLAY_KEY + index.toString())}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildResultDisplay(element: backend.CResultDisplay, index: number, _updateIdc: any) {
|
|
||||||
return (
|
|
||||||
<div className={FieldWithSeparator}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabel}>{element.title}</div>
|
|
||||||
<div className={gamepadDialogClasses.FieldChildren}>{get_value(DISPLAY_KEY + index.toString())}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildEventDisplay(element: backend.CEventDisplay, index: number, _updateIdc: any) {
|
|
||||||
return (
|
|
||||||
<div className={FieldWithSeparator}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabel}>{element.title}</div>
|
|
||||||
<div className={gamepadDialogClasses.FieldChildren}>{get_value(DISPLAY_KEY + index.toString())}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildAbout() {
|
|
||||||
if (about == null) {
|
|
||||||
return [];
|
|
||||||
} else {
|
|
||||||
let elements = [
|
|
||||||
<div className={staticClasses.PanelSectionTitle}>
|
|
||||||
About
|
|
||||||
</div>,
|
|
||||||
<PanelSectionRow>
|
|
||||||
<div className={FieldWithSeparator}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabel}>Name</div>
|
|
||||||
<div className={gamepadDialogClasses.FieldChildren}>{about.name}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</PanelSectionRow>,
|
|
||||||
<PanelSectionRow>
|
|
||||||
<div className={FieldWithSeparator}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabel}>Version</div>
|
|
||||||
<div className={gamepadDialogClasses.FieldChildren}>{about.version}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</PanelSectionRow>,
|
|
||||||
<PanelSectionRow>
|
|
||||||
<div className={FieldWithSeparator}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabel}>Description</div>
|
|
||||||
<div className={gamepadDialogClasses.FieldDescription}>{about.description}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</PanelSectionRow>
|
|
||||||
];
|
|
||||||
if (about.url != null) {
|
|
||||||
elements.push(
|
|
||||||
<PanelSectionRow>
|
|
||||||
<div className={FieldWithSeparator}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabel}>URL</div>
|
|
||||||
<div className={gamepadDialogClasses.FieldDescription}>{about.url}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</PanelSectionRow>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (about.authors.length > 1) {
|
|
||||||
let authors = about.authors.map((elem, i) => {
|
|
||||||
if (i == about!.authors.length - 1) {
|
|
||||||
return <p>{elem}</p>;
|
|
||||||
} else {
|
|
||||||
return <span>{elem}</span>;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
elements.push(
|
|
||||||
<PanelSectionRow>
|
|
||||||
<div className={FieldWithSeparator}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabel}>Authors</div>
|
|
||||||
<div className={gamepadDialogClasses.FieldDescription}>{authors}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</PanelSectionRow>
|
|
||||||
);
|
|
||||||
} else if (about.authors.length == 1) {
|
|
||||||
elements.push(
|
|
||||||
<PanelSectionRow>
|
|
||||||
<div className={FieldWithSeparator}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabel}>Author</div>
|
|
||||||
<div className={gamepadDialogClasses.FieldDescription}>{about.authors[0]}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</PanelSectionRow>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
elements.push(
|
|
||||||
<PanelSectionRow>
|
|
||||||
<div className={FieldWithSeparator}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabel}>Author</div>
|
|
||||||
<div className={gamepadDialogClasses.FieldDescription}>NGnius</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</PanelSectionRow>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (about.license != null) {
|
|
||||||
elements.push(
|
|
||||||
<PanelSectionRow>
|
|
||||||
<div className={FieldWithSeparator}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabelRow}>
|
|
||||||
<div className={gamepadDialogClasses.FieldLabel}>License</div>
|
|
||||||
<div className={gamepadDialogClasses.FieldChildren}>{about.license}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</PanelSectionRow>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return elements;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default definePlugin((serverApi: ServerAPI) => {
|
export default definePlugin((serverApi: ServerAPI) => {
|
||||||
return {
|
return {
|
||||||
title: <div className={staticClasses.Title}>{about == null? "Caylon": about.name}</div>,
|
title: <div className={staticClasses.Title}>{about == null? "Caylon": about.name}</div>,
|
||||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Reference in a new issue