prepare web build
This commit is contained in:
parent
fcd270861c
commit
d635ab673c
6 changed files with 44 additions and 45 deletions
12
CLAUDE.md
12
CLAUDE.md
|
|
@ -35,6 +35,18 @@ On Windows, use the launcher for best UTF-8 support:
|
||||||
OpenTheBox.cmd
|
OpenTheBox.cmd
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Web Build (itch.io)
|
||||||
|
```
|
||||||
|
dotnet run --project src/OpenTheBox.Web # Dev local (http://localhost:5000)
|
||||||
|
dotnet publish src/OpenTheBox.Web -c Release -o builds/web # Publication
|
||||||
|
```
|
||||||
|
Upload `builds/web/wwwroot/` sur itch.io en HTML5.
|
||||||
|
|
||||||
|
Running locally:
|
||||||
|
```
|
||||||
|
npx serve builds/web/wwwroot/
|
||||||
|
```
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
```
|
```
|
||||||
dotnet test
|
dotnet test
|
||||||
|
|
|
||||||
|
|
@ -592,7 +592,7 @@ public sealed class WebGameHost
|
||||||
ColorSystem = ColorSystemSupport.TrueColor
|
ColorSystem = ColorSystemSupport.TrueColor
|
||||||
});
|
});
|
||||||
bufferConsole.Profile.Width = WebTerminal.Width;
|
bufferConsole.Profile.Width = WebTerminal.Width;
|
||||||
bufferConsole.Profile.Height = _terminal.Height;
|
bufferConsole.Profile.Height = WebTerminal.Height;
|
||||||
|
|
||||||
bufferConsole.Write(InventoryPanel.Render(_state, _registry, _loc, scrollOffset, selectedIndex: selectedIndex));
|
bufferConsole.Write(InventoryPanel.Render(_state, _registry, _loc, scrollOffset, selectedIndex: selectedIndex));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ public sealed class WebTerminal
|
||||||
});
|
});
|
||||||
|
|
||||||
public const int Width = 120;
|
public const int Width = 120;
|
||||||
public int Height { get; private set; } = 30;
|
public const int Height = 30;
|
||||||
|
|
||||||
public WebTerminal(IJSRuntime js)
|
public WebTerminal(IJSRuntime js)
|
||||||
{
|
{
|
||||||
|
|
@ -37,24 +37,13 @@ public sealed class WebTerminal
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes the xterm.js terminal in the browser and reads actual dimensions.
|
/// Initializes the xterm.js terminal in the browser (fixed 120x30).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task InitAsync()
|
public async Task InitAsync()
|
||||||
{
|
{
|
||||||
await _js.InvokeVoidAsync("terminalInterop.init");
|
await _js.InvokeVoidAsync("terminalInterop.init");
|
||||||
|
|
||||||
// Read actual terminal dimensions after fitAddon has sized the terminal
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var dims = await _js.InvokeAsync<TerminalDimensions>("terminalInterop.getDimensions");
|
|
||||||
if (dims.rows >= 30)
|
|
||||||
Height = dims.rows;
|
|
||||||
}
|
|
||||||
catch { /* fallback to 30 */ }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private record TerminalDimensions(int cols, int rows);
|
|
||||||
|
|
||||||
// ── Output ───────────────────────────────────────────────────────────
|
// ── Output ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -94,7 +83,7 @@ public sealed class WebTerminal
|
||||||
ColorSystem = ColorSystemSupport.TrueColor
|
ColorSystem = ColorSystemSupport.TrueColor
|
||||||
});
|
});
|
||||||
console.Profile.Width = Width;
|
console.Profile.Width = Width;
|
||||||
console.Profile.Height = _instance?.Height ?? 50;
|
console.Profile.Height = Height;
|
||||||
console.Write(renderable);
|
console.Write(renderable);
|
||||||
return writer.ToString();
|
return writer.ToString();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,17 +21,16 @@ body {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#terminal-container.active {
|
#terminal-container.active {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Let xterm.js determine the natural size from 120x30 @ fontSize 16.
|
||||||
|
CSS transform scale (set by JS) shrinks it to fit smaller viewports. */
|
||||||
#terminal {
|
#terminal {
|
||||||
width: 100%;
|
flex-shrink: 0;
|
||||||
height: 100%;
|
|
||||||
max-width: 1200px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loading screen */
|
/* Loading screen */
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/lib/xterm.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@xterm/xterm@5.5.0/lib/xterm.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/@xterm/addon-fit@0.10.0/lib/addon-fit.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/@xterm/addon-web-links@0.11.0/lib/addon-web-links.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@xterm/addon-web-links@0.11.0/lib/addon-web-links.min.js"></script>
|
||||||
<script src="js/terminal-interop.js"></script>
|
<script src="js/terminal-interop.js"></script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
// Terminal interop bridge: xterm.js <-> .NET Blazor WASM
|
// Terminal interop bridge: xterm.js <-> .NET Blazor WASM
|
||||||
window.terminalInterop = {
|
window.terminalInterop = {
|
||||||
term: null,
|
term: null,
|
||||||
fitAddon: null,
|
|
||||||
|
|
||||||
init: function () {
|
init: function () {
|
||||||
const term = new Terminal({
|
const term = new Terminal({
|
||||||
cols: 120,
|
cols: 120,
|
||||||
rows: 30,
|
rows: 30,
|
||||||
fontFamily: "'Cascadia Mono', 'Consolas', 'Courier New', monospace",
|
fontFamily: "'Cascadia Mono', 'Consolas', 'Courier New', monospace",
|
||||||
fontSize: 14,
|
fontSize: 16,
|
||||||
theme: {
|
theme: {
|
||||||
background: '#1a1a2e',
|
background: '#1a1a2e',
|
||||||
foreground: '#e0e0e0',
|
foreground: '#e0e0e0',
|
||||||
|
|
@ -18,43 +17,47 @@ window.terminalInterop = {
|
||||||
},
|
},
|
||||||
cursorBlink: true,
|
cursorBlink: true,
|
||||||
allowProposedApi: true,
|
allowProposedApi: true,
|
||||||
scrollback: 1000
|
scrollback: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
const fitAddon = new FitAddon.FitAddon();
|
// Show terminal container BEFORE opening so xterm can measure
|
||||||
term.loadAddon(fitAddon);
|
|
||||||
|
|
||||||
// Show terminal container BEFORE opening so fitAddon can measure real dimensions
|
|
||||||
document.getElementById('loading').classList.add('hidden');
|
document.getElementById('loading').classList.add('hidden');
|
||||||
document.getElementById('terminal-container').classList.add('active');
|
document.getElementById('terminal-container').classList.add('active');
|
||||||
|
|
||||||
term.open(document.getElementById('terminal'));
|
term.open(document.getElementById('terminal'));
|
||||||
|
|
||||||
// Fit to container, enforce minimum dimensions for game readability
|
// Scale the terminal to fit the viewport while keeping exact 120x30
|
||||||
fitAddon.fit();
|
this._scaleToFit();
|
||||||
const minCols = 120, minRows = 30;
|
window.addEventListener('resize', () => this._scaleToFit());
|
||||||
if (term.cols < minCols || term.rows < minRows) {
|
|
||||||
term.resize(Math.max(term.cols, minCols), Math.max(term.rows, minRows));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward key input to C#
|
// Forward key input to C#
|
||||||
term.onData(function (data) {
|
term.onData(function (data) {
|
||||||
DotNet.invokeMethodAsync('OpenTheBox.Web', 'OnTerminalInput', data);
|
DotNet.invokeMethodAsync('OpenTheBox.Web', 'OnTerminalInput', data);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle resize
|
|
||||||
window.addEventListener('resize', function () {
|
|
||||||
fitAddon.fit();
|
|
||||||
if (term.cols < minCols || term.rows < minRows) {
|
|
||||||
term.resize(Math.max(term.cols, minCols), Math.max(term.rows, minRows));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.term = term;
|
this.term = term;
|
||||||
this.fitAddon = fitAddon;
|
|
||||||
term.focus();
|
term.focus();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_scaleToFit: function () {
|
||||||
|
const el = document.querySelector('#terminal .xterm-screen');
|
||||||
|
if (!el) return;
|
||||||
|
|
||||||
|
const container = document.getElementById('terminal-container');
|
||||||
|
const pad = 16; // padding around terminal
|
||||||
|
const maxW = container.clientWidth - pad;
|
||||||
|
const maxH = container.clientHeight - pad;
|
||||||
|
const termW = el.offsetWidth;
|
||||||
|
const termH = el.offsetHeight;
|
||||||
|
|
||||||
|
if (termW === 0 || termH === 0) return;
|
||||||
|
|
||||||
|
const scale = Math.min(1, maxW / termW, maxH / termH);
|
||||||
|
const wrapper = document.getElementById('terminal');
|
||||||
|
wrapper.style.transform = scale < 1 ? `scale(${scale})` : '';
|
||||||
|
wrapper.style.transformOrigin = 'center center';
|
||||||
|
},
|
||||||
|
|
||||||
write: function (text) {
|
write: function (text) {
|
||||||
if (this.term) {
|
if (this.term) {
|
||||||
this.term.write(text);
|
this.term.write(text);
|
||||||
|
|
@ -75,9 +78,6 @@ window.terminalInterop = {
|
||||||
},
|
},
|
||||||
|
|
||||||
getDimensions: function () {
|
getDimensions: function () {
|
||||||
if (this.term) {
|
|
||||||
return { cols: this.term.cols, rows: this.term.rows };
|
|
||||||
}
|
|
||||||
return { cols: 120, rows: 30 };
|
return { cols: 120, rows: 30 };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue