From 6738c964006ab59247c08339c9b51b6cfca07bed Mon Sep 17 00:00:00 2001 From: Thomas Farstrike Date: Tue, 24 Mar 2026 11:06:58 +0100 Subject: [PATCH] Beautify WebREPL --- webrepl/webrepl.css | 139 ++++++++++++++++++++++++++++++++++++-- webrepl/webrepl.html | 4 +- webrepl/webrepl_tweaks.js | 91 +++++++++++++++++++++++++ 3 files changed, 227 insertions(+), 7 deletions(-) create mode 100644 webrepl/webrepl_tweaks.js diff --git a/webrepl/webrepl.css b/webrepl/webrepl.css index e723c7bb..35515404 100644 --- a/webrepl/webrepl.css +++ b/webrepl/webrepl.css @@ -1,13 +1,140 @@ +:root { + color-scheme: light; + --bg: #ffffff; + --panel: #f6f7f9; + --panel-border: #e1e5ea; + --text: #1c1f24; + --muted: #5c6572; + --accent: #f0a010; + --accent-hover: #e08f00; + --accent-active: #cc7f00; + --shadow: 0 10px 30px rgba(19, 27, 43, 0.08); + --radius: 12px; + --focus-ring: 0 0 0 3px rgba(240, 160, 16, 0.3); +} + +* { + box-sizing: border-box; +} + html { - background: #555; + background: var(--bg); +} + +body { + margin: 0; + padding: 24px 28px 32px; + font: 16px/1.6 "Inter", "Segoe UI", "Helvetica Neue", Arial, sans-serif; + color: var(--text); + background: var(--bg); } h1 { - margin-bottom: 20px; - font: 20px/1.5 sans-serif; + margin: 0 0 20px; + font: 600 24px/1.3 "Inter", "Segoe UI", "Helvetica Neue", Arial, sans-serif; + color: var(--text); } + +form { + display: flex; + flex-wrap: wrap; + gap: 12px; + align-items: center; + margin-bottom: 16px; +} + +/* Fixed-height wrapper keeps the terminal footprint stable; rows are computed from this height. */ +#term-wrapper { + height: 420px; +} + +/* Terminal fills the wrapper; row count is recalculated on load/resize only. */ +#term { + height: 100%; + border-radius: var(--radius); + border: 1px solid var(--panel-border); + background: #0f141b; + color: #f1f5f9; + padding: 8px; + box-shadow: var(--shadow); + overflow: hidden; +} + +#file-boxes { + margin-left: 20px; +} + .file-box { - margin: 4px; - padding: 4px; - background: #888; + margin: 0 0 16px; + padding: 14px 16px 16px; + background: var(--panel); + border: 1px solid var(--panel-border); + border-radius: var(--radius); + box-shadow: var(--shadow); + display: grid; + gap: 10px; +} + +.file-box strong { + font-size: 15px; +} + +#file-status { + color: var(--muted); + font-size: 14px; +} + +input[type="text"], +input[type="file"] { + width: 100%; + padding: 10px 12px; + border-radius: 10px; + border: 1px solid var(--panel-border); + background: #ffffff; + color: var(--text); + font-size: 14px; +} + +input[type="text"]:focus, +input[type="file"]:focus { + outline: none; + border-color: var(--accent); + box-shadow: var(--focus-ring); +} + +input[type="submit"], +input[type="button"] { + padding: 10px 16px; + border-radius: 999px; + border: none; + background: var(--accent); + color: #1a1200; + font-weight: 600; + font-size: 14px; + cursor: pointer; + transition: transform 0.08s ease, background 0.15s ease, box-shadow 0.15s ease; + box-shadow: 0 8px 18px rgba(240, 160, 16, 0.35); +} + +input[type="submit"]:hover, +input[type="button"]:hover { + background: var(--accent-hover); + transform: translateY(-1px); +} + +input[type="submit"]:active, +input[type="button"]:active { + background: var(--accent-active); + transform: translateY(0); +} + +input[type="submit"]:focus, +input[type="button"]:focus { + outline: none; + box-shadow: var(--focus-ring); +} + +i { + color: var(--muted); + font-size: 13px; } diff --git a/webrepl/webrepl.html b/webrepl/webrepl.html index 226a0e74..6aa7e6a7 100644 --- a/webrepl/webrepl.html +++ b/webrepl/webrepl.html @@ -13,7 +13,8 @@ -
+
+
@@ -42,5 +43,6 @@ + diff --git a/webrepl/webrepl_tweaks.js b/webrepl/webrepl_tweaks.js new file mode 100644 index 00000000..28f39d3e --- /dev/null +++ b/webrepl/webrepl_tweaks.js @@ -0,0 +1,91 @@ +// Set terminal height dynamically, without modifying webrepl.js +(function() { + var maxReadyAttempts = 90; + var readyAttempts = 0; + var resizeScheduled = false; + var resizeDebounce = null; + + function get_term_container() { + return document.getElementById('term'); + } + + // Wrapper keeps a fixed height; rows are derived from its rendered height. + function get_term_wrapper() { + return document.getElementById('term-wrapper') || get_term_container(); + } + + // Compute rows once on load/resize using wrapper height and terminal padding. + function calculate_dynamic_rows() { + var wrapper = get_term_wrapper(); + var termContainer = get_term_container(); + if (!wrapper || !termContainer) { + return null; + } + var rect = wrapper.getBoundingClientRect(); + var height = rect.height || wrapper.clientHeight || window.innerHeight; + var style = window.getComputedStyle(termContainer); + var paddingTop = parseFloat(style.paddingTop) || 0; + var paddingBottom = parseFloat(style.paddingBottom) || 0; + var contentHeight = height - paddingTop - paddingBottom; + return Math.max(24, Math.min(80, (contentHeight - 20) / 12)) | 0; + } + + function resize_term_rows() { + if (!window.term || !window.term.resize) { + return false; + } + var rows = calculate_dynamic_rows(); + if (rows === null) { + return false; + } + var cols = window.term.cols || 80; + if (window.term.rows !== rows) { + window.term.resize(cols, rows); + } + return true; + } + + function schedule_resize() { + if (resizeScheduled) { + return; + } + resizeScheduled = true; + window.requestAnimationFrame(function() { + resizeScheduled = false; + resize_term_rows(); + }); + } + + function schedule_resize_debounced() { + if (resizeDebounce) { + window.clearTimeout(resizeDebounce); + } + resizeDebounce = window.setTimeout(function() { + resizeDebounce = null; + schedule_resize(); + }, 80); + } + + function wait_for_term_ready() { + if (window.term && window.term.resize) { + schedule_resize_debounced(); + if (resize_term_rows()) { + return; + } + } + if (readyAttempts >= maxReadyAttempts) { + return; + } + readyAttempts += 1; + window.requestAnimationFrame(wait_for_term_ready); + } + + window.addEventListener('load', function() { + wait_for_term_ready(); + schedule_resize_debounced(); + }); + + window.addEventListener('resize', function() { + schedule_resize_debounced(); + }); +}).call(this);