169 lines
4.7 KiB
Svelte
Executable File
169 lines
4.7 KiB
Svelte
Executable File
<script lang="ts">
|
|
import { Terminal, type PrintData } from '$lib/stores/terminal/terminal';
|
|
import { onMount } from 'svelte';
|
|
import Input from './terminal/Input.svelte';
|
|
import { initTerminal, isInitializing } from '$lib/stores/terminal/init.svelte';
|
|
import { clear, print } from '$lib/stores/terminal/stdio/io';
|
|
import type { User } from '$lib/stores/bash/etc/userData';
|
|
|
|
const clearTerminal = (): void => clear();
|
|
|
|
const printOutput = (e: HTMLElement, d: PrintData): void => print(e, d);
|
|
|
|
function updateTerminal() {
|
|
username = terminal!.getUser().username;
|
|
cwd = terminal!.getCwd();
|
|
}
|
|
|
|
function getWidth() {
|
|
const e = document.getElementById('cout');
|
|
if(!e){
|
|
throw new Error('cant get width of the teminal element. Its null');
|
|
}
|
|
//gets an int from padding property value (which is a string) by cutting last 2 letters "px" and parsing to int
|
|
const padding: number = parseInt(window.getComputedStyle(e, null).getPropertyValue('padding').slice(0, -2));
|
|
return e.clientWidth - (padding * 2);
|
|
}
|
|
|
|
function getFontSize() {
|
|
const e = document.getElementById('cout');
|
|
if(!e) {
|
|
throw new Error('cant get font size of the terminal element. its null');
|
|
}
|
|
|
|
const canvas = document.createElement('canvas');
|
|
const ctx = canvas.getContext('2d')!;
|
|
ctx.font = `${window.getComputedStyle(e, null).getPropertyValue('font-size')} 'JetBrains Mono', monospace;`;
|
|
return ctx.measureText('M').width;
|
|
}
|
|
|
|
function inputHandler(event: KeyboardEvent) {
|
|
switch (event.key) {
|
|
case 'Enter': {
|
|
terminal.executeCommand(inputValue);
|
|
updateTerminal();
|
|
break;
|
|
}
|
|
case 'ArrowRight': {
|
|
//TODO: Move cursor visually
|
|
}
|
|
case 'ArrowLeft': {
|
|
//TODO: Move cursor visually
|
|
}
|
|
case 'ArrowUp': {
|
|
//TODO: Make a traverse history function with up/down args
|
|
}
|
|
case 'ArrowDown': {
|
|
//TODO: Make a traverse history function with up/down args
|
|
}
|
|
}
|
|
|
|
const elem = document.getElementById('cout');
|
|
if(!elem){
|
|
throw new Error('cant scroll to bottom, element is null');
|
|
}
|
|
|
|
elem.scrollTop = elem.scrollHeight;
|
|
}
|
|
|
|
//Callback initializer
|
|
const callbackInit = {
|
|
print: (data: any) => {
|
|
const e = document.getElementById('outputWrapper');
|
|
if (!e) return;
|
|
printOutput(e, data);
|
|
},
|
|
clear: clearTerminal,
|
|
getWidth: getWidth,
|
|
getFontSize: getFontSize
|
|
};
|
|
|
|
//Test user with basic data so the bash can run
|
|
let testUser: User = {
|
|
username: 'kamil',
|
|
passwd: '123',
|
|
uid: 0,
|
|
gid: 0,
|
|
home: '/home/kamil',
|
|
history: []
|
|
};
|
|
|
|
//Empty terminal variable where the terminal class instance will be stored
|
|
let terminal: Terminal;
|
|
let username: string = $state(testUser.username);
|
|
let cwd: string = $state(testUser.home);
|
|
|
|
let inputValue = $state<string>('');
|
|
|
|
onMount(async () => {
|
|
try {
|
|
terminal = await initTerminal({ username: 'root', password: '123'}, callbackInit, 'en_US');
|
|
updateTerminal();
|
|
} catch (error) {
|
|
console.error('onMount trycatch failed', error);
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<label for="input" onkeydowncapture={(event) => inputHandler(event)} class="w-11/12">
|
|
<div id="terminal" class="terminal-window shadow-() h-full w-full rounded-md shadow-bg">
|
|
<div
|
|
class="terminal-bar flex h-9 w-full flex-row items-center rounded-t-md bg-bg-dark text-center font-terminal text-sm font-bold text-primary-dark light:bg-bg-dark-light light:text-primary-light"
|
|
>
|
|
<div class="dots-wrapper mx-2.5 flex h-full flex-row items-center justify-center gap-2.5">
|
|
<button class="size-2.5 cursor-pointer rounded-full p-0" title=""></button>
|
|
<button class="size-2.5 cursor-pointer rounded-full p-0" title=""></button>
|
|
<button class="size-2.5 cursor-pointer rounded-full p-0" title=""></button>
|
|
</div>
|
|
<div class=" flex mr-2 grow">
|
|
<h5>{username}</h5>
|
|
<!-- prettier-ignore -->
|
|
<h5 class=" mr-2">@terminal: </h5>
|
|
<h5>{cwd}</h5>
|
|
</div>
|
|
</div>
|
|
<div
|
|
class="inner-content scroll-hidden h-7/8 origin-top overflow-y-auto rounded-b-md bg-bg-light-dark p-4 text-text-dark shadow-subtle light:bg-bg-lighter-light light:text-text-light"
|
|
id="cout"
|
|
>
|
|
<div id="outputWrapper"></div>
|
|
<Input {cwd} bind:inputValue />
|
|
</div>
|
|
</div>
|
|
</label>
|
|
|
|
<style>
|
|
* {
|
|
transition: var(--transition-standard);
|
|
}
|
|
.dots-wrapper {
|
|
& > button {
|
|
border: none;
|
|
&:hover {
|
|
transform: translateY(-0.1rem);
|
|
}
|
|
&:active {
|
|
transform: translate(0);
|
|
}
|
|
&:nth-child(1) {
|
|
background-color: rgb(255, 0, 0);
|
|
&:active {
|
|
background-color: rgb(255, 100, 100);
|
|
}
|
|
}
|
|
&:nth-child(2) {
|
|
background-color: rgb(255, 165, 0);
|
|
&:active {
|
|
background-color: rgb(255, 215, 50);
|
|
}
|
|
}
|
|
&:nth-child(3) {
|
|
background-color: rgb(50, 205, 50);
|
|
&:active {
|
|
background-color: rgb(100, 255, 100);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|