mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Improve demo by making full screen, add control bar
This commit is contained in:
@@ -19,6 +19,7 @@ if ('WebAssembly' in window) {
|
||||
|
||||
import { Terminal, ITerminalOptions, type IDisposable, type ITheme } from '@xterm/xterm';
|
||||
import { AttachAddon } from '@xterm/addon-attach';
|
||||
import { initControlBar } from './components/controlBar';
|
||||
import { ClipboardAddon } from '@xterm/addon-clipboard';
|
||||
import { FitAddon } from '@xterm/addon-fit';
|
||||
import { LigaturesAddon } from '@xterm/addon-ligatures';
|
||||
@@ -231,6 +232,7 @@ if (document.location.pathname === '/test') {
|
||||
window.WebglAddon = WebglAddon;
|
||||
} else {
|
||||
createTerminal();
|
||||
initControlBar();
|
||||
document.getElementById('dispose').addEventListener('click', disposeRecreateButtonHandler);
|
||||
document.getElementById('create-new-window').addEventListener('click', createNewWindowButtonHandler);
|
||||
document.getElementById('serialize').addEventListener('click', serializeButtonHandler);
|
||||
@@ -337,6 +339,7 @@ function createTerminal(): void {
|
||||
}
|
||||
|
||||
term.focus();
|
||||
updateTerminalContainerBackground();
|
||||
|
||||
const resizeObserver = new ResizeObserver(entries => {
|
||||
if (autoResize) {
|
||||
@@ -611,10 +614,18 @@ function initOptions(term: Terminal): void {
|
||||
}
|
||||
}
|
||||
term.options[o] = value;
|
||||
if (o === 'theme') {
|
||||
updateTerminalContainerBackground();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function updateTerminalContainerBackground(): void {
|
||||
const bg = term.options.theme?.background ?? '#000000';
|
||||
terminalContainer.style.backgroundColor = bg;
|
||||
}
|
||||
|
||||
function initAddons(term: Terminal): void {
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
export function initControlBar(): void {
|
||||
// Sidebar resize handling
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const resizeHandleH = document.getElementById('sidebar-resize-handle-horizontal');
|
||||
const resizeHandleV = document.getElementById('sidebar-resize-handle-vertical');
|
||||
const resizeHandleCorner = document.getElementById('sidebar-resize-handle-corner');
|
||||
let resizeMode: 'none' | 'horizontal' | 'vertical' | 'corner' = 'none';
|
||||
|
||||
function startResize(mode: 'horizontal' | 'vertical' | 'corner', e: MouseEvent): void {
|
||||
resizeMode = mode;
|
||||
document.body.style.cursor = mode === 'horizontal' ? 'ew-resize' : mode === 'vertical' ? 'ns-resize' : 'nesw-resize';
|
||||
document.body.style.userSelect = 'none';
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
resizeHandleH.addEventListener('mousedown', (e: MouseEvent) => startResize('horizontal', e));
|
||||
resizeHandleV.addEventListener('mousedown', (e: MouseEvent) => startResize('vertical', e));
|
||||
resizeHandleCorner.addEventListener('mousedown', (e: MouseEvent) => startResize('corner', e));
|
||||
|
||||
document.addEventListener('mousemove', (e: MouseEvent) => {
|
||||
if (resizeMode === 'none') return;
|
||||
if (resizeMode === 'horizontal' || resizeMode === 'corner') {
|
||||
const newWidth = window.innerWidth - e.clientX - 10;
|
||||
sidebar.style.width = `${Math.max(200, newWidth)}px`;
|
||||
}
|
||||
if (resizeMode === 'vertical' || resizeMode === 'corner') {
|
||||
const rect = sidebar.getBoundingClientRect();
|
||||
const newHeight = e.clientY - rect.top;
|
||||
sidebar.style.height = `${Math.max(100, newHeight)}px`;
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('mouseup', () => {
|
||||
resizeMode = 'none';
|
||||
document.body.style.cursor = '';
|
||||
document.body.style.userSelect = '';
|
||||
});
|
||||
}
|
||||
+33
-15
@@ -12,19 +12,25 @@
|
||||
<link rel="stylesheet" href="/style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="color: #2D2E2C">xterm.js: A terminal for the <em style="color: #5DA5D5">web</em></h1>
|
||||
<div id="banner">
|
||||
<span class="banner-title">xterm.js</span>
|
||||
<div class="banner-tabs">
|
||||
<button id="optionsbutton" class="tabLinks" onclick="openSection(event, 'options')">Options</button>
|
||||
<button id="addonsbutton" class="tabLinks" onclick="openSection(event, 'addons')">Addons</button>
|
||||
<button id="stylebutton" class="tabLinks" onclick="openSection(event, 'style')">Style</button>
|
||||
<button id="testbutton" class="tabLinks" onclick="openSection(event, 'test')">Test</button>
|
||||
<button id="vtbutton" class="tabLinks" onclick="openSection(event, 'vt')">VT</button>
|
||||
<button id="gpubutton" class="tabLinks" onclick="openSection(event, 'gpu')">GPU</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container">
|
||||
<div class="grid">
|
||||
<div id="terminal-container"></div>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div class="tab">
|
||||
<button id="optionsbutton" class="tabLinks" onclick="openSection(event, 'options')">Options</button>
|
||||
<button id="addonsbutton" class="tabLinks" onclick="openSection(event, 'addons')">Addons</button>
|
||||
<button id="stylebutton" class="tabLinks" onclick="openSection(event, 'style')">Style</button>
|
||||
<button id="testbutton" class="tabLinks" onclick="openSection(event, 'test')">Test</button>
|
||||
<button id="vtbutton" class="tabLinks" onclick="openSection(event, 'vt')">VT</button>
|
||||
</div>
|
||||
<div id="sidebar" class="grid">
|
||||
<div id="sidebar-resize-handle-horizontal"></div>
|
||||
<div id="sidebar-resize-handle-vertical"></div>
|
||||
<div id="sidebar-resize-handle-corner"></div>
|
||||
<div id="options" class="tabContent">
|
||||
<h3>Options</h3>
|
||||
<p>These options can be set in the <code>Terminal</code> constructor or by using the <code>Terminal.options</code> property.</p>
|
||||
@@ -169,12 +175,13 @@
|
||||
<h3>VT</h3>
|
||||
<div id="vt-container"></div>
|
||||
</div>
|
||||
<div id="gpu" class="tabContent">
|
||||
<h3>GPU</h3>
|
||||
<input type="checkbox" id="texture-atlas-zoom"/>
|
||||
<label for="texture-atlas-zoom">Zoom texture atlas</label>
|
||||
<div id="texture-atlas"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="texture-atlas-container">
|
||||
<input type="checkbox" id="texture-atlas-zoom"/>
|
||||
<label for="texture-atlas-zoom">Zoom texture atlas</label>
|
||||
<div id="texture-atlas"></div>
|
||||
</div>
|
||||
<script src="dist/client-bundle.js" defer ></script>
|
||||
<script>
|
||||
@@ -194,12 +201,23 @@
|
||||
document.getElementById(""+tab+"button").classList.add("active");
|
||||
}
|
||||
function openSection(event, section) {
|
||||
const sidebar = document.getElementById("sidebar");
|
||||
const tabContent = document.getElementsByClassName("tabContent");
|
||||
const tabLinks = document.getElementsByClassName("tabLinks");
|
||||
let itr;
|
||||
|
||||
// If clicking active tab, toggle sidebar visibility
|
||||
if (event.currentTarget.classList.contains("active")) {
|
||||
sidebar.classList.toggle("sidebar-hidden");
|
||||
return;
|
||||
}
|
||||
|
||||
// Show sidebar if hidden
|
||||
sidebar.classList.remove("sidebar-hidden");
|
||||
|
||||
for (itr = 0; itr < tabContent.length; itr+=1) {
|
||||
tabContent[itr].style.display = "none";
|
||||
}
|
||||
const tabLinks = document.getElementsByClassName("tabLinks");
|
||||
for (itr = 0; itr < tabLinks.length; itr+=1) {
|
||||
tabLinks[itr].className = tabLinks[itr].className.replace(" active", "");
|
||||
}
|
||||
|
||||
+97
-29
@@ -2,16 +2,50 @@ body {
|
||||
font-family: helvetica, sans-serif, arial;
|
||||
font-size: 1em;
|
||||
color: #111;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100vh;
|
||||
display: grid;
|
||||
grid-template-rows: 24px 1fr;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
/* Top banner */
|
||||
#banner {
|
||||
background: #2D2E2C;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 10px;
|
||||
border-bottom: 1px solid #0005;
|
||||
}
|
||||
.banner-title {
|
||||
color: #5DA5D5;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
}
|
||||
.banner-tabs {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
}
|
||||
.banner-tabs button {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #ccc;
|
||||
padding: 4px 10px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
}
|
||||
.banner-tabs button:hover {
|
||||
background: rgba(255,255,255,0.1);
|
||||
}
|
||||
.banner-tabs button.active {
|
||||
background: rgba(255,255,255,0.2);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#terminal-container {
|
||||
height: 60%;
|
||||
margin: 0 auto;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
p {
|
||||
@@ -44,45 +78,79 @@ pre {
|
||||
|
||||
#container {
|
||||
display: flex;
|
||||
position: relative;
|
||||
min-height: 0;
|
||||
}
|
||||
.grid {
|
||||
flex: 1;
|
||||
/* max-height: 80vh;
|
||||
overflow-y: auto; */
|
||||
width: 100%;
|
||||
min-width: 100px;
|
||||
}
|
||||
div:first-of-type.grid {
|
||||
flex: 2;
|
||||
height: 60vh;
|
||||
height: 100%;
|
||||
}
|
||||
.tab {
|
||||
overflow: hidden;
|
||||
|
||||
/* Sidebar */
|
||||
#sidebar {
|
||||
position: fixed;
|
||||
top: 24px;
|
||||
right: 0;
|
||||
width: 400px;
|
||||
height: 500px;
|
||||
background: #fff;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #f1f1f1;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
|
||||
z-index: 1000;
|
||||
overflow: auto;
|
||||
flex: none;
|
||||
opacity: 0.5;
|
||||
transition: opacity 0.1s;
|
||||
}
|
||||
#sidebar:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
#sidebar.sidebar-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Style the buttons inside the tab */
|
||||
.tab button {
|
||||
background-color: inherit;
|
||||
float: left;
|
||||
border: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
padding: 14px 16px;
|
||||
transition: 0.3s;
|
||||
font-size: 17px;
|
||||
/* Resize handles */
|
||||
#sidebar-resize-handle-horizontal {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 6px;
|
||||
cursor: ew-resize;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Change background color of buttons on hover */
|
||||
.tab button:hover {
|
||||
background-color: #ddd;
|
||||
#sidebar-resize-handle-horizontal:hover {
|
||||
background: rgba(0, 120, 212, 0.3);
|
||||
}
|
||||
#sidebar-resize-handle-vertical {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 6px;
|
||||
cursor: ns-resize;
|
||||
background: transparent;
|
||||
}
|
||||
#sidebar-resize-handle-vertical:hover {
|
||||
background: rgba(0, 120, 212, 0.3);
|
||||
}
|
||||
#sidebar-resize-handle-corner {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
cursor: nesw-resize;
|
||||
background: transparent;
|
||||
}
|
||||
#sidebar-resize-handle-corner:hover {
|
||||
background: rgba(0, 120, 212, 0.5);
|
||||
}
|
||||
|
||||
/* Create an active/current tablink class */
|
||||
.tab button.active {
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
/* Style the tab content */
|
||||
.tabContent {
|
||||
@@ -92,7 +160,7 @@ div:first-of-type.grid {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
#texture-atlas-zoom:checked + label + #texture-atlas canvas {
|
||||
#texture-atlas-zoom:checked ~ #texture-atlas canvas {
|
||||
/* Zoom atlas to the width of the container*/
|
||||
width: 100% !important;
|
||||
height: auto !important;
|
||||
|
||||
Reference in New Issue
Block a user