Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"devDependencies": true
}
],
"import/unambiguous": "off"
"import/unambiguous": "off",
"no-bitwise": ["error", { "allow": ["~", "&", "|"] }]
},
"settings": {
"import/resolver": {
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -808,3 +808,5 @@ FodyWeavers.xsd
# Additional files built by Visual Studio

# End of https://www.toptal.com/developers/gitignore/api/visualstudio,visualstudiocode,eclipse,intellij,webstorm,node
.idea
*.iso
214 changes: 103 additions & 111 deletions bun.lock

Large diffs are not rendered by default.

137 changes: 85 additions & 52 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,74 +1,107 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- SEO and Meta Tags -->
<title>BitBox - Browser VM</title>
<meta name="title" content="BitBox - Browser VM" />
<meta name="email" content="daipham.3213@gmail.com" />
<meta name="author" content="Dai Pham" />
<meta name="description" content="BitBox - Browser VM" />
<meta name="keywords" content="BitBox, Browser VM, Virtual Machine, WebAssembly, V86, x86, WASM/WASI" />
<meta name="description"
content="A modern, flat, and responsive static web page mimicking a macOS-style terminal UI, built with HTML and custom CSS." />
<meta name="keywords"
content="BitBox, Browser VM, Virtual Machine, WebAssembly, V86, x86, WASM/WASI, Terminal, UI, Frontend, Developer, Portfolio" />
<meta name="github" content="https://github.com/daipham3213">
<meta name="opendev.org" content="https://review.opendev.org/q/owner:daipham.3213@gmail.com">
<meta name="linkedin" content="www.linkedin.com/in/daipham-3213">
<link rel="icon" href="/favico.svg" type="image/png" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Language" content="en" />

<!-- Custom Stylesheet -->
<style>
@import "src/styles/app.css";
@import "/static/css/app.css";
</style>
<title>BitBox - Browser VM</title>

<!-- Google Fonts: Space Mono -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap" rel="stylesheet">

</head>

<body>
<div id="terminal-container">
<div id="terminal-toolbar">
<span class="toolbar-title">BitBox</span>
<span id="emulator-state" class="toolbar-state"></span>
<div id="toolbar-buttons" class="toolbar-buttons">
<a class="toolbar-button" href="https://github.com/daipham3213" _target="_blank" rel="noopener noreferrer">
<img class="botton-img" id="github" alt="GitHub - daipham3213" src="/img/github.svg" width="16" height="16" />
</a>
<a class="toolbar-button" href="https://review.opendev.org/q/owner:daipham.3213@gmail.com" _target="_blank"
rel="noopener noreferrer">
<img class="button-img" id="opendev" alt="OpenDev - daipham.3213@gmail.com" src="/img/opendev.svg" width="16"
height="16" />
</a>
<a class="toolbar-button" href="https://www.linkedin.com/in/daipham-3213" _target="_blank"
rel="noopener noreferrer">
<img class="button-img" id="linkedin" alt="LinkedIn - daipham-3213" src="/img/linkedin.svg" width="16"
height="16" />
</a>
<button id="upload-button" class="toolbar-button upload-button" title="Upload File">
<img class="button-img" id="upload" alt="Upload File" src="/img/upload.svg" width="16" height="16" />
</button>
<body class="l-body">

<div class="m-terminal-window">

<header class="m-title-bar">
<div class="m-title-bar__buttons">
<div class="m-title-bar__button m-title-bar__button--close">
<svg class="m-title-bar__button-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M6 18L18 6M6 6l12 12"></path>
</svg>
</div>
<div class="m-title-bar__button m-title-bar__button--minimize">
<svg class="m-title-bar__button-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M20 12H4"></path>
</svg>
</div>
<div class="m-title-bar__button m-title-bar__button--maximize">
<svg class="m-title-bar__button-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3"
d="M4 8V4h4m12 0h-4v4m0 8v4h-4M4 16v4h4"></path>
</svg>
</div>
</div>
</div>
<div id="terminal"></div>
<div id="serial">
<div id="serial-output">
<h6>Loading resources, please wait...</h6>
<div class="m-title-bar__text">BitBox &mdash; Browser VM</div>
</header>

<main class="m-terminal-content" id="terminal-main-content">
<div id="terminal" class="terminal"></div>
<div id="serial" class="serial">
<div id="serial-output" class="serial-output">
<h6>Loading resources, please wait...</h6>
</div>
<canvas id="serial-canvas" width="800" height="600"></canvas>
</div>
<canvas id="serial-canvas" width="800" height="600"></canvas>
</div>
</div>
<div id="modal-overlay">
<div id="upload-modal">
<button id="modal-close-button" title="Close">&times;</button>
<h3>Upload File</h3>
<div class="form-group">
<p> All files will be uploaded to `/home/daiplg` directory. </p>
</main>

<footer class="m-footer-stats">

<div id="progress-bar" class="m-footer-stats__item">
<div class="m-footer-stats__text-row">
<span>STATE</span>
<span id="emulator-state">loading...</span>
</div>
<div class="m-progress-bar">
<div id="emulator-state-progress" class="m-progress-bar__fill m-progress-bar__fill--disk" style="width: 0;">
</div>
</div>
</div>
<div class="form-group">
<button id="select-file-button">Select File...</button>
<input type="file" id="file-input" style="display: none;" multiple>
<span id="selected-filename">No file selected</span>

<div class="m-footer-stats__item m-footer-stats__item--network is-stats-hidden">
<span id="emulator-uptime">🟢 0s</span>
<span> ╎ </span>
<span id="emulator-nw-down" class="m-footer-stats__network-speed">▼ 0B/s</span>
<span id="emulator-nw-up" class="m-footer-stats__network-speed">▲ 0B/s</span>
<span> ╎ </span>
<div class="m-tooltip">
<div class="m-file-input o-spinning-border o-shadow">
<input id="emulator-9p-files-send-btn" class="m-file-input__input" type="file" multiple />
<label for="emulator-9p-files-send-btn" class="m-file-input__label">📂</label>
</div>
<span class="m-tooltip__text">Upload File</span>
</div>
</div>
</div>

</footer>

</div>

<!-- Custom JavaScript Modules -->
<script src="/v86/libv86.js"></script>
<script type="module" src="/src/js/main.js"></script>
<script type="module" src="/src/main.js"></script>

</body>

</html>
9 changes: 9 additions & 0 deletions public/static/css/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* libraries css */
@import '@xterm/xterm/css/xterm.css';

/* app css */
@import "base/_base.css";
@import "layout/_layout.css";
@import "modules/_modules.css";
@import "state/_state.css";
@import "theme/_theme.css";
22 changes: 22 additions & 0 deletions public/static/css/base/_base.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* Base styles: Resets, typography, and foundational elements */
html {
box-sizing: border-box;
font-size: 16px;
}

*, *::before, *::after {
box-sizing: inherit;
}

body {
margin: 0;
padding: 0;
font-family: 'Consolas', monospace;
background: #1e1e1e;
}

/* Base link styles, if any */
a {
text-decoration: none;
color: inherit;
}
8 changes: 8 additions & 0 deletions public/static/css/layout/_layout.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/* Layout styles: High-level page structure and responsiveness */
.l-body {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: 1rem;
}
9 changes: 9 additions & 0 deletions public/static/css/modules/_modules.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@import "footer-stats.css";
@import "progress-bar.css";
@import "terminal-window.css";
@import "terminal-content.css";
@import "title-bar.css";
@import "app-xterm.css";
@import "tooltip.css";
@import "button.css";
@import "file-input.css";
33 changes: 33 additions & 0 deletions public/static/css/modules/app-xterm.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* xterm.js specific overrides for theme integration */
.xterm {
height: 100%;
width: 100%;
padding: 0.25rem; /* Adjust padding to fit terminal content */
}

.xterm-viewport {
background-color: #282C34; /* Ensure background matches terminal window */
}

.xterm .xterm-rows {
font-family: 'Consolas', monospace;
color: #ABB2BF;
}

.xterm .xterm-cursor-block {
background-color: #ABB2BF;
}

.xterm-viewport::-webkit-scrollbar {
width: 8px;
}

.xterm-viewport::-webkit-scrollbar-track {
background: #333;
}

.xterm-viewport::-webkit-scrollbar-thumb {
background-color: #555;
border-radius: 4px;
}

54 changes: 54 additions & 0 deletions public/static/css/modules/button.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
.m-button {
background-color: transparent;
border: none;
color: #61AFEF;
/* Default text color for this button type */
cursor: pointer;
padding: 0.25rem;
border-radius: 0.25rem;
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
transition: background-color 0.2s ease, box-shadow 0.2s ease, transform 0.3s ease-in-out;
min-width: 180px;
}

.m-button__content {
position: relative;
z-index: 2;
/* Ensures content is on top of pseudo-elements */
color: #ffffff;
/* White text/icon color for content */
display: flex;
/* For icon and text alignment */
align-items: center;
gap: 0.5rem;
padding: 12px 24px;
/* Visual padding for the clickable area */
}

.m-button__icon {
font-size: 1.25rem;
}

.m-button:hover {
background-color: rgba(97, 175, 239, 0.1);
transform: scale(1.05);
}

.m-button:focus {
outline: none;
box-shadow: 0 0 0 2px rgba(97, 175, 239, 0.5);
}

.m-button:active {
background-color: rgba(97, 175, 239, 0.2);
}

@media (max-width: 600px) {
.m-button {
min-width: unset;
width: 90%;
}
}
58 changes: 58 additions & 0 deletions public/static/css/modules/file-input.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.m-file-input {
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
min-width: 36px;
padding: 0.25rem;
border-radius: 0.25rem;
background-color: #1f2937;
/* Dark gray background */
color: #ffffff;
/* White text/icon color */
transition: background-color 0.2s ease, box-shadow 0.2s ease, transform 0.3s ease-in-out;
}

.m-file-input:hover {
transform: scale(1.05);
background-color: rgba(97, 175, 239, 0.1);
}

.m-file-input__input {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
opacity: 0;
/* Hide the default file input */
cursor: pointer;
z-index: 2;
/* Ensure it's clickable */
}

.m-file-input__label {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
color: #ffffff;
position: relative;
z-index: 1;
/* Above input but below pseudo-elements for border */
padding: 4px 8px;
/* Visual padding for the clickable area */
width: 100%;
height: 100%;
}

.m-file-input__icon {
font-size: 1.25rem;
}

@media (max-width: 600px) {
.m-file-input {
min-width: unset;
width: 90%;
}
}
Loading