feat: clear terminal button, cleanup styling

This commit is contained in:
Maarten van Heusden
2026-02-02 09:44:33 +01:00
parent f12000df52
commit 2995a28d5c
3 changed files with 35 additions and 16 deletions

View File

@@ -5,6 +5,8 @@ use tauri::State;
use crate::AppState;
use crate::steam::SteamDownload;
/* Parts of this file are derived from https://github.com/cablehead/tauri-xtermjs-nushell/blob/0bdd4a27ee2874de12e99bccd6c91d6ec5d28fbc/src-tauri/src/main.rs */
#[tauri::command]
pub async fn async_write_to_pty(data: &str, state: State<'_, AppState>) -> Result<(), ()> {
write!(state.writer.lock().await, "{}", data).map_err(|_| ())
@@ -18,7 +20,7 @@ pub async fn async_read_from_pty(state: State<'_, AppState>) -> Result<Option<St
let data = reader.fill_buf().map_err(|_| ())?;
// Send the data to the webview if necessary
if data.len() > 0 {
if !data.is_empty() {
std::str::from_utf8(data)
.map(|v| Some(v.to_string()))
.map_err(|_| ())?
@@ -64,14 +66,14 @@ pub fn create_depotdownloader_command(steam_download: &SteamDownload, cwd: &Path
command.cwd(cwd);
if !steam_download.is_anonymous() {
command.args(["-username", &*steam_download.username().clone().unwrap()]);
command.args(["-password", &*steam_download.password().clone().unwrap()]);
command.args(["-username", &steam_download.username().clone().unwrap()]);
command.args(["-password", &steam_download.password().clone().unwrap()]);
}
command.args(["-app", &*steam_download.app_id()]);
command.args(["-depot", &*steam_download.depot_id()]);
command.args(["-manifest", &*steam_download.manifest_id()]);
command.args(["-dir", &*steam_download.output_path()]);
command.args(["-app", steam_download.app_id()]);
command.args(["-depot", steam_download.depot_id()]);
command.args(["-manifest", steam_download.manifest_id()]);
command.args(["-dir", &steam_download.output_path()]);
command
}

View File

@@ -17,7 +17,7 @@
<body class="select-none">
<div class="f1-light text-center mb-1">Steam Depot Downloader</div>
<div class="flex justify-between gap-2 w-svw flex-row">
<div class="w-1/2 h-full">
<div class="w-1/2 h-full" id="left-side">
<div class="mx-auto">
<form id="theform">
<div class="form-group mx-3 mt-1">
@@ -159,10 +159,15 @@
</div>
</div>
</div>
<div class="w-1/2 h-full px-2">
<div class="w-1/2 h-full px-2" id="right-side">
<div class="mt-2 h-full w-full mx-auto">
<div class="border border-gray-300 rounded-md bg-gray-900 text-white shadow shadow-blue-200">
<span class="text-md font-semibold block text-center">Download output</span>
<div class="text-md font-semibold w-full inline-flex my-px items-center">
<span class="text-center w-full">Download output</span>
<button id="clear-terminal" class="disabled:pointer-events-none disabled:line-through disabled:text-gray-300 ml-auto py-px px-2 border-2 rounded-xs border-red-500/75 font-normal enabled:hover:bg-red-200/30 enabled:active:bg-red-200/50">
Clear
</button>
</div>
<div class="max-h-[70vh]" id="xtermjs"></div>
</div>
<div class="mt-3 justify-between flex flex-row gap-3">

View File

@@ -7,8 +7,10 @@ import {Terminal} from "@xterm/xterm";
import { FitAddon } from "@xterm/addon-fit";
import { listen } from "@tauri-apps/api/event";
function setLoader(state: boolean) {
$("#busy").prop("hidden", !state);
/* Parts of this file are derived from https://github.com/cablehead/tauri-xtermjs-nushell/blob/0bdd4a27ee2874de12e99bccd6c91d6ec5d28fbc/src/main.ts */
function blockTerminalClearButton(state: boolean) {
$("#clear-terminal").prop( "disabled", state );
}
@@ -16,8 +18,9 @@ function setLoadingState(state: boolean) {
$("#busy").prop("hidden", !state);
// loop through all buttons and input fields and disable them
for (const element of document.querySelectorAll("button, input")) {
for (const element of document.querySelectorAll("button, input, div[role='button']")) {
if (element.closest("#settings-content")) continue;
if (element.closest("#right-side")) continue;
(element as any).disabled = state;
}
@@ -49,7 +52,7 @@ const invalidFields = () => {
return invalidFields;
};
const registerTerminal = async (terminalElement: HTMLElement) => {
const registerTerminal: (terminalElement: HTMLElement) => Promise<Terminal> = async (terminalElement: HTMLElement) => {
const fitAddon = new FitAddon();
const term = new Terminal({
fontSize: 10,
@@ -57,7 +60,7 @@ const registerTerminal = async (terminalElement: HTMLElement) => {
rows: 100,
cols: 100,
theme: {
background: "rgb(47, 47, 47)",
background: "rgb(33, 33, 33)",
},
});
term.loadAddon(fitAddon);
@@ -97,11 +100,13 @@ const registerTerminal = async (terminalElement: HTMLElement) => {
}
window.requestAnimationFrame(readFromPty);
return term;
};
$(async () => {
await registerTerminal($("#xtermjs")[0]);
let terminal = await registerTerminal($("#xtermjs")[0]);
let downloadDirectory: string | null;
// Startup logic
@@ -109,6 +114,9 @@ $(async () => {
await invoke("preload_vectum");
setLoadingState(false);
$("#clear-terminal").on("click", async () => {
terminal.reset()
})
$("#pickpath").on("click", async () => {
// Open a dialog
@@ -196,6 +204,9 @@ $(async () => {
setLoadingState(true);
await invoke("start_download", {steamDownload: steamDownload});
// Block clear terminal button (to avoid clearing ongoing download logs)
blockTerminalClearButton(true);
console.log("Send frontend data over to backend. Ready for next download.");
});
@@ -230,4 +241,5 @@ $(async () => {
listen<string>("command-exited", () => {
setLoadingState(false);
blockTerminalClearButton(false);
});