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]]
|
||||
name = "usdpl-back"
|
||||
version = "0.7.2"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58928ed65332c30b9b9be5140fcdab97e45db679a5845d829aa26492765272e5"
|
||||
checksum = "e2ff8cc372a3b876bdbad212a398b06127bdb67603bce621d4148a50f1195372"
|
||||
dependencies = [
|
||||
"async-recursion",
|
||||
"async-trait",
|
||||
|
|
|
@ -8,7 +8,7 @@ license = "MIT"
|
|||
repository = "https://github.com/NGnius/kaylon"
|
||||
|
||||
[dependencies]
|
||||
usdpl-back = { version = "0.7.2"}
|
||||
usdpl-back = { version = "0.8.0"}
|
||||
|
||||
clap = { version = "3.2", features = ["derive", "std"], default-features = false }
|
||||
|
||||
|
@ -28,7 +28,7 @@ log = { version = "0.4" }
|
|||
simplelog = { version = "0.12" }
|
||||
|
||||
[features]
|
||||
default = ["decky"]
|
||||
default = []
|
||||
decky = ["usdpl-back/decky"]
|
||||
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
|
||||
|
||||
echo " --- Building plugin backend ---"
|
||||
cargo build --release --features encrypt
|
||||
cargo build --release --features decky,encrypt
|
||||
mkdir -p out
|
||||
cp target/release/caylon out/backend
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
#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
|
||||
|
||||
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}')
|
||||
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 ../..
|
||||
|
||||
|
|
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
|
||||
async def _main(self):
|
||||
# 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:
|
||||
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,
|
||||
//showContextMenu,
|
||||
staticClasses,
|
||||
SliderField,
|
||||
ToggleField,
|
||||
//NotchLabel
|
||||
gamepadDialogClasses,
|
||||
joinClassNames,
|
||||
} from "decky-frontend-lib";
|
||||
import { VFC, useState } from "react";
|
||||
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 {register_for_steam_events, unregister_for_steam_events} from "./steam_events";
|
||||
|
||||
const FieldWithSeparator = joinClassNames(gamepadDialogClasses.Field, gamepadDialogClasses.WithBottomSeparatorStandard);
|
||||
|
||||
const DISPLAY_KEY = "display";
|
||||
const VALUE_KEY = "value";
|
||||
import {DISPLAY_KEY} from "./consts";
|
||||
import {Elements} from "./components/elements";
|
||||
import {About} from "./components/about";
|
||||
|
||||
let items: backend.CElement[] = [];
|
||||
let about: backend.CAbout | null = null;
|
||||
|
@ -167,10 +160,6 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
|
|||
updateInternal(!triggerInternal);
|
||||
}
|
||||
|
||||
function updateIdc(_: any) {
|
||||
update();
|
||||
}
|
||||
|
||||
// perform tasks (like updating display elements) only while rendering the plugin
|
||||
let taskItem = updateTasks.pop();
|
||||
while (taskItem != undefined) {
|
||||
|
@ -180,12 +169,8 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => {
|
|||
|
||||
return (
|
||||
<PanelSection>
|
||||
{items.map(
|
||||
(elem, i) => {
|
||||
return <PanelSectionRow>{buildHtmlElement(elem, i, updateIdc)}</PanelSectionRow>
|
||||
})
|
||||
}
|
||||
{ about != null && buildAbout() }
|
||||
<Elements items={items}/>
|
||||
<About about={about}/>
|
||||
<PanelSectionRow>
|
||||
<ButtonItem
|
||||
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) => {
|
||||
return {
|
||||
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