mirror of
https://github.com/dredx/prole.git
synced 2026-09-24 19:34:31 +00:00
763 lines
26 KiB
HTML
763 lines
26 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Prole Service Dependencies Installer</title>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||
background: #1a1a1a;
|
||
color: #e0e0e0;
|
||
overflow: hidden;
|
||
height: 100vh;
|
||
position: relative;
|
||
}
|
||
|
||
#background-image {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background-image: url('images/prole-type.gif');
|
||
background-size: cover;
|
||
background-position: center;
|
||
background-repeat: no-repeat;
|
||
opacity: 0.15;
|
||
z-index: 0;
|
||
}
|
||
|
||
.installer-container {
|
||
position: relative;
|
||
z-index: 1;
|
||
height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: rgba(26, 26, 26, 0.85);
|
||
backdrop-filter: blur(10px);
|
||
}
|
||
|
||
.installer-header {
|
||
padding: 30px;
|
||
text-align: center;
|
||
border-bottom: 2px solid #333;
|
||
}
|
||
|
||
.installer-header h1 {
|
||
font-size: 32px;
|
||
color: #4a9eff;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.installer-header p {
|
||
color: #aaa;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.installer-content {
|
||
flex: 1;
|
||
padding: 40px;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.step {
|
||
display: none;
|
||
max-width: 900px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.step.active {
|
||
display: block;
|
||
}
|
||
|
||
.checklist-item {
|
||
background: rgba(255, 255, 255, 0.05);
|
||
border: 1px solid #333;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
margin-bottom: 15px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.checklist-item-content {
|
||
flex: 1;
|
||
}
|
||
|
||
.checklist-item-title {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: #fff;
|
||
margin-bottom: 8px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.checklist-item-description {
|
||
font-size: 14px;
|
||
color: #aaa;
|
||
margin-top: 5px;
|
||
}
|
||
|
||
.sub-checklist {
|
||
margin-top: 15px;
|
||
margin-left: 30px;
|
||
padding-left: 20px;
|
||
border-left: 2px solid #444;
|
||
}
|
||
|
||
.sub-checklist-item {
|
||
background: rgba(255, 255, 255, 0.03);
|
||
border: 1px solid #2a2a2a;
|
||
border-radius: 6px;
|
||
padding: 12px;
|
||
margin-bottom: 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
|
||
.status-indicator {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 15px;
|
||
}
|
||
|
||
.checkmark {
|
||
width: 24px;
|
||
height: 24px;
|
||
border-radius: 50%;
|
||
border: 2px solid #4a9eff;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.checkmark.installed {
|
||
background: #4a9eff;
|
||
border-color: #4a9eff;
|
||
}
|
||
|
||
.checkmark.installed::after {
|
||
content: '✓';
|
||
color: white;
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.checkmark.not-installed {
|
||
background: transparent;
|
||
border-color: #666;
|
||
}
|
||
|
||
.checkmark.not-installed::after {
|
||
content: '✗';
|
||
color: #666;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.btn {
|
||
padding: 10px 20px;
|
||
border: none;
|
||
border-radius: 6px;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: all 0.3s;
|
||
text-decoration: none;
|
||
display: inline-block;
|
||
}
|
||
|
||
.btn-primary {
|
||
background: #4a9eff;
|
||
color: white;
|
||
}
|
||
|
||
.btn-primary:hover {
|
||
background: #3a8eef;
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
.btn-secondary {
|
||
background: #555;
|
||
color: white;
|
||
}
|
||
|
||
.btn-secondary:hover {
|
||
background: #666;
|
||
}
|
||
|
||
.btn-download {
|
||
background: #28a745;
|
||
color: white;
|
||
}
|
||
|
||
.btn-download:hover {
|
||
background: #218838;
|
||
}
|
||
|
||
.btn-update {
|
||
background: #ffc107;
|
||
color: #1a1a1a;
|
||
}
|
||
|
||
.btn-update:hover {
|
||
background: #e0a800;
|
||
}
|
||
|
||
.command-display {
|
||
background: #0a0a0a;
|
||
border: 1px solid #333;
|
||
border-radius: 6px;
|
||
padding: 20px;
|
||
margin: 20px 0;
|
||
font-family: 'Courier New', monospace;
|
||
font-size: 14px;
|
||
color: #4a9eff;
|
||
overflow-x: auto;
|
||
}
|
||
|
||
.command-display code {
|
||
color: #4a9eff;
|
||
white-space: pre-wrap;
|
||
}
|
||
|
||
.installer-footer {
|
||
padding: 20px 40px;
|
||
border-top: 2px solid #333;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.btn-large {
|
||
padding: 12px 30px;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.terminal-window {
|
||
position: fixed;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 80%;
|
||
max-width: 800px;
|
||
height: 500px;
|
||
background: rgba(10, 10, 10, 0.95);
|
||
border: 2px solid #4a9eff;
|
||
border-radius: 8px;
|
||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
|
||
z-index: 1000;
|
||
display: none;
|
||
flex-direction: column;
|
||
backdrop-filter: blur(10px);
|
||
}
|
||
|
||
.terminal-window.active {
|
||
display: flex;
|
||
}
|
||
|
||
.terminal-window::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background-image: url('images/prole-type.gif');
|
||
background-size: cover;
|
||
background-position: center;
|
||
opacity: 0.2;
|
||
z-index: -1;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.terminal-header {
|
||
padding: 15px;
|
||
background: rgba(74, 158, 255, 0.2);
|
||
border-bottom: 1px solid #4a9eff;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.terminal-title {
|
||
color: #4a9eff;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.terminal-close {
|
||
background: #ff4444;
|
||
color: white;
|
||
border: none;
|
||
width: 24px;
|
||
height: 24px;
|
||
border-radius: 50%;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.terminal-body {
|
||
flex: 1;
|
||
padding: 20px;
|
||
overflow-y: auto;
|
||
font-family: 'Courier New', monospace;
|
||
font-size: 14px;
|
||
color: #4a9eff;
|
||
}
|
||
|
||
.terminal-prompt {
|
||
color: #4a9eff;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.terminal-input {
|
||
background: transparent;
|
||
border: none;
|
||
color: #4a9eff;
|
||
font-family: 'Courier New', monospace;
|
||
font-size: 14px;
|
||
width: 100%;
|
||
outline: none;
|
||
}
|
||
|
||
.terminal-output {
|
||
color: #aaa;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.cluster-status {
|
||
background: #0a0a0a;
|
||
border: 1px solid #333;
|
||
border-radius: 6px;
|
||
padding: 20px;
|
||
margin: 20px 0;
|
||
font-family: 'Courier New', monospace;
|
||
font-size: 14px;
|
||
color: #4a9eff;
|
||
min-height: 200px;
|
||
max-height: 400px;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.cluster-status pre {
|
||
margin: 0;
|
||
color: #4a9eff;
|
||
}
|
||
|
||
.status-text {
|
||
color: #aaa;
|
||
font-style: italic;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div id="background-image"></div>
|
||
|
||
<div class="installer-container">
|
||
<div class="installer-header">
|
||
<h1>Prole Service Dependencies Installer</h1>
|
||
<p>Install and configure required dependencies for Prole services</p>
|
||
</div>
|
||
|
||
<div class="installer-content">
|
||
<!-- Step 1: Dependency Installation -->
|
||
<div class="step active" id="step1">
|
||
<h2 style="margin-bottom: 30px; color: #4a9eff;">Step 1: Install Dependencies</h2>
|
||
|
||
<!-- Docker Check -->
|
||
<div class="checklist-item">
|
||
<div class="checklist-item-content">
|
||
<div class="checklist-item-title">
|
||
<span>Docker</span>
|
||
</div>
|
||
<div class="checklist-item-description">
|
||
Container platform required for running Prole services
|
||
</div>
|
||
</div>
|
||
<div class="status-indicator">
|
||
<div class="checkmark not-installed" id="docker-check"></div>
|
||
<a href="https://www.docker.com/products/docker-desktop" target="_blank" class="btn btn-download">Click here to download</a>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Homebrew Check -->
|
||
<div class="checklist-item">
|
||
<div class="checklist-item-content">
|
||
<div class="checklist-item-title">
|
||
<span>Homebrew</span>
|
||
</div>
|
||
<div class="checklist-item-description">
|
||
Package manager for macOS (required for k3d installation)
|
||
</div>
|
||
<div class="sub-checklist">
|
||
<div class="sub-checklist-item">
|
||
<div class="checklist-item-content">
|
||
<div class="checklist-item-title" style="font-size: 16px;">
|
||
<span>Homebrew Installed & Current</span>
|
||
</div>
|
||
</div>
|
||
<div class="status-indicator">
|
||
<div class="checkmark not-installed" id="homebrew-check"></div>
|
||
<button class="btn btn-update" id="update-homebrew-btn">Update Homebrew</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- k3d Check -->
|
||
<div class="checklist-item">
|
||
<div class="checklist-item-content">
|
||
<div class="checklist-item-title">
|
||
<span>k3d</span>
|
||
</div>
|
||
<div class="checklist-item-description">
|
||
Lightweight wrapper to run k3s in Docker (installed via Homebrew)
|
||
</div>
|
||
</div>
|
||
<div class="status-indicator">
|
||
<div class="checkmark not-installed" id="k3d-check"></div>
|
||
<a href="https://k3d.io/" target="_blank" class="btn btn-download">Click here to download</a>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Command Display -->
|
||
<div class="command-display">
|
||
<strong style="color: #fff; margin-bottom: 10px; display: block;">Commands to execute:</strong>
|
||
<code id="install-commands"># Commands will appear here after checking dependencies</code>
|
||
</div>
|
||
|
||
<div style="text-align: center; margin-top: 30px;">
|
||
<button class="btn btn-primary btn-large" id="install-btn">Install</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Step 2: Create Home Cluster -->
|
||
<div class="step" id="step2">
|
||
<h2 style="margin-bottom: 30px; color: #4a9eff;">Step 2: Create Home Cluster</h2>
|
||
|
||
<!-- Docker Running Check -->
|
||
<div class="checklist-item">
|
||
<div class="checklist-item-content">
|
||
<div class="checklist-item-title">
|
||
<span>Docker Installed and Running</span>
|
||
</div>
|
||
<div class="checklist-item-description">
|
||
Verify Docker is installed and the daemon is running
|
||
</div>
|
||
</div>
|
||
<div class="status-indicator">
|
||
<div class="checkmark not-installed" id="docker-running-check"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- k3d Ready Check -->
|
||
<div class="checklist-item">
|
||
<div class="checklist-item-content">
|
||
<div class="checklist-item-title">
|
||
<span>k3d Command and Dependencies Ready</span>
|
||
</div>
|
||
<div class="checklist-item-description">
|
||
Verify k3d and all related dependencies are installed and ready
|
||
</div>
|
||
</div>
|
||
<div class="status-indicator">
|
||
<div class="checkmark not-installed" id="k3d-ready-check"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- k3d Cluster List -->
|
||
<div class="cluster-status">
|
||
<strong style="color: #fff; margin-bottom: 10px; display: block;">k3d cluster list output:</strong>
|
||
<pre id="cluster-list-output" class="status-text">Running k3d cluster list...</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="installer-footer">
|
||
<button class="btn btn-secondary" id="prev-btn" style="display: none;">Previous</button>
|
||
<button class="btn btn-primary btn-large" id="next-btn">Next</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Terminal Window -->
|
||
<div class="terminal-window" id="terminal-window">
|
||
<div class="terminal-header">
|
||
<div class="terminal-title">Prole Terminal</div>
|
||
<button class="terminal-close" id="terminal-close">×</button>
|
||
</div>
|
||
<div class="terminal-body" id="terminal-body">
|
||
<div class="terminal-prompt">$ what is my name?</div>
|
||
<div class="terminal-output" id="terminal-output"></div>
|
||
<div class="terminal-prompt" id="terminal-input-line" style="display: none;">
|
||
$ <input type="text" class="terminal-input" id="terminal-input" autocomplete="off">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
let currentStep = 1;
|
||
let userName = '';
|
||
let terminalActive = false;
|
||
|
||
// Check dependencies on load
|
||
async function checkDependencies() {
|
||
// Simulate checking dependencies
|
||
// In a real implementation, this would call a backend API
|
||
|
||
// Check Docker
|
||
try {
|
||
const dockerCheck = await checkCommand('docker --version');
|
||
updateCheckmark('docker-check', dockerCheck);
|
||
} catch (e) {
|
||
updateCheckmark('docker-check', false);
|
||
}
|
||
|
||
// Check Homebrew
|
||
try {
|
||
const brewCheck = await checkCommand('brew --version');
|
||
updateCheckmark('homebrew-check', brewCheck);
|
||
} catch (e) {
|
||
updateCheckmark('homebrew-check', false);
|
||
}
|
||
|
||
// Check k3d
|
||
try {
|
||
const k3dCheck = await checkCommand('k3d --version');
|
||
updateCheckmark('k3d-check', k3dCheck);
|
||
} catch (e) {
|
||
updateCheckmark('k3d-check', false);
|
||
}
|
||
|
||
updateInstallCommands();
|
||
}
|
||
|
||
// Simulate command checking (in real app, this would use a backend)
|
||
async function checkCommand(command) {
|
||
// This is a simulation - in a real app, you'd call a backend API
|
||
// For now, we'll simulate based on common scenarios
|
||
return new Promise((resolve) => {
|
||
setTimeout(() => {
|
||
// Simulate: docker and brew are often installed, k3d less so
|
||
if (command.includes('docker')) {
|
||
resolve(Math.random() > 0.3); // 70% chance installed
|
||
} else if (command.includes('brew')) {
|
||
resolve(Math.random() > 0.2); // 80% chance installed
|
||
} else if (command.includes('k3d')) {
|
||
resolve(Math.random() > 0.7); // 30% chance installed
|
||
} else {
|
||
resolve(false);
|
||
}
|
||
}, 500);
|
||
});
|
||
}
|
||
|
||
function updateCheckmark(id, installed) {
|
||
const checkmark = document.getElementById(id);
|
||
if (installed) {
|
||
checkmark.classList.remove('not-installed');
|
||
checkmark.classList.add('installed');
|
||
} else {
|
||
checkmark.classList.remove('installed');
|
||
checkmark.classList.add('not-installed');
|
||
}
|
||
}
|
||
|
||
function updateInstallCommands() {
|
||
const dockerInstalled = document.getElementById('docker-check').classList.contains('installed');
|
||
const brewInstalled = document.getElementById('homebrew-check').classList.contains('installed');
|
||
const k3dInstalled = document.getElementById('k3d-check').classList.contains('installed');
|
||
|
||
let commands = [];
|
||
|
||
if (!brewInstalled) {
|
||
commands.push('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"');
|
||
} else {
|
||
commands.push('brew update');
|
||
commands.push('brew upgrade');
|
||
}
|
||
|
||
if (!k3dInstalled && brewInstalled) {
|
||
commands.push('brew install k3d');
|
||
}
|
||
|
||
const commandsDisplay = document.getElementById('install-commands');
|
||
if (commands.length > 0) {
|
||
commandsDisplay.textContent = commands.join('\n');
|
||
} else {
|
||
commandsDisplay.textContent = '# All dependencies are already installed!';
|
||
}
|
||
}
|
||
|
||
// Update Homebrew button
|
||
document.getElementById('update-homebrew-btn').addEventListener('click', () => {
|
||
const commandsDisplay = document.getElementById('install-commands');
|
||
commandsDisplay.textContent = 'brew update\nbrew upgrade';
|
||
alert('Click the Install button to update Homebrew');
|
||
});
|
||
|
||
// Install button
|
||
document.getElementById('install-btn').addEventListener('click', () => {
|
||
const commands = document.getElementById('install-commands').textContent;
|
||
if (commands.includes('All dependencies')) {
|
||
alert('All dependencies are already installed!');
|
||
return;
|
||
}
|
||
|
||
// Show commands that will be executed
|
||
const confirmed = confirm(`The following commands will be executed:\n\n${commands}\n\nProceed?`);
|
||
if (confirmed) {
|
||
// In a real app, this would execute the commands via a backend
|
||
alert('Installation commands executed! (This is a simulation - in production, commands would run via backend)');
|
||
|
||
// Simulate installation success
|
||
setTimeout(() => {
|
||
checkDependencies();
|
||
}, 2000);
|
||
}
|
||
});
|
||
|
||
// Next button
|
||
document.getElementById('next-btn').addEventListener('click', () => {
|
||
if (currentStep === 1) {
|
||
// Move to step 2
|
||
document.getElementById('step1').classList.remove('active');
|
||
document.getElementById('step2').classList.add('active');
|
||
document.getElementById('prev-btn').style.display = 'block';
|
||
currentStep = 2;
|
||
|
||
// Check cluster status
|
||
checkClusterStatus();
|
||
} else if (currentStep === 2) {
|
||
// Open terminal window
|
||
openTerminal();
|
||
}
|
||
});
|
||
|
||
// Previous button
|
||
document.getElementById('prev-btn').addEventListener('click', () => {
|
||
if (currentStep === 2) {
|
||
document.getElementById('step2').classList.remove('active');
|
||
document.getElementById('step1').classList.add('active');
|
||
document.getElementById('prev-btn').style.display = 'none';
|
||
currentStep = 1;
|
||
}
|
||
});
|
||
|
||
// Check cluster status
|
||
async function checkClusterStatus() {
|
||
// Check Docker running
|
||
try {
|
||
const dockerRunning = await checkCommand('docker ps');
|
||
updateCheckmark('docker-running-check', dockerRunning);
|
||
} catch (e) {
|
||
updateCheckmark('docker-running-check', false);
|
||
}
|
||
|
||
// Check k3d ready
|
||
try {
|
||
const k3dReady = await checkCommand('k3d --version');
|
||
updateCheckmark('k3d-ready-check', k3dReady);
|
||
} catch (e) {
|
||
updateCheckmark('k3d-ready-check', false);
|
||
}
|
||
|
||
// Run k3d cluster list
|
||
const clusterOutput = document.getElementById('cluster-list-output');
|
||
clusterOutput.textContent = 'Running: k3d cluster list\n\n';
|
||
|
||
// Simulate k3d cluster list output
|
||
setTimeout(() => {
|
||
const output = `$ k3d cluster list
|
||
|
||
NAME CLUSTER SERVERS AGENTS LOADBALANCER
|
||
prole-data-cluster running 1 0 true
|
||
|
||
Clusters found: 1`;
|
||
clusterOutput.textContent = output;
|
||
}, 1000);
|
||
}
|
||
|
||
// Terminal functions
|
||
function openTerminal() {
|
||
const terminal = document.getElementById('terminal-window');
|
||
terminal.classList.add('active');
|
||
terminalActive = true;
|
||
|
||
// Start the prompt sequence
|
||
setTimeout(() => {
|
||
const inputLine = document.getElementById('terminal-input-line');
|
||
inputLine.style.display = 'block';
|
||
document.getElementById('terminal-input').focus();
|
||
}, 500);
|
||
}
|
||
|
||
document.getElementById('terminal-close').addEventListener('click', () => {
|
||
document.getElementById('terminal-window').classList.remove('active');
|
||
terminalActive = false;
|
||
userName = '';
|
||
document.getElementById('terminal-output').innerHTML = '';
|
||
document.getElementById('terminal-input-line').style.display = 'none';
|
||
document.getElementById('terminal-input').value = '';
|
||
});
|
||
|
||
document.getElementById('terminal-input').addEventListener('keypress', (e) => {
|
||
if (e.key === 'Enter') {
|
||
const input = document.getElementById('terminal-input');
|
||
const value = input.value.trim();
|
||
const output = document.getElementById('terminal-output');
|
||
|
||
if (!userName) {
|
||
// First question: "what is my name?"
|
||
userName = value || 'Prole';
|
||
output.innerHTML = `<div style="color: #4a9eff;">$ ${value}</div>`;
|
||
output.innerHTML += `<div style="color: #aaa; margin-top: 10px;">Hi, I'm ${userName}. What should I call you?</div>`;
|
||
input.value = '';
|
||
|
||
// Update prompt
|
||
setTimeout(() => {
|
||
const promptLine = document.querySelector('.terminal-prompt');
|
||
if (promptLine) {
|
||
promptLine.textContent = `$ `;
|
||
}
|
||
}, 100);
|
||
} else {
|
||
// Second question: "What should I call you?"
|
||
const userResponse = value || 'User';
|
||
output.innerHTML += `<div style="color: #4a9eff;">$ ${value}</div>`;
|
||
output.innerHTML += `<div style="color: #aaa; margin-top: 10px;">Nice to meet you, ${userResponse}! I'm ${userName}.</div>`;
|
||
input.value = '';
|
||
|
||
// Close terminal after a moment
|
||
setTimeout(() => {
|
||
document.getElementById('terminal-window').classList.remove('active');
|
||
terminalActive = false;
|
||
}, 2000);
|
||
}
|
||
}
|
||
});
|
||
|
||
// Initialize
|
||
checkDependencies();
|
||
</script>
|
||
</body>
|
||
</html>
|
||
|
||
|
||
|
||
|