move to rsbuild over webpack

This commit is contained in:
Rachel Powers
2024-04-20 14:56:53 -07:00
parent 756a47510f
commit d7d84fa7e6
18 changed files with 993 additions and 4407 deletions

View File

@@ -4,8 +4,8 @@
"description": "an IC10 emulator for IC10 mips from Stationeers", "description": "an IC10 emulator for IC10 mips from Stationeers",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"build": "webpack --config webpack.config.prod.js", "build": "rsbuild build",
"start": "webpack-dev-server" "start": "rsbuild dev"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -25,39 +25,24 @@
"homepage": "https://github.com/ryex/ic10emu#readme", "homepage": "https://github.com/ryex/ic10emu#readme",
"devDependencies": { "devDependencies": {
"@oneidentity/zstd-js": "^1.0.3", "@oneidentity/zstd-js": "^1.0.3",
"@rsbuild/core": "^0.6.4",
"@rsbuild/plugin-image-compress": "^0.6.4",
"@rsbuild/plugin-type-check": "^0.6.4",
"@rspack/cli": "^0.6.2",
"@rspack/core": "^0.6.2",
"@swc/helpers": "^0.5.10",
"@types/ace": "^0.0.52", "@types/ace": "^0.0.52",
"@types/bootstrap": "^5.2.10", "@types/bootstrap": "^5.2.10",
"@types/wicg-file-system-access": "^2023.10.5", "@types/wicg-file-system-access": "^2023.10.5",
"autoprefixer": "^10.4.19",
"copy-webpack-plugin": "^12.0.2",
"css-loader": "^6.11.0",
"css-minimizer-webpack-plugin": "^6.0.0",
"esbuild": "^0.20.2",
"esbuild-loader": "^4.1.0",
"extract-loader": "^5.1.0",
"fork-ts-checker-webpack-plugin": "^9.0.2", "fork-ts-checker-webpack-plugin": "^9.0.2",
"hello-wasm-pack": "^0.1.0",
"html-webpack-plugin": "^5.6.0",
"image-minimizer-webpack-plugin": "^4.0.0",
"imagemin": "^8.0.1",
"imagemin-gifsicle": "^7.0.0",
"imagemin-jpegtran": "^7.0.0",
"imagemin-optipng": "^8.0.0",
"imagemin-svgo": "^10.0.1",
"lit-scss-loader": "^2.0.1", "lit-scss-loader": "^2.0.1",
"mini-css-extract-plugin": "^2.9.0", "mini-css-extract-plugin": "^2.9.0",
"postcss-loader": "^8.1.1", "postcss-loader": "^8.1.1",
"sass": "^1.75.0", "sass": "^1.75.0",
"sass-loader": "^14.2.1",
"style-loader": "^3.3.4",
"thread-loader": "^4.0.2",
"ts-lit-plugin": "^2.0.2", "ts-lit-plugin": "^2.0.2",
"ts-loader": "^9.5.1", "ts-loader": "^9.5.1",
"typescript": "^5.4.5", "typescript": "^5.4.5",
"typescript-lit-html-plugin": "^0.9.0", "typescript-lit-html-plugin": "^0.9.0"
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4"
}, },
"dependencies": { "dependencies": {
"@leeoniya/ufuzzy": "^1.0.14", "@leeoniya/ufuzzy": "^1.0.14",

4589
www/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

70
www/rsbuild.config.ts Normal file
View File

@@ -0,0 +1,70 @@
import { defineConfig } from "@rsbuild/core";
import { pluginTypeCheck } from "@rsbuild/plugin-type-check";
import { pluginImageCompress } from '@rsbuild/plugin-image-compress';
const rspack = require("@rspack/core");
const path = require("path");
const commitHash = require("child_process")
.execSync("git rev-parse --short HEAD")
.toString()
.trim();
export default defineConfig({
output: {
targets: ["web"],
},
source: {
entry: {
index: "./src/ts/index.ts",
},
},
tools: {
rspack: {
plugins: [
new rspack.CopyRspackPlugin({
patterns: [
// "src/index.html",
"img/*.png",
"img/*/*.png",
// { from: "data/database.json", to: "data" },
// Copy Shoelace assets to dist/shoelace
{
from: path.resolve(
__dirname,
"node_modules/@shoelace-style/shoelace/dist/assets",
),
to: "shoelace/assets",
},
],
}),
new rspack.DefinePlugin({
__COMMIT_HASH__: JSON.stringify(commitHash),
__BUILD_DATE__: JSON.stringify(new Date()),
}),
],
},
swc: {
jsc: {
parser: {
syntax: "typescript",
// dynamicImport: true,
decorators: true,
},
transform: {
legacyDecorator: true,
decoratorMetadata: true,
// decoratorVersion: "2022-03",
},
// target: "es2021",
},
},
htmlPlugin: {
template: "./src/index.html",
},
},
plugins: [
pluginTypeCheck(),
pluginImageCompress(),
],
});

View File

@@ -12,6 +12,7 @@
<meta property="og:url" content="https://ryex.github.io/ic10emu/" /> <meta property="og:url" content="https://ryex.github.io/ic10emu/" />
<link rel="stylesheet" href="./main.css"> <link rel="stylesheet" href="./main.css">
<script src="./main.js"></script>
<style> <style>
body { body {
opacity: 0; opacity: 0;

View File

@@ -2,14 +2,14 @@ import { HTMLTemplateResult, html, css } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from "lit/decorators.js";
import { BaseElement, defaultCss } from "../components"; import { BaseElement, defaultCss } from "../components";
import '@shoelace-style/shoelace/dist/components/icon/icon.js'; import "@shoelace-style/shoelace/dist/components/icon/icon.js";
import "@shoelace-style/shoelace/dist/components/icon-button/icon-button.js"; import "@shoelace-style/shoelace/dist/components/icon-button/icon-button.js";
import "@shoelace-style/shoelace/dist/components/menu/menu.js"; import "@shoelace-style/shoelace/dist/components/menu/menu.js";
import "@shoelace-style/shoelace/dist/components/divider/divider.js"; import "@shoelace-style/shoelace/dist/components/divider/divider.js";
import "@shoelace-style/shoelace/dist/components/menu-item/menu-item.js"; import "@shoelace-style/shoelace/dist/components/menu-item/menu-item.js";
import "@shoelace-style/shoelace/dist/components/dropdown/dropdown.js"; import "@shoelace-style/shoelace/dist/components/dropdown/dropdown.js";
import '@shoelace-style/shoelace/dist/components/relative-time/relative-time.js'; import "@shoelace-style/shoelace/dist/components/relative-time/relative-time.js";
import '@shoelace-style/shoelace/dist/components/tooltip/tooltip.js'; import "@shoelace-style/shoelace/dist/components/tooltip/tooltip.js";
import SlMenuItem from "@shoelace-style/shoelace/dist/components/menu-item/menu-item.js"; import SlMenuItem from "@shoelace-style/shoelace/dist/components/menu-item/menu-item.js";
@customElement("app-nav") @customElement("app-nav")
@@ -99,9 +99,9 @@ export class Nav extends BaseElement {
super(); super();
} }
@property() accessor gitVer: string; @property() gitVer: string;
@property() accessor appVer: string; @property() appVer: string;
@property() accessor buildDate: string; @property() buildDate: string;
protected render(): HTMLTemplateResult { protected render(): HTMLTemplateResult {
return html` return html`
<nav id="navBar" class="navbar navbar-default"> <nav id="navBar" class="navbar navbar-default">
@@ -114,7 +114,11 @@ export class Nav extends BaseElement {
label="Main Menu" label="Main Menu"
></sl-icon-button> ></sl-icon-button>
<sl-menu class="menu" @sl-select=${this._menuClickHandler} style="z-index: 10"> <sl-menu
class="menu"
@sl-select=${this._menuClickHandler}
style="z-index: 10"
>
<sl-menu-item value="share"> <sl-menu-item value="share">
Share Share
<sl-icon name="share" slot="prefix"></sl-icon> <sl-icon name="share" slot="prefix"></sl-icon>
@@ -150,9 +154,7 @@ export class Nav extends BaseElement {
Presets Presets
<sl-icon name="code-square" slot="prefix"></sl-icon> <sl-icon name="code-square" slot="prefix"></sl-icon>
<sl-menu slot="submenu"> <sl-menu slot="submenu">
<sl-menu-item value="preset-demo"> <sl-menu-item value="preset-demo"> Demo </sl-menu-item>
Demo
</sl-menu-item>
</sl-menu> </sl-menu>
</sl-menu-item> </sl-menu-item>
</sl-menu> </sl-menu>
@@ -167,7 +169,9 @@ export class Nav extends BaseElement {
</div> </div>
<div class="hstack version mt-auto mb-auto"> <div class="hstack version mt-auto mb-auto">
<small>v${this.appVer}-${this.gitVer}</small> <small>v${this.appVer}-${this.gitVer}</small>
<small class="ms-2"><sl-relative-time date=${this.buildDate}></sl-relative-time></small> <small class="ms-2">
<sl-relative-time date=${this.buildDate}></sl-relative-time>
</small>
</div> </div>
</div> </div>
@@ -175,7 +179,8 @@ export class Nav extends BaseElement {
<a <a
class="navbar-text mt-auto mb-auto align-self-center" class="navbar-text mt-auto mb-auto align-self-center"
href="https://github.com/ryex/ic10emu" href="https://github.com/ryex/ic10emu"
>View on Github <sl-icon library="fa" name="fab-github"></sl-icon> >View on Github
<sl-icon library="fa" name="fab-github"></sl-icon>
</a> </a>
</div> </div>
@@ -239,7 +244,7 @@ export class Nav extends BaseElement {
case "keyboardShortcuts": case "keyboardShortcuts":
window.Editor.kbShortcuts.show(); window.Editor.kbShortcuts.show();
break; break;
case 'preset-demo': case "preset-demo":
window.location.hash = "demo"; window.location.hash = "demo";
default: default:
console.log("Unknown main menu item", item.value); console.log("Unknown main menu item", item.value);

View File

@@ -3,11 +3,11 @@ import { customElement, property, query, state } from "lit/decorators.js";
import { BaseElement, defaultCss } from "../components"; import { BaseElement, defaultCss } from "../components";
import { VMState } from "../session"; import { VMState } from "../session";
import '@shoelace-style/shoelace/dist/components/dialog/dialog.js'; import "@shoelace-style/shoelace/dist/components/dialog/dialog.js";
import '@shoelace-style/shoelace/dist/components/format-date/format-date.js'; import "@shoelace-style/shoelace/dist/components/format-date/format-date.js";
import '@shoelace-style/shoelace/dist/components/relative-time/relative-time.js'; import "@shoelace-style/shoelace/dist/components/relative-time/relative-time.js";
import '@shoelace-style/shoelace/dist/components/format-bytes/format-bytes.js'; import "@shoelace-style/shoelace/dist/components/format-bytes/format-bytes.js";
import SlInput from '@shoelace-style/shoelace/dist/components/input/input.js'; import SlInput from "@shoelace-style/shoelace/dist/components/input/input.js";
import { repeat } from "lit/directives/repeat.js"; import { repeat } from "lit/directives/repeat.js";
import SlDialog from "@shoelace-style/shoelace/dist/components/dialog/dialog.js"; import SlDialog from "@shoelace-style/shoelace/dist/components/dialog/dialog.js";
import { when } from "lit/directives/when.js"; import { when } from "lit/directives/when.js";
@@ -16,12 +16,10 @@ export type SaveDialogMode = "save" | "load";
@customElement("save-dialog") @customElement("save-dialog")
export class SaveDialog extends BaseElement { export class SaveDialog extends BaseElement {
static styles = [ static styles = [...defaultCss];
...defaultCss,
];
@state() accessor saves: { name: string, date: Date, session: VMState }[]; @state() saves: { name: string; date: Date; session: VMState }[];
@state() accessor mode: SaveDialogMode; @state() mode: SaveDialogMode;
constructor() { constructor() {
super(); super();
@@ -29,8 +27,13 @@ export class SaveDialog extends BaseElement {
} }
connectedCallback(): void { connectedCallback(): void {
super.connectedCallback() super.connectedCallback();
window.App.get().then(app => app.session.addEventListener("sessions-local-update", this._handleSessionsUpdate.bind(this))); window.App.get().then((app) =>
app.session.addEventListener(
"sessions-local-update",
this._handleSessionsUpdate.bind(this),
),
);
this.loadsaves(); this.loadsaves();
} }
@@ -45,7 +48,7 @@ export class SaveDialog extends BaseElement {
}); });
} }
@query("sl-dialog") accessor dialog: SlDialog; @query("sl-dialog") dialog: SlDialog;
show(mode: SaveDialogMode) { show(mode: SaveDialogMode) {
this.mode = mode; this.mode = mode;
@@ -59,16 +62,27 @@ export class SaveDialog extends BaseElement {
render() { render() {
return html` return html`
<sl-dialog label="Save Session"> <sl-dialog label="Save Session">
${when(this.mode === "save", ${when(
this.mode === "save",
() => html` () => html`
<div class="hstack mb-2"> <div class="hstack mb-2">
<sl-input class="save-name-input" autofocus></sl-input> <sl-input class="save-name-input" autofocus></sl-input>
<sl-button class="ms-2" variant="success" @click=${this._handleSaveClick}>Save</sl-button> <sl-button
</div> class="ms-2"
` variant="success"
@click=${this._handleSaveClick}
>Save</sl-button
>
</div>
`,
)} )}
<sl-input class="filter-input" ?autofocus=${this.mode === "load"} placeholder="Filter Saves" clearable <sl-input
@sl-input=${this._handleSearchInput}> class="filter-input"
?autofocus=${this.mode === "load"}
placeholder="Filter Saves"
clearable
@sl-input=${this._handleSearchInput}
>
<sl-icon slot="suffix" name="search"></sl-icon> <sl-icon slot="suffix" name="search"></sl-icon>
</sl-input> </sl-input>
<table> <table>
@@ -77,22 +91,26 @@ export class SaveDialog extends BaseElement {
<th>Date</th> <th>Date</th>
<th>Size</th> <th>Size</th>
</tr> </tr>
${when( ${when(typeof this.saves !== "undefined", () =>
typeof this.saves !== "undefined", repeat(
() => repeat(this.saves, (save) => save.name, (save) => { this.saves,
const size = JSON.stringify(save.session).length (save) => save.name,
return html` (save) => {
<tr> const size = JSON.stringify(save.session).length;
<td>${save.name}</td> return html`
<td> <tr>
<sl-format-date .date=${save.date}></sl-format-date> <td>${save.name}</td>
<sl-relative-time .date=${save.date}></sl-relative-time> <td>
</td> <sl-format-date .date=${save.date}></sl-format-date>
<td><sl-format-bytes .value=${size}></sl-format-bytes></td> <sl-relative-time .date=${save.date}></sl-relative-time>
</tr> </td>
`; <td>
}, <sl-format-bytes .value=${size}></sl-format-bytes>
) </td>
</tr>
`;
},
),
)} )}
</table> </table>
</sl-dialog> </sl-dialog>
@@ -108,7 +126,5 @@ export class SaveDialog extends BaseElement {
await app.session.saveLocal(name); await app.session.saveLocal(name);
} }
_handleSearchInput() { _handleSearchInput() {}
}
} }

View File

@@ -12,9 +12,9 @@ import SlInput from "@shoelace-style/shoelace/dist/components/input/input.js";
@customElement("session-share-dialog") @customElement("session-share-dialog")
export class ShareSessionDialog extends BaseElement { export class ShareSessionDialog extends BaseElement {
@query(".dialog") accessor dialog: SlDialog; @query(".dialog") dialog: SlDialog;
@query(".input") accessor input: SlInput; @query(".input") input: SlInput;
@property({ type: String }) accessor link: string; @property({ type: String }) link: string;
constructor() { constructor() {
super(); super();

View File

@@ -11,7 +11,7 @@ import SlDetails from "@shoelace-style/shoelace/dist/components/details/details.
@customElement("ic10-details") @customElement("ic10-details")
export class IC10Details extends SlDetails { export class IC10Details extends SlDetails {
@query(".details__summary-icon") accessor summaryIcon: HTMLSpanElement; @query(".details__summary-icon") summaryIcon: HTMLSpanElement;
static styles = [ static styles = [
SlDetails.styles, SlDetails.styles,

View File

@@ -1,10 +1,4 @@
import { import { ace, Ace, Range, AceLanguageClient, setupLspWorker } from "./ace";
ace,
Ace,
Range,
AceLanguageClient,
setupLspWorker,
} from "./ace";
import { LanguageProvider } from "ace-linters/types/language-provider"; import { LanguageProvider } from "ace-linters/types/language-provider";
@@ -32,7 +26,10 @@ import { customElement, state, query } from "lit/decorators.js";
import { editorStyles } from "./styles"; import { editorStyles } from "./styles";
import "./shortcuts_ui"; import "./shortcuts_ui";
import { AceKeyboardShortcuts } from "./shortcuts_ui"; import { AceKeyboardShortcuts } from "./shortcuts_ui";
import { LanguageClientConfig, ProviderOptions } from "ace-linters/types/types/language-service"; import {
LanguageClientConfig,
ProviderOptions,
} from "ace-linters/types/types/language-service";
@customElement("ace-ic10") @customElement("ace-ic10")
export class IC10Editor extends BaseElement { export class IC10Editor extends BaseElement {
@@ -69,9 +66,9 @@ export class IC10Editor extends BaseElement {
stylesAdded: string[]; stylesAdded: string[];
tooltipObserver: MutationObserver; tooltipObserver: MutationObserver;
@query(".e-kb-shortcuts") accessor kbShortcuts: AceKeyboardShortcuts; @query(".e-kb-shortcuts") kbShortcuts: AceKeyboardShortcuts;
@query(".e-settings-dialog") accessor settingDialog: SlDialog; @query(".e-settings-dialog") settingDialog: SlDialog;
constructor() { constructor() {
super(); super();
@@ -137,8 +134,9 @@ export class IC10Editor extends BaseElement {
<sl-switch <sl-switch
id="editorRelativeLineNumbers" id="editorRelativeLineNumbers"
?checked=${this.settings.relativeLineNumbers} ?checked=${this.settings.relativeLineNumbers}
>Relative Line Numbers</sl-switch >
> Relative Line Numbers
</sl-switch>
</sl-dialog> </sl-dialog>
<ace-kb-menu class="e-kb-shortcuts"></ace-kb-menu> <ace-kb-menu class="e-kb-shortcuts"></ace-kb-menu>
`; `;
@@ -513,9 +511,9 @@ export class IC10Editor extends BaseElement {
}; };
const options: ProviderOptions = { const options: ProviderOptions = {
functionality: { functionality: {
semanticTokens: true semanticTokens: true,
} },
} };
// Create a language provider for web worker // Create a language provider for web worker
this.languageProvider = AceLanguageClient.for(serverData, options); this.languageProvider = AceLanguageClient.for(serverData, options);
this.languageProvider.registerEditor(this.editor); this.languageProvider.registerEditor(this.editor);
@@ -589,7 +587,9 @@ export class IC10Editor extends BaseElement {
if (session) { if (session) {
session.on("change", () => { session.on("change", () => {
var val = session.getValue(); var val = session.getValue();
window.App.get().then(app => app.session.setProgramCode(session_id, val)); window.App.get().then((app) =>
app.session.setProgramCode(session_id, val),
);
}); });
} }
} }

View File

@@ -29,7 +29,7 @@ export class AceKeyboardShortcuts extends BaseElement {
]; ];
editor?: Ace.Editor; editor?: Ace.Editor;
@query('.drawer') accessor drawer: SlDrawer; @query(".drawer") drawer: SlDrawer;
constructor() { constructor() {
super(); super();

View File

@@ -47,7 +47,6 @@ export const VMDeviceMixin = <T extends Constructor<LitElement>>(
superClass: T, superClass: T,
) => { ) => {
class VMDeviceMixinClass extends superClass { class VMDeviceMixinClass extends superClass {
_deviceID: number; _deviceID: number;
get deviceID() { get deviceID() {
return this._deviceID; return this._deviceID;
@@ -60,33 +59,37 @@ export const VMDeviceMixin = <T extends Constructor<LitElement>>(
device: DeviceRef; device: DeviceRef;
@state() accessor name: string | null = null; @state() name: string | null = null;
@state() accessor nameHash: number | null = null; @state() nameHash: number | null = null;
@state() accessor prefabName: string | null; @state() prefabName: string | null;
@state() accessor fields: LogicFields; @state() fields: LogicFields;
@state() accessor slots: Slot[]; @state() slots: Slot[];
@state() accessor reagents: Reagents; @state() reagents: Reagents;
@state() accessor connections: Connection[]; @state() connections: Connection[];
@state() accessor icIP: number; @state() icIP: number;
@state() accessor icOpCount: number; @state() icOpCount: number;
@state() accessor icState: string; @state() icState: string;
@state() accessor errors: ICError[]; @state() errors: ICError[];
@state() accessor registers: Registers | null; @state() registers: Registers | null;
@state() accessor stack: Stack | null; @state() stack: Stack | null;
@state() accessor aliases: Aliases | null; @state() aliases: Aliases | null;
@state() accessor defines: Defines | null; @state() defines: Defines | null;
@state() accessor pins: Pins | null; @state() pins: Pins | null;
connectedCallback(): void { connectedCallback(): void {
const root = super.connectedCallback(); const root = super.connectedCallback();
window.VM.get().then(vm => vm.addEventListener( window.VM.get().then((vm) =>
"vm-device-modified", vm.addEventListener(
this._handleDeviceModified.bind(this), "vm-device-modified",
)); this._handleDeviceModified.bind(this),
window.VM.get().then(vm => vm.addEventListener( ),
"vm-devices-update", );
this._handleDevicesModified.bind(this), window.VM.get().then((vm) =>
)); vm.addEventListener(
"vm-devices-update",
this._handleDevicesModified.bind(this),
),
);
this.updateDevice(); this.updateDevice();
return root; return root;
} }
@@ -194,10 +197,9 @@ export const VMActiveICMixin = <T extends Constructor<LitElement>>(
connectedCallback(): void { connectedCallback(): void {
const root = super.connectedCallback(); const root = super.connectedCallback();
window.VM.get().then(vm => vm.addEventListener( window.VM.get().then((vm) =>
"vm-run-ic", vm.addEventListener("vm-run-ic", this._handleDeviceModified.bind(this)),
this._handleDeviceModified.bind(this), );
));
window.App.app.session.addEventListener( window.App.app.session.addEventListener(
"session-active-ic", "session-active-ic",
this._handleActiveIC.bind(this), this._handleActiveIC.bind(this),

View File

@@ -65,7 +65,7 @@ export class VMICControls extends VMActiveICMixin(BaseElement) {
`, `,
]; ];
@query(".active-ic-select") accessor activeICSelect: SlSelect; @query(".active-ic-select") activeICSelect: SlSelect;
protected render() { protected render() {
const ics = Array.from(window.VM.vm.ics); const ics = Array.from(window.VM.vm.ics);
@@ -125,7 +125,11 @@ export class VMICControls extends VMActiveICMixin(BaseElement) {
> >
${ics.map( ${ics.map(
([id, device], _index) => ([id, device], _index) =>
html`<sl-option name=${device.name} prefabName=${device.prefabName} value=${id}> html`<sl-option
name=${device.name}
prefabName=${device.prefabName}
value=${id}
>
${device.name ${device.name
? html`<span slot="suffix">${device.prefabName}</span>` ? html`<span slot="suffix">${device.prefabName}</span>`
: ""} : ""}
@@ -170,13 +174,13 @@ export class VMICControls extends VMActiveICMixin(BaseElement) {
} }
_handleRunClick() { _handleRunClick() {
window.VM.get().then(vm => vm.run()); window.VM.get().then((vm) => vm.run());
} }
_handleStepClick() { _handleStepClick() {
window.VM.get().then(vm => vm.step()); window.VM.get().then((vm) => vm.step());
} }
_handleResetClick() { _handleResetClick() {
window.VM.get().then(vm => vm.reset()); window.VM.get().then((vm) => vm.reset());
} }
updateIC(): void { updateIC(): void {

View File

@@ -53,7 +53,7 @@ import { cache } from "lit/directives/cache.js";
export class VMDeviceCard extends VMDeviceMixin(BaseElement) { export class VMDeviceCard extends VMDeviceMixin(BaseElement) {
image_err: boolean; image_err: boolean;
@property({ type: Boolean }) accessor open: boolean; @property({ type: Boolean }) open: boolean;
constructor() { constructor() {
super(); super();
@@ -200,68 +200,31 @@ export class VMDeviceCard extends VMDeviceMixin(BaseElement) {
}, this); }, this);
return html` return html`
<sl-tooltip content="${this.prefabName}"> <sl-tooltip content="${this.prefabName}">
<img <img class="image" src="img/stationpedia/${this.prefabName}.png"
class="image" onerror="this.src = '${VMDeviceCard.transparentImg}'" />
src="img/stationpedia/${this.prefabName}.png"
onerror="this.src = '${VMDeviceCard.transparentImg}'"
/>
</sl-tooltip> </sl-tooltip>
<div class="header-name"> <div class="header-name">
<sl-input <sl-input id="vmDeviceCard${this.deviceID}Id" class="device-id" size="small" pill value=${this.deviceID}
id="vmDeviceCard${this.deviceID}Id" @sl-change=${this._handleChangeID}>
class="device-id"
size="small"
pill
value=${this.deviceID}
@sl-change=${this._handleChangeID}
>
<span slot="prefix">Id</span> <span slot="prefix">Id</span>
<sl-copy-button slot="suffix" value=${this.deviceID}></sl-copy-button> <sl-copy-button slot="suffix" value=${this.deviceID}></sl-copy-button>
</sl-input> </sl-input>
<sl-input <sl-input id="vmDeviceCard${this.deviceID}Name" class="device-name" size="small" pill placeholder=${this.prefabName}
id="vmDeviceCard${this.deviceID}Name" value=${this.name} @sl-change=${this._handleChangeName}>
class="device-name"
size="small"
pill
placeholder=${this.prefabName}
value=${this.name}
@sl-change=${this._handleChangeName}
>
<span slot="prefix">Name</span> <span slot="prefix">Name</span>
<sl-copy-button <sl-copy-button slot="suffix" from="vmDeviceCard${this.deviceID}Name.value"></sl-copy-button>
slot="suffix"
from="vmDeviceCard${this.deviceID}Name.value"
></sl-copy-button>
</sl-input> </sl-input>
<sl-input <sl-input id="vmDeviceCard${this.deviceID}NameHash" size="small" pill class="device-name-hash"
id="vmDeviceCard${this.deviceID}NameHash" value="${this.nameHash}" disabled>
size="small"
pill
class="device-name-hash"
value="${this.nameHash}"
disabled
>
<span slot="prefix">Hash</span> <span slot="prefix">Hash</span>
<sl-copy-button <sl-copy-button slot="suffix" from="vmDeviceCard${this.deviceID}NameHash.value"></sl-copy-button>
slot="suffix"
from="vmDeviceCard${this.deviceID}NameHash.value"
></sl-copy-button>
</sl-input> </sl-input>
${badges.map((badge) => badge)} ${badges.map((badge) => badge)}
</div> </div>
<div class="ms-auto mt-auto mb-auto me-2"> <div class="ms-auto mt-auto mb-auto me-2">
<sl-tooltip <sl-tooltip content=${thisIsActiveIc ? "Removing the selected Active IC is disabled" : "Remove Device" }>
content=${thisIsActiveIc <sl-icon-button class="remove-button" name="trash" label="Remove Device" ?disabled=${thisIsActiveIc}
? "Removing the selected Active IC is disabled" @click=${this._handleDeviceRemoveButton}></sl-icon-button>
: "Remove Device"}
>
<sl-icon-button
class="remove-button"
name="trash"
label="Remove Device"
?disabled=${thisIsActiveIc}
@click=${this._handleDeviceRemoveButton}
></sl-icon-button>
</sl-tooltip> </sl-tooltip>
</div> </div>
`; `;
@@ -272,20 +235,12 @@ export class VMDeviceCard extends VMDeviceMixin(BaseElement) {
const inputIdBase = `vmDeviceCard${this.deviceID}Field`; const inputIdBase = `vmDeviceCard${this.deviceID}Field`;
return html` return html`
${fields.map(([name, field], _index, _fields) => { ${fields.map(([name, field], _index, _fields) => {
return html` <sl-input return html` <sl-input id="${inputIdBase}${name}" key="${name}" value="${displayNumber(field.value)}" size="small"
id="${inputIdBase}${name}" @sl-change=${this._handleChangeField}>
key="${name}" <span slot="prefix">${name}</span>
value="${displayNumber(field.value)}" <sl-copy-button slot="suffix" from="${inputIdBase}${name}.value"></sl-copy-button>
size="small" <span slot="suffix">${field.field_type}</span>
@sl-change=${this._handleChangeField} </sl-input>`;
>
<span slot="prefix">${name}</span>
<sl-copy-button
slot="suffix"
from="${inputIdBase}${name}.value"
></sl-copy-button>
<span slot="suffix">${field.field_type}</span>
</sl-input>`;
})} })}
`; `;
} }
@@ -396,8 +351,8 @@ export class VMDeviceCard extends VMDeviceMixin(BaseElement) {
(pin, index) => (pin, index) =>
html` html`
<sl-select hoist placement="top" clearable key=${index} value=${pin} @sl-change=${this._handleChangePin}> <sl-select hoist placement="top" clearable key=${index} value=${pin} @sl-change=${this._handleChangePin}>
<span slot="prefix">d${index}</span> <span slot="prefix">d${index}</span>
${visibleDevices.map( ${visibleDevices.map(
(device, _index) => (device, _index) =>
html` html`
<sl-option value=${device.id}> <sl-option value=${device.id}>
@@ -425,47 +380,31 @@ export class VMDeviceCard extends VMDeviceMixin(BaseElement) {
<sl-tab slot="nav" panel="networks">Networks</sl-tab> <sl-tab slot="nav" panel="networks">Networks</sl-tab>
<sl-tab slot="nav" panel="pins" ?disabled=${!this.pins}>Pins</sl-tab> <sl-tab slot="nav" panel="pins" ?disabled=${!this.pins}>Pins</sl-tab>
<sl-tab-panel name="fields" active <sl-tab-panel name="fields" active>${this.renderFields()}</sl-tab-panel>
>${this.renderFields()}</sl-tab-panel
>
<sl-tab-panel name="slots">${this.renderSlots()}</sl-tab-panel> <sl-tab-panel name="slots">${this.renderSlots()}</sl-tab-panel>
<sl-tab-panel name="reagents">${this.renderReagents()}</sl-tab-panel> <sl-tab-panel name="reagents">${this.renderReagents()}</sl-tab-panel>
<sl-tab-panel name="networks">${this.renderNetworks()}</sl-tab-panel> <sl-tab-panel name="networks">${this.renderNetworks()}</sl-tab-panel>
<sl-tab-panel name="pins">${this.renderPins()}</sl-tab-panel> <sl-tab-panel name="pins">${this.renderPins()}</sl-tab-panel>
</sl-tab-group> </sl-tab-group>
</ic10-details> </ic10-details>
<sl-dialog <sl-dialog class="remove-device-dialog" no-header @sl-request-close=${this._preventOverlayClose}>
class="remove-device-dialog"
no-header
@sl-request-close=${this._preventOverlayClose}
>
<div class="remove-dialog-body"> <div class="remove-dialog-body">
<img <img class="dialog-image mt-auto mb-auto me-2" src="img/stationpedia/${this.prefabName}.png"
class="dialog-image mt-auto mb-auto me-2" onerror="this.src = '${VMDeviceCard.transparentImg}'" />
src="img/stationpedia/${this.prefabName}.png"
onerror="this.src = '${VMDeviceCard.transparentImg}'"
/>
<div class="flex-g"> <div class="flex-g">
<p><strong>Are you sure you want to remove this device?</strong></p> <p><strong>Are you sure you want to remove this device?</strong></p>
<span>Id ${this.deviceID} : ${this.name ?? this.prefabName}</span> <span>Id ${this.deviceID} : ${this.name ?? this.prefabName}</span>
</div> </div>
</div> </div>
<div slot="footer"> <div slot="footer">
<sl-button <sl-button variant="primary" autofocus @click=${this._closeRemoveDialog}>Close</sl-button>
variant="primary" <sl-button variant="danger" @click=${this._removeDialogRemove}>Remove</sl-button>
autofocus
@click=${this._closeRemoveDialog}
>Close</sl-button
>
<sl-button variant="danger" @click=${this._removeDialogRemove}
>Remove</sl-button
>
</div> </div>
</sl-dialog> </sl-dialog>
`; `;
} }
@query(".remove-device-dialog") accessor removeDialog: SlDialog; @query(".remove-device-dialog") removeDialog: SlDialog;
_preventOverlayClose(event: CustomEvent) { _preventOverlayClose(event: CustomEvent) {
if (event.detail.source === "overlay") { if (event.detail.source === "overlay") {
@@ -557,7 +496,7 @@ export class VMDeviceCard extends VMDeviceMixin(BaseElement) {
@customElement("vm-device-list") @customElement("vm-device-list")
export class VMDeviceList extends BaseElement { export class VMDeviceList extends BaseElement {
@state() accessor devices: number[]; @state() devices: number[];
static styles = [ static styles = [
...defaultCss, ...defaultCss,
@@ -650,7 +589,7 @@ export class VMDeviceList extends BaseElement {
private _filteredDeviceIds: number[] | undefined; private _filteredDeviceIds: number[] | undefined;
private _filter: string = ""; private _filter: string = "";
@query(".device-filter-input") accessor filterInput: SlInput; @query(".device-filter-input") filterInput: SlInput;
get filter() { get filter() {
return this._filter; return this._filter;
} }
@@ -729,8 +668,8 @@ export class VMAddDeviceButton extends BaseElement {
`, `,
]; ];
@query("sl-drawer") accessor drawer: SlDrawer; @query("sl-drawer") drawer: SlDrawer;
@query(".device-search-input") accessor searchInput: SlInput; @query(".device-search-input") searchInput: SlInput;
private _deviceDB: DeviceDB; private _deviceDB: DeviceDB;
private _strutures: Map<string, DeviceDBEntry> = new Map(); private _strutures: Map<string, DeviceDBEntry> = new Map();
@@ -828,11 +767,7 @@ export class VMAddDeviceButton extends BaseElement {
this._searchResults ?? [], this._searchResults ?? [],
(result) => result.name, (result) => result.name,
(result) => cache(html` (result) => cache(html`
<vm-device-template <vm-device-template prefab_name=${result.name} class="card" @add-device-template=${this._handleDeviceAdd}>
prefab_name=${result.name}
class="card"
@add-device-template=${this._handleDeviceAdd}
>
</vm-device-template> </vm-device-template>
`) `)
); );
@@ -845,33 +780,20 @@ export class VMAddDeviceButton extends BaseElement {
render() { render() {
return html` return html`
<sl-button <sl-button variant="neutral" outline pill @click=${this._handleAddButtonClick}>
variant="neutral"
outline
pill
@click=${this._handleAddButtonClick}
>
Add Device Add Device
</sl-button> </sl-button>
<sl-drawer class="add-device-drawer" placement="bottom" no-header> <sl-drawer class="add-device-drawer" placement="bottom" no-header>
<sl-input <sl-input class="device-search-input" autofocus placeholder="Search For Device" clearable
class="device-search-input" @sl-input=${this._handleSearchInput}>
autofocus
placeholder="Search For Device"
clearable
@sl-input=${this._handleSearchInput}
>
<span slot="prefix">Search Structures</span> <span slot="prefix">Search Structures</span>
<sl-icon slot="suffix" name="search"></sl-icon> <sl-icon slot="suffix" name="search"></sl-icon>
</sl-input> </sl-input>
<div class="search-results">${this.renderSearchResults()}</div> <div class="search-results">${this.renderSearchResults()}</div>
<sl-button <sl-button slot="footer" variant="primary" @click=${()=> {
slot="footer" this.drawer.hide();
variant="primary"
@click=${() => {
this.drawer.hide();
}} }}
> >
Close Close
</sl-button> </sl-button>
</sl-drawer> </sl-drawer>
@@ -928,12 +850,12 @@ export class VmDeviceTemplate extends BaseElement {
`, `,
]; ];
@state() accessor fields: { [key in LogicType]?: LogicField }; @state() fields: { [key in LogicType]?: LogicField };
@state() accessor slots: SlotTemplate[]; @state() slots: SlotTemplate[];
@state() accessor template: DeviceTemplate; @state() template: DeviceTemplate;
@state() accessor device_id: number | undefined; @state() device_id: number | undefined;
@state() accessor device_name: string | undefined; @state() device_name: string | undefined;
@state() accessor connections: Connection[]; @state() connections: Connection[];
constructor() { constructor() {
super(); super();

View File

@@ -24,7 +24,7 @@ class VirtualMachine extends EventTarget {
_devices: Map<number, DeviceRef>; _devices: Map<number, DeviceRef>;
_ics: Map<number, DeviceRef>; _ics: Map<number, DeviceRef>;
accessor db: DeviceDB; db: DeviceDB;
dbPromise: Promise<{ default: DeviceDB }>; dbPromise: Promise<{ default: DeviceDB }>;
private app: App; private app: App;

View File

@@ -11,6 +11,7 @@
"esModuleInterop": true, "esModuleInterop": true,
"isolatedModules": true, "isolatedModules": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"emitDecoratorMetadata": true,
"useDefineForClassFields": false, "useDefineForClassFields": false,
"types": ["@types/wicg-file-system-access", "@types/ace"], "types": ["@types/wicg-file-system-access", "@types/ace"],
"plugins": [ "plugins": [

View File

@@ -1,129 +0,0 @@
const CopyWebpackPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const miniCssExtractPlugin = require("mini-css-extract-plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
const { SourceMap } = require("module");
const webpack = require("webpack");
const path = require("path");
const commitHash = require('child_process')
.execSync('git rev-parse --short HEAD')
.toString()
.trim();
module.exports = {
entry: "./src/ts/main.ts",
output: {
path: path.resolve(__dirname, "dist"),
filename: "main.js",
clean: true,
},
devServer: {
static: path.resolve(__dirname, "dist"),
port: 8080,
hot: true,
},
mode: "development",
devtool: "eval-source-map",
plugins: [
new ForkTsCheckerWebpackPlugin(),
new CopyWebpackPlugin({
patterns: [
"img/*.png",
"img/*/*.png",
// { from: "data/database.json", to: "data" },
// Copy Shoelace assets to dist/shoelace
{
from: path.resolve(
__dirname,
"node_modules/@shoelace-style/shoelace/dist/assets",
),
to: "shoelace/assets",
},
],
}),
new HtmlWebpackPlugin({ template: "./src/index.html" }),
new miniCssExtractPlugin(),
new webpack.DefinePlugin({
__COMMIT_HASH__: JSON.stringify(commitHash),
__BUILD_DATE__: JSON.stringify(new Date),
}),
],
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
loader: "esbuild-loader",
options: {
target: "es2021",
tsconfig: "./tsconfig.json",
},
},
{
test: /\.(jpg|png|svg|gif)$/,
type: "asset/resource",
},
{
test: /\.css|\.s(c|a)ss$/,
use: [
{
// inject CSS to page
loader: miniCssExtractPlugin.loader,
},
{
// translates CSS into CommonJS modules
loader: "css-loader",
options: {
sourceMap: true,
},
},
{
// Run postcss actions
loader: "postcss-loader",
options: {
// `postcssOptions` is needed for postcss 8.x;
// if you use postcss 7.x skip the key
postcssOptions: {
// postcss plugins, can be exported to postcss.config.js
plugins: function () {
return [require("autoprefixer")];
},
},
},
},
{
// compiles Sass to CSS
loader: "sass-loader",
options: {
sourceMap: true,
},
},
],
// parser: {
// javascript : { importMeta: false }
// }
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js", ".json"],
fallback: {
crypto: require.resolve("crypto-browserify"),
buffer: require.resolve("buffer"),
stream: require.resolve("stream-browserify"),
vm: require.resolve("vm-browserify"),
},
},
experiments: {
asyncWebAssembly: true,
syncWebAssembly: true,
},
watchOptions: {
aggregateTimeout: 200,
poll: 200,
},
optimization: {
chunkIds: "named",
},
};

View File

@@ -1,162 +0,0 @@
const CopyWebpackPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const miniCssExtractPlugin = require("mini-css-extract-plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
const { EsbuildPlugin } = require("esbuild-loader");
const webpack = require("webpack");
const path = require("path");
const commitHash = require('child_process')
.execSync('git rev-parse --short HEAD')
.toString()
.trim();
module.exports = {
entry: "./src/ts/main.ts",
output: {
path: path.resolve(__dirname, "dist"),
filename: "main.js",
clean: true,
},
mode: "production",
devtool: "source-map",
plugins: [
new ForkTsCheckerWebpackPlugin(),
new CopyWebpackPlugin({
patterns: [
"img/*.png",
"img/*/*.png",
// { from: "data/database.json", to: "data" },
// Copy Shoelace assets to dist/shoelace
{
from: path.resolve(
__dirname,
"node_modules/@shoelace-style/shoelace/dist/assets",
),
to: "shoelace/assets",
},
],
}),
new HtmlWebpackPlugin({ template: "./src/index.html" }),
new miniCssExtractPlugin(),
new webpack.DefinePlugin({
__COMMIT_HASH__: JSON.stringify(commitHash),
__BUILD_DATE__: JSON.stringify(new Date),
}),
],
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
loader: "esbuild-loader",
options: {
target: "es2021",
tsconfig: "./tsconfig.json",
},
},
{
test: /\.(jpg|png|svg|gif)$/,
type: "asset/resource",
},
{
test: /\.(scss)$/,
use: [
{
// inject CSS to page
loader: miniCssExtractPlugin.loader,
},
{
// translates CSS into CommonJS modules
loader: "css-loader",
},
{
loader: "esbuild-loader",
options: {
loader: 'css',
minify: true,
},
},
{
// Run postcss actions
loader: "postcss-loader",
options: {
// `postcssOptions` is needed for postcss 8.x;
// if you use postcss 7.x skip the key
postcssOptions: {
// postcss plugins, can be exported to postcss.config.js
plugins: function () {
return [require("autoprefixer")];
},
},
},
},
{
// compiles Sass to CSS
loader: "sass-loader",
},
],
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
fallback: {
crypto: require.resolve("crypto-browserify"),
buffer: require.resolve("buffer"),
stream: require.resolve("stream-browserify"),
vm: require.resolve("vm-browserify"),
},
},
experiments: {
asyncWebAssembly: true,
syncWebAssembly: true,
},
optimization: {
minimizer: [
new EsbuildPlugin({
target: "es2021", // Syntax to transpile to (see options below for possible values)
css: true,
}),
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminMinify,
options: {
// Lossless optimization with custom option
// Feel free to experiment with options for better result for you
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
// Svgo configuration here https://github.com/svg/svgo#configuration
[
"svgo",
{
plugins: [
{
name: "preset-default",
params: {
overrides: {
removeViewBox: false,
addAttributesToSVGElement: {
params: {
attributes: [
{ xmlns: "http://www.w3.org/2000/svg" },
],
},
},
},
},
},
],
},
],
],
},
},
}),
],
},
};