peardock/index.html
2024-12-01 22:14:26 -05:00

545 lines
15 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Docker P2P Manager</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
<!-- xterm.css for Terminal -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/xterm/css/xterm.css">
<style>
body {
margin: 0;
display: flex;
height: 100vh;
background-color: #1a1a1a;
color: white;
overflow: hidden;
}
.hidden {
display: none !important;
}
#titlebar {
-webkit-app-region: drag;
height: 30px;
width: 100%;
position: fixed;
top: 0;
background-color: #2c2c2c;
z-index: 1000;
}
pear-ctrl[data-platform="darwin"] {
float: left;
margin-top: 5px;
margin-left: 10px;
}
#sidebar {
position: fixed;
top: 30px;
left: 0;
background-color: #2c2c2c;
height: calc(100vh - 30px);
width: 250px;
overflow-y: auto;
transition: width 0.3s ease-in-out;
}
#sidebar.collapsed {
width: 50px;
}
#sidebar.collapsed .content {
display: none;
}
#collapse-sidebar-btn {
position: absolute;
top: 10px;
right: 10px;
background-color: #444;
border: none;
color: white;
width: 30px;
height: 30px;
border-radius: 50%;
font-size: 16px;
line-height: 30px;
text-align: center;
cursor: pointer;
}
#content {
display: flex;
flex-direction: column;
/* Keep vertical stacking for child elements */
margin-left: 250px;
/* Leave space for the sidebar */
flex: 1;
/* Allow the content to grow */
overflow-y: auto;
/* Allow scrolling if content overflows */
position: relative;
}
#sidebar.collapsed~#content {
margin-left: 50px;
}
.connection-status {
border-radius: 50%;
width: 10px;
height: 10px;
display: inline-block;
margin-right: 8px;
}
.status-connected {
background-color: green;
}
.status-disconnected {
background-color: red;
}
#terminal-modal {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
max-height: 90vh;
height: 300px;
background-color: #1a1a1a;
border-top: 2px solid #444;
display: none;
flex-direction: column;
z-index: 1000;
overflow: hidden;
}
#terminal-modal .header {
background-color: #444;
cursor: move;
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
#terminal-resize-handle {
width: 100%;
height: 10px;
cursor: ns-resize;
background-color: #444;
position: absolute;
bottom: 0;
left: 0;
}
#terminal-container {
flex: 1;
overflow: hidden;
background-color: black;
color: white;
}
#tray {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background-color: #444;
padding: 5px 10px;
display: flex;
gap: 10px;
overflow-x: auto;
white-space: nowrap;
z-index: 999;
}
#tray .tray-item {
background-color: #555;
color: white;
padding: 5px 10px;
border-radius: 5px;
cursor: pointer;
}
#status-indicator {
display: none;
/* Ensure it's hidden by default */
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.75);
z-index: 1050;
}
#status-indicator .spinner-border {
width: 3rem;
height: 3rem;
}
#status-indicator p {
margin-top: 1rem;
color: #fff;
font-size: 1.25rem;
}
#welcome-page {
display: flex;
flex-direction: column;
/* Stack child elements vertically */
justify-content: center;
/* Center content vertically */
align-items: center;
/* Center content horizontally */
text-align: center;
/* Center-align text */
position: absolute;
/* Overlay it over the content area */
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/* Center it perfectly in the content */
max-width: 800px;
/* Restrict the width of the welcome page */
width: 100%;
/* Allow it to scale */
padding: 20px;
background-color: transparent;
/* Match the theme */
}
#welcome-page.hidden {
display: none !important;
/* Completely hide when not needed */
}
#dashboard {
display: flex;
/* Use flex layout for content within the dashboard */
flex-direction: column;
/* Stack elements vertically */
flex: 1;
/* Ensure it uses all available space */
width: 100%;
/* Take up the full width of the content area */
margin-top: 30px;
/* Remove extra padding */
overflow-y: auto;
/* Allow vertical scrolling if needed */
position: relative;
/* Prevent overlap with other elements */
}
#dashboard.hidden {
display: none !important;
/* Hide the dashboard completely when not needed */
}
#alert-container {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 1055;
/* Ensure it overlays important elements only */
display: flex;
flex-direction: column-reverse;
/* Stack alerts upwards */
gap: 10px;
/* Add space between alerts */
pointer-events: none;
/* Prevent container from blocking clicks */
}
.alert {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 80%;
padding: 12px 20px;
background-color: #2b2b2b;
color: #e0e0e0;
border-radius: 6px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5);
font-family: Arial, sans-serif;
font-size: 14px;
animation: fadeIn 0.3s ease-out, fadeOut 4.5s ease-in forwards;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
pointer-events: auto;
/* Allow alerts to be interactive */
}
.alert.success {
border-left: 6px solid #28a745;
/* Green border for success */
}
.alert.danger {
border-left: 6px solid #dc3545;
/* Red border for danger */
}
.alert .close-btn {
background: none;
border: none;
color: #e0e0e0;
font-size: 16px;
cursor: pointer;
margin-left: auto;
/* Align to the far right */
}
@media (max-width: 768px) {
#alert-container {
bottom: 10px;
right: 10px;
}
.alert {
max-width: 90%;
font-size: 12px;
padding: 10px 15px;
white-space: normal;
/* Allow wrapping on small screens */
text-overflow: clip;
/* Disable ellipsis when wrapping */
}
}
@media (min-width: 768px) {
.alert {
white-space: nowrap;
/* Re-enable nowrap for larger screens */
text-overflow: ellipsis;
/* Add ellipsis for overflowed text */
}
}
#sidebar.collapsed .btn-danger {
display: none;
}
/* General scrollbar styles for dark and skinny scrollbars */
* {
scrollbar-width: thin;
/* Firefox */
scrollbar-color: #555 #1a1a1a;
/* Firefox: thumb and track color */
}
/* WebKit-based browsers (Chrome, Edge, Safari) */
*::-webkit-scrollbar {
width: 8px;
/* Width of vertical scrollbar */
height: 8px;
/* Height of horizontal scrollbar */
}
*::-webkit-scrollbar-track {
background: #1a1a1a;
/* Track color */
}
*::-webkit-scrollbar-thumb {
background-color: #555;
/* Thumb color */
border-radius: 10px;
/* Round the thumb */
border: 2px solid #1a1a1a;
/* Space between thumb and track */
}
*::-webkit-scrollbar-thumb:hover {
background-color: #777;
/* Lighter color on hover */
}
*::-webkit-scrollbar-thumb:active {
background-color: #999;
/* Even lighter color when active */
}
</style>
</head>
<body>
<div id="titlebar">
<pear-ctrl></pear-ctrl>
</div>
<div id="sidebar">
<button id="collapse-sidebar-btn">&lt;</button>
<div class="content">
<h4 class="text-center mt-3">Connections</h4>
<ul id="connection-list" class="list-group mb-3"></ul>
<form id="add-connection-form" class="px-3">
<input type="text" id="new-connection-topic" class="form-control mb-2" placeholder="Enter server topic"
required>
<button type="submit" class="btn btn-primary w-100">Add Connection</button>
</form>
</div>
</div>
<div id="content">
<div id="welcome-page">
<h1>Welcome to Peartainer</h1>
<p class="mt-3">Easily manage your Docker containers across peer-to-peer connections.</p>
<p>To get started, add a connection using the form in the sidebar.</p>
<!-- <img src="https://via.placeholder.com/500x300" alt="Welcome Graphic" class="img-fluid mt-4"> -->
</div>
<div id="dashboard" class="hidden">
<div class="table-responsive">
<table class="table table-dark table-striped">
<thead>
<tr>
<th>Name</th>
<th>Image</th>
<th>Status</th>
<th>CPU (%)</th>
<th>Memory (MB)</th>
<th>IP Address</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="container-list"></tbody>
</table>
</div>
</div>
</div>
<!-- Duplicate Container Modal -->
<div class="modal fade" id="duplicateModal" tabindex="-1" aria-labelledby="duplicateModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content bg-dark text-white">
<div class="modal-header">
<h5 class="modal-title" id="duplicateModalLabel">Duplicate Container</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="duplicate-container-form">
<div class="mb-3">
<label for="container-name" class="form-label">Container Name</label>
<input type="text" class="form-control" id="container-name" required>
</div>
<div class="mb-3">
<label for="container-hostname" class="form-label">Hostname</label>
<input type="text" class="form-control" id="container-hostname" required>
</div>
<div class="mb-3">
<label for="container-image" class="form-label">Image</label>
<input type="text" class="form-control" id="container-image" required>
</div>
<div class="mb-3">
<label for="container-netmode" class="form-label">Net Mode</label>
<input type="text" class="form-control" id="container-netmode" required>
</div>
<div class="mb-3">
<label for="container-cpu" class="form-label">CPU Count</label>
<input type="number" class="form-control" id="container-cpu" required>
</div>
<div class="mb-3">
<label for="container-memory" class="form-label">Memory (MB)</label>
<input type="number" class="form-control" id="container-memory" required>
</div>
<div class="mb-3">
<label for="container-config" class="form-label">Container Configuration (JSON)</label>
<textarea class="form-control" id="container-config" rows="10" required></textarea>
</div>
<button type="submit" class="btn btn-primary">Deploy Duplicate</button>
</form>
</div>
</div>
</div>
</div>
<!-- Terminal Modal -->
<div id="terminal-modal">
<div class="header">
<span id="terminal-title"></span>
<div>
<button id="kill-terminal-btn" class="btn btn-sm btn-danger">
<i class="fas fa-times-circle"></i>
</button>
</div>
</div>
<div id="terminal-container"></div>
<div id="terminal-resize-handle"></div>
</div>
<!-- Delete Confirmation Modal -->
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content bg-dark text-white">
<div class="modal-header">
<h5 class="modal-title" id="deleteModalLabel">Confirm Deletion</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
Are you sure you want to delete this container?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" id="confirm-delete-btn" class="btn btn-danger">Delete</button>
</div>
</div>
</div>
</div>
<!-- Status Indicator Overlay -->
<div id="status-indicator"
class="position-fixed top-0 start-0 w-100 h-100 d-flex justify-content-center align-items-center bg-dark bg-opacity-75"
style="display: none; z-index: 1050;">
<div class="text-center">
<div class="spinner-border text-light" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-3 text-light">Processing...</p>
</div>
</div>
<!-- Docker Terminal Modal -->
<!-- Docker CLI Terminal Modal -->
<div id="docker-terminal-modal" class="position-fixed bottom-0 start-0 w-100 max-height-90 bg-dark text-white d-flex flex-column" style="display: none; z-index: 1000;">
<div class="header d-flex justify-content-between align-items-center bg-secondary p-2">
<span id="docker-terminal-title" class="fw-bold">Docker CLI Terminal</span>
<button id="docker-kill-terminal-btn" class="btn btn-sm btn-danger">
<i class="fas fa-times-circle"></i>
</button>
</div>
<div id="docker-terminal-container" class="flex-grow-1 overflow-hidden" style="background-color: black;"></div>
<div id="docker-terminal-resize-handle" class="bg-secondary" style="height: 10px; cursor: ns-resize;"></div>
</div>
<!-- Alert Container -->
<div id="alert-container" class="position-fixed top-0 start-50 translate-middle-x mt-3"
style="z-index: 1051; max-width: 90%;"></div>
<!-- xterm.js -->
<script src="https://cdn.jsdelivr.net/npm/xterm/lib/xterm.js"></script>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<!-- Your App JS -->
<script type="module" src="app.js"></script>
</body>
</html>