Skip to content
Snippets Groups Projects
Commit b0c978d7 authored by ali asaria's avatar ali asaria
Browse files

improve look of xterm at bottom of screen

parent 38dd9f69
No related branches found
No related tags found
No related merge requests found
import { Box, Sheet } from '@mui/joy'; import { Box, Sheet } from '@mui/joy';
import { FitAddon } from '@xterm/addon-fit'; import { FitAddon } from '@xterm/addon-fit';
import { Terminal } from '@xterm/xterm'; import { Terminal } from '@xterm/xterm';
import { useEffect, useRef } from 'react'; import { useEffect, useRef, useState } from 'react';
import useSWRSubscription from 'swr/subscription';
import type { SWRSubscriptionOptions } from 'swr/subscription';
const TERMINAL_SPEED = 100; //ms between adding each line (create an animation effect)
export default function OutputTerminal({}) { export default function OutputTerminal({}) {
const terminalRef = useRef(null); const terminalRef = useRef(null);
let term: Terminal | null = null; let term: Terminal | null = null;
let lineQueue: string[] = [];
let isProcessing = false;
const fitAddon = new FitAddon(); const fitAddon = new FitAddon();
...@@ -13,31 +20,35 @@ export default function OutputTerminal({}) { ...@@ -13,31 +20,35 @@ export default function OutputTerminal({}) {
fitAddon.fit(); fitAddon.fit();
} }
useEffect(() => { function processQueue() {
// This is hardcoded to local for now -- just building if (lineQueue.length === 0) {
var source = new EventSource('http://localhost:8338/server/stream_log'); isProcessing = false;
source.onmessage = function (event) { return;
// console.log(event.data); }
// var logs = document.getElementById('logs');
// logs.innerHTML += event.data + '<br>';
// // Scroll to bottom
// logs.scrollTop = document.getElementById('logs').scrollHeight;
if (term !== null) { isProcessing = true;
console.log(event.data); const line = lineQueue.shift()!;
const lines = JSON.parse(event.data); term?.writeln(line.replace(/\n$/, ''));
console.log(lines); if (terminalRef.current) {
lines.forEach((line: string) => { terminalRef.current.scrollIntoView({ behavior: 'smooth' });
term.writeln(line); }
if (terminalRef.current) {
terminalRef.current.scrollIntoView({ behavior: 'smooth' }); setTimeout(() => {
} processQueue();
}); }, TERMINAL_SPEED); // 100ms delay between each line
} }
window.addEventListener('resize', handleResize);
}; function addLinesOneByOne(lines: string[]) {
lineQueue = lineQueue.concat(lines);
if (!isProcessing) {
processQueue();
}
}
term = new Terminal(); useEffect(() => {
term = new Terminal({
smoothScrollDuration: 200, // Set smooth scroll duration to 200ms
});
term.loadAddon(fitAddon); term.loadAddon(fitAddon);
if (terminalRef.current) term.open(terminalRef.current); if (terminalRef.current) term.open(terminalRef.current);
...@@ -45,22 +56,43 @@ export default function OutputTerminal({}) { ...@@ -45,22 +56,43 @@ export default function OutputTerminal({}) {
window.addEventListener('resize', handleResize); window.addEventListener('resize', handleResize);
const eventSource = new EventSource(
'http://localhost:8338/server/stream_log'
);
eventSource.onmessage = (event) => {
if (term !== null) {
const lines = JSON.parse(event.data);
addLinesOneByOne(lines);
}
};
eventSource.onerror = (error) => {
console.error('EventSource failed:', error);
};
return () => { return () => {
eventSource.close();
term?.dispose(); term?.dispose();
source.close();
window.removeEventListener('resize', handleResize); window.removeEventListener('resize', handleResize);
}; };
}); });
return ( return (
<Box sx={{ height: '100%', overflow: 'hidden' }}> <Box
sx={{
gridArea: 'footer',
height: '100%',
overflow: 'hidden',
border: '10px solid #444',
padding: '6px',
backgroundColor: '#000',
}}
>
<Sheet <Sheet
sx={{ sx={{
gridArea: 'terminal',
height: '100%',
overflow: 'auto', overflow: 'auto',
backgroundColor: '#222', backgroundColor: '#000',
// color: 'white', color: '#aaa',
height: '100%',
}} }}
ref={terminalRef} ref={terminalRef}
></Sheet> ></Sheet>
......
...@@ -187,4 +187,12 @@ textarea { ...@@ -187,4 +187,12 @@ textarea {
font-family: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI"; font-family: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI";
font-size: 16px; font-size: 16px;
padding: 16px; padding: 16px;
}
.xterm-viewport::-webkit-scrollbar {
background-color: var(--joy-palette-background-level-1);
}
.xterm-viewport::-webkit-scrollbar-thumb {
background: var(--joy-palette-primary-400);
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment