Refactor Ansible Sandbox page: Updated styles for improved layout and user experience, including new sandbox-specific styles, a redesigned navigation link, and enhanced tab functionality for code, output, and status views. Added responsive design adjustments for better mobile compatibility.

This commit is contained in:
Daniel LaForce 2025-04-10 19:08:54 -06:00
parent 0937c4bd7a
commit 7d9df34dde
2 changed files with 382 additions and 326 deletions

View File

@ -99,7 +99,7 @@
left: 0;
right: 0;
z-index: 1000;
padding: 1.25rem 0;
padding: 1rem 0;
border-bottom: 1px solid var(--border);
}
@ -190,24 +190,25 @@
gap: 1.25rem;
}
.dashboard-link {
.back-link {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.625rem 1.25rem;
font-size: 0.95rem;
gap: 0.5rem;
padding: 0.5rem 1rem;
background-color: rgba(59, 130, 246, 0.1);
border: 1px solid rgba(59, 130, 246, 0.3);
border-radius: 0.5rem;
font-size: 0.9rem;
font-weight: 500;
color: var(--text-primary);
background-color: rgba(59, 130, 246, 0.1);
border: 1px solid rgba(59, 130, 246, 0.2);
border-radius: 0.5rem;
text-decoration: none;
transition: all var(--transition-normal);
}
.dashboard-link:hover {
.back-link:hover {
background-color: rgba(59, 130, 246, 0.2);
border-color: rgba(59, 130, 246, 0.3);
border-color: var(--accent);
transform: translateY(-2px);
}
.live-indicator {
@ -1188,6 +1189,242 @@
transform: scale(1.05);
}
}
/* Sandbox Specific Styles */
.sandbox-content {
padding-top: 8rem;
max-width: 900px;
margin: 0 auto;
}
.sandbox-title {
font-size: 2.5rem;
margin-bottom: 1rem;
text-align: center;
color: var(--text-primary);
background: var(--accent-gradient);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.sandbox-description {
text-align: center;
color: var(--text-secondary);
margin-bottom: 3rem;
font-size: 1.1rem;
}
.sandbox-tabs {
display: flex;
justify-content: center;
margin-bottom: 2rem;
}
.preview-tabs {
display: flex;
gap: 2rem;
border-bottom: 1px solid var(--border);
padding-bottom: 0.5rem;
width: 100%;
justify-content: center;
}
.preview-tab {
font-size: 1.1rem;
font-weight: 500;
color: var(--text-secondary);
cursor: pointer;
position: relative;
padding: 0.5rem 1rem;
transition: color var(--transition-normal);
}
.preview-tab::after {
content: '';
position: absolute;
bottom: -8px;
left: 0;
width: 0;
height: 3px;
background: var(--accent-gradient);
transition: width var(--transition-normal);
}
.preview-tab:hover {
color: var(--text-primary);
}
.preview-tab.active {
color: var(--accent);
}
.preview-tab.active::after {
width: 100%;
}
.preview-content {
background-color: var(--card-bg);
border-radius: 0.75rem;
overflow: hidden;
border: 1px solid var(--border);
margin-bottom: 2rem;
box-shadow: var(--card-shadow);
min-height: 400px;
}
.tab-content {
display: none;
padding: 2rem;
}
.tab-content.active {
display: block;
}
.tab-content h3 {
margin-bottom: 1rem;
color: var(--text-primary);
}
.preview-status {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1.5rem;
font-size: 1.1rem;
}
.status-dot {
width: 12px;
height: 12px;
border-radius: 50%;
}
.status-ready {
background-color: var(--info);
box-shadow: 0 0 5px var(--info);
}
.status-running {
background-color: var(--warning);
box-shadow: 0 0 5px var(--warning);
animation: pulse 1.5s infinite;
}
.status-success {
background-color: var(--success);
box-shadow: 0 0 5px var(--success);
}
@keyframes pulse {
0% {
opacity: 0.6;
}
50% {
opacity: 1;
}
100% {
opacity: 0.6;
}
}
.time-remaining {
margin-bottom: 0.75rem;
color: var(--text-secondary);
}
.time-progress {
height: 8px;
background-color: rgba(71, 85, 105, 0.2);
border-radius: 4px;
overflow: hidden;
margin-bottom: 2rem;
}
.time-progress-bar {
height: 100%;
background: var(--accent-gradient);
width: 0;
transition: width 1s ease-in-out;
}
.sandbox-controls {
display: flex;
gap: 1rem;
justify-content: center;
}
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.75rem;
padding: 0.75rem 1.5rem;
font-size: 1rem;
font-weight: 500;
border-radius: 0.5rem;
cursor: pointer;
transition: all var(--transition-normal);
border: none;
}
.btn-primary {
background: var(--accent-gradient);
color: white;
}
.btn-primary:hover {
box-shadow: var(--accent-glow);
transform: translateY(-2px);
}
.btn-outline {
background-color: transparent;
border: 1px solid var(--accent);
color: var(--accent);
}
.btn-outline:hover {
background-color: rgba(59, 130, 246, 0.1);
transform: translateY(-2px);
}
/* Code editor styles */
.code-editor {
font-family: 'JetBrains Mono', monospace;
background-color: rgba(15, 23, 42, 0.3);
border-radius: 0.5rem;
padding: 1.5rem;
font-size: 0.9rem;
line-height: 1.6;
max-height: 500px;
overflow-y: auto;
}
/* Responsive styles */
@media (max-width: 768px) {
.sandbox-title {
font-size: 2rem;
}
.preview-tabs {
gap: 1rem;
}
.preview-tab {
font-size: 0.9rem;
padding: 0.5rem;
}
.sandbox-controls {
flex-direction: column;
}
.btn {
width: 100%;
}
}
</style>
</head>
<body>
@ -1196,26 +1433,14 @@
<div class="container">
<div class="logo">
<a href="index.html">
<span class="logo-text-glow">Argobox</span>
<span class="logo-dot-glow">.com</span>
<span class="logo-text-glow">ArgoBox</span><span class="logo-dot-glow">.com</span>
</a>
</div>
<div class="nav-menu" id="navMenu">
<a href="index.html#home" class="nav-link">Home</a>
<a href="index.html#technologies" class="nav-link">Technologies</a>
<a href="index.html#services" class="nav-link">Services</a>
<a href="index.html#projects" class="nav-link">Projects</a>
<a href="index.html#dashboards" class="nav-link">Dashboards</a>
<a href="index.html#contact" class="nav-link">Contact</a>
</div>
<div class="nav-buttons">
<a href="dashboard.html" class="dashboard-link" target="_blank">
<span class="live-indicator"></span>
<span>Live Dashboard</span>
<a href="index.html" class="back-link">
<i class="fas fa-arrow-left"></i>
<span>Back to Home</span>
</a>
<button class="menu-toggle" id="menuToggle" aria-label="Toggle menu">
<i class="fas fa-bars"></i>
</button>
</div>
</div>
</nav>
@ -1228,192 +1453,56 @@
</div>
</div>
<div class="docs-container">
<aside class="sidebar">
<div class="sidebar-header">
<h2 class="sidebar-title">Ansible Sandbox</h2>
<a href="index.html" class="back-link">
<i class="fas fa-arrow-left"></i>
Back to Home
</a>
<div class="container">
<div class="sandbox-content">
<h1 class="sandbox-title">Ansible Sandbox</h1>
<p class="sandbox-description">Deploy infrastructure with Ansible playbooks in an isolated environment.</p>
<div class="sandbox-tabs">
<div class="preview-tabs">
<div class="preview-tab active" data-tab="code">Code</div>
<div class="preview-tab" data-tab="output">Output</div>
<div class="preview-tab" data-tab="status">Status</div>
</div>
</div>
<div class="sidebar-section">
<h3 class="sidebar-section-title">Getting Started</h3>
<ul class="sidebar-nav">
<li class="sidebar-nav-item">
<a href="#introduction" class="sidebar-nav-link active">Introduction</a>
</li>
<li class="sidebar-nav-item">
<a href="#prerequisites" class="sidebar-nav-link">Prerequisites</a>
</li>
<li class="sidebar-nav-item">
<a href="#quick-start" class="sidebar-nav-link">Quick Start Guide</a>
</li>
</ul>
</div>
<div class="sidebar-section">
<h3 class="sidebar-section-title">Features</h3>
<ul class="sidebar-nav">
<li class="sidebar-nav-item">
<a href="#sandbox-environment" class="sidebar-nav-link">Sandbox Environment</a>
</li>
<li class="sidebar-nav-item">
<a href="#playbook-examples" class="sidebar-nav-link">Playbook Examples</a>
</li>
<li class="sidebar-nav-item">
<a href="#best-practices" class="sidebar-nav-link">Best Practices</a>
</li>
</ul>
</div>
<div class="sidebar-section">
<h3 class="sidebar-section-title">Resources</h3>
<ul class="sidebar-nav">
<li class="sidebar-nav-item">
<a href="#documentation" class="sidebar-nav-link">Documentation</a>
</li>
<li class="sidebar-nav-item">
<a href="#troubleshooting" class="sidebar-nav-link">Troubleshooting</a>
</li>
<li class="sidebar-nav-item">
<a href="#community" class="sidebar-nav-link">Community</a>
</li>
</ul>
</div>
</aside>
<main class="main-content">
<header class="docs-header">
<h1 class="docs-title">Ansible Sandbox Documentation</h1>
<p class="docs-subtitle">Learn, experiment, and master Ansible automation in a safe environment</p>
</header>
<section id="introduction" class="docs-section">
<h2 class="docs-section-title">Introduction</h2>
<p class="docs-text">
Welcome to the ArgoBox Ansible Sandbox! This environment provides a safe and isolated space for learning
and experimenting with Ansible automation. Whether you're new to Ansible or an experienced user, our
sandbox offers the perfect platform to develop and test your automation skills.
</p>
<div class="docs-note">
<div class="docs-note-title">
<i class="fas fa-info-circle"></i>
Note
<div class="preview-content">
<div id="code-tab" class="tab-content active">
<div class="code-editor">
<h3>Ansible Playbook Editor</h3>
<p>Edit your playbook here...</p>
</div>
<p>The Ansible Sandbox is part of the ArgoBox Lab Environment, designed to provide hands-on experience
with enterprise-grade automation tools.</p>
</div>
</section>
<section id="prerequisites" class="docs-section">
<h2 class="docs-section-title">Prerequisites</h2>
<div class="docs-subsection">
<h3 class="docs-subsection-title">System Requirements</h3>
<ul class="docs-list">
<li>Access to ArgoBox Lab Environment</li>
<li>Basic understanding of YAML syntax</li>
<li>Familiarity with command-line interface</li>
<li>Text editor or IDE for writing playbooks</li>
</ul>
<div id="output-tab" class="tab-content">
<h3>Deployment Output</h3>
<p>Output will appear here when you deploy...</p>
</div>
<div class="docs-subsection">
<h3 class="docs-subsection-title">Required Knowledge</h3>
<p class="docs-text">
While no prior Ansible experience is required, basic understanding of the following concepts will be
helpful:
</p>
<ul class="docs-list">
<li>Linux/Unix command line basics</li>
<li>SSH and basic networking concepts</li>
<li>Version control with Git (optional)</li>
</ul>
</div>
</section>
<section id="quick-start" class="docs-section">
<h2 class="docs-section-title">Quick Start Guide</h2>
<div class="docs-warning">
<div class="docs-warning-title">
<i class="fas fa-exclamation-triangle"></i>
Important
<div id="status-tab" class="tab-content">
<h3>Deployment Status</h3>
<div class="preview-status">
<div class="status-dot status-ready"></div>
<span>Ready to deploy</span>
</div>
<div class="time-remaining">
<div>Sandbox environment ready</div>
</div>
<div class="time-progress">
<div class="time-progress-bar"></div>
</div>
<p>Make sure you have completed the initial setup and have your credentials ready before proceeding.</p>
</div>
<div class="docs-subsection">
<h3 class="docs-subsection-title">Getting Started Steps</h3>
<ol class="docs-list">
<li>Log in to your ArgoBox environment</li>
<li>Navigate to the Ansible Sandbox section</li>
<li>Create your first playbook using the provided templates</li>
<li>Test your playbook in the sandbox environment</li>
</ol>
</div>
<div class="docs-code">
<pre>
# Example playbook structure
---
- name: My First Playbook
hosts: sandbox
tasks:
- name: Ensure Apache is installed
ansible.builtin.package:
name: apache2
state: present</pre>
</div>
</section>
<section id="sandbox-environment" class="docs-section">
<h2 class="docs-section-title">Sandbox Environment</h2>
<p class="docs-text">
Our sandbox environment provides a fully isolated space where you can experiment with Ansible playbooks
without affecting production systems. The environment includes multiple target hosts, common services, and
pre-configured inventory files.
</p>
<div class="docs-subsection">
<h3 class="docs-subsection-title">Available Resources</h3>
<table class="docs-table">
<thead>
<tr>
<th>Resource</th>
<th>Description</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Control Node</td>
<td>Main Ansible control server</td>
<td>Available</td>
</tr>
<tr>
<td>Target Hosts</td>
<td>3 Ubuntu servers for testing</td>
<td>Available</td>
</tr>
<tr>
<td>Example Playbooks</td>
<td>Pre-configured templates</td>
<td>Available</td>
</tr>
</tbody>
</table>
</div>
</section>
<div class="docs-section">
<a href="construction.html" class="docs-button">
<i class="fas fa-book"></i>
View Full Documentation
</a>
</div>
</main>
<div class="sandbox-controls">
<button id="deploy-btn" class="btn btn-primary">
<i class="fas fa-play"></i> Deploy Playbook
</button>
<button id="reset-btn" class="btn btn-outline">
<i class="fas fa-redo"></i> Reset Environment
</button>
</div>
</div>
</div>
<button class="mobile-menu-toggle">
@ -1453,64 +1542,21 @@
<!-- JavaScript -->
<script>
document.addEventListener('DOMContentLoaded', function() {
// Set current year for copyright
document.getElementById('current-year').textContent = new Date().getFullYear();
// Mobile menu toggle
const menuToggle = document.getElementById('menuToggle');
const navMenu = document.getElementById('navMenu');
menuToggle.addEventListener('click', function() {
navMenu.classList.toggle('show');
const icon = menuToggle.querySelector('i');
if (navMenu.classList.contains('show')) {
icon.classList.remove('fa-bars');
icon.classList.add('fa-times');
} else {
icon.classList.remove('fa-times');
icon.classList.add('fa-bars');
}
});
// Tab switching
// Get the tabs and tab contents
const tabs = document.querySelectorAll('.preview-tab');
const tabContents = document.querySelectorAll('.tab-content');
// Tab switching functionality
tabs.forEach(tab => {
tab.addEventListener('click', function() {
const tabId = this.getAttribute('data-tab');
tab.addEventListener('click', () => {
const target = tab.getAttribute('data-tab');
// Hide all tabs and show the selected one
tabs.forEach(t => t.classList.remove('active'));
tabContents.forEach(tc => tc.classList.remove('active'));
this.classList.add('active');
document.getElementById(`${tabId}-tab`).classList.add('active');
});
});
// Playbook selection
const playbooks = document.querySelectorAll('.playbook-card');
const previewTitle = document.querySelector('.preview-title span');
playbooks.forEach(playbook => {
playbook.addEventListener('click', function() {
playbooks.forEach(p => p.classList.remove('active'));
this.classList.add('active');
const playbookName = this.querySelector('.playbook-title').textContent;
previewTitle.textContent = playbookName;
// Reset status
const statusIndicator = document.querySelector('.preview-status');
statusIndicator.innerHTML = '<div class="status-dot status-ready"></div><span>Ready to deploy</span>';
// Switch back to code tab
tabs.forEach(t => t.classList.remove('active'));
tabContents.forEach(tc => tc.classList.remove('active'));
document.querySelector('[data-tab="code"]').classList.add('active');
document.getElementById('code-tab').classList.add('active');
tab.classList.add('active');
document.getElementById(`${target}-tab`).classList.add('active');
});
});
@ -1519,83 +1565,93 @@
const resetBtn = document.getElementById('reset-btn');
const statusIndicator = document.querySelector('.preview-status');
deployBtn.addEventListener('click', function() {
// Show the "running" tab
tabs.forEach(t => t.classList.remove('active'));
tabContents.forEach(tc => tc.classList.remove('active'));
document.querySelector('[data-tab="output"]').classList.add('active');
document.getElementById('output-tab').classList.add('active');
// Update status to "running"
statusIndicator.innerHTML = '<div class="status-dot status-running"></div><span>Deploying...</span>';
// Disable the deploy button while "running"
deployBtn.disabled = true;
deployBtn.style.opacity = "0.7";
deployBtn.style.cursor = "not-allowed";
// Simulate a delay for deployment
setTimeout(function() {
// Update status to "success"
statusIndicator.innerHTML = '<div class="status-dot status-success"></div><span>Deployment successful</span>';
if (deployBtn) {
deployBtn.addEventListener('click', function() {
// Show the "running" tab
if (tabs && tabs.length > 0) {
tabs.forEach(t => t.classList.remove('active'));
}
if (tabContents && tabContents.length > 0) {
tabContents.forEach(tc => tc.classList.remove('active'));
}
// Re-enable the deploy button
deployBtn.disabled = false;
deployBtn.style.opacity = "1";
deployBtn.style.cursor = "pointer";
const outputTab = document.querySelector('[data-tab="output"]');
const outputTabContent = document.getElementById('output-tab');
if (outputTab) outputTab.classList.add('active');
if (outputTabContent) outputTabContent.classList.add('active');
// Switch to the VM status tab
tabs.forEach(t => t.classList.remove('active'));
tabContents.forEach(tc => tc.classList.remove('active'));
// Update status to "running"
if (statusIndicator) {
statusIndicator.innerHTML = '<div class="status-dot status-running"></div><span>Deploying...</span>';
}
document.querySelector('[data-tab="status"]').classList.add('active');
document.getElementById('status-tab').classList.add('active');
// Disable the deploy button while "running"
deployBtn.disabled = true;
deployBtn.style.opacity = "0.7";
deployBtn.style.cursor = "not-allowed";
// Start the countdown timer simulation
let timeLeft = 15; // minutes
const timeRemainingDiv = document.querySelector('.time-remaining div');
const timeProgressBar = document.querySelector('.time-progress-bar');
// For demo purposes, we'll just set the initial values
timeRemainingDiv.textContent = "Sandbox environment active for 15 more minutes";
timeProgressBar.style.width = "100%";
// In a real implementation, you would use setInterval to update the countdown
// This is left commented out to avoid unnecessary timer in the demo
/*
const countdownInterval = setInterval(function() {
timeLeft -= 1;
const width = (timeLeft / 15) * 100;
if (timeLeft <= 0) {
clearInterval(countdownInterval);
timeRemainingDiv.textContent = "Sandbox environment expired";
timeProgressBar.style.width = "0%";
// Reset status
statusIndicator.innerHTML = '<div class="status-dot status-ready"></div><span>Ready to deploy</span>';
} else {
timeRemainingDiv.textContent = `Sandbox environment active for ${timeLeft} more minutes`;
timeProgressBar.style.width = `${width}%`;
// Simulate a delay for deployment
setTimeout(function() {
// Update status to "success"
if (statusIndicator) {
statusIndicator.innerHTML = '<div class="status-dot status-success"></div><span>Deployment successful</span>';
}
}, 60000); // Update every minute
*/
}, 3000); // Simulate 3 second deployment
});
// Re-enable the deploy button
deployBtn.disabled = false;
deployBtn.style.opacity = "1";
deployBtn.style.cursor = "pointer";
// Switch to the VM status tab
if (tabs && tabs.length > 0) {
tabs.forEach(t => t.classList.remove('active'));
}
if (tabContents && tabContents.length > 0) {
tabContents.forEach(tc => tc.classList.remove('active'));
}
const statusTab = document.querySelector('[data-tab="status"]');
const statusTabContent = document.getElementById('status-tab');
if (statusTab) statusTab.classList.add('active');
if (statusTabContent) statusTabContent.classList.add('active');
// Start the countdown timer simulation
const timeRemainingDiv = document.querySelector('.time-remaining div');
const timeProgressBar = document.querySelector('.time-progress-bar');
// For demo purposes, we'll just set the initial values
if (timeRemainingDiv) {
timeRemainingDiv.textContent = "Sandbox environment active for 15 more minutes";
}
if (timeProgressBar) {
timeProgressBar.style.width = "100%";
}
}, 3000); // Simulate 3 second deployment
});
}
// Reset button
resetBtn.addEventListener('click', function() {
// Reset status
statusIndicator.innerHTML = '<div class="status-dot status-ready"></div><span>Ready to deploy</span>';
// Switch back to code tab
tabs.forEach(t => t.classList.remove('active'));
tabContents.forEach(tc => tc.classList.remove('active'));
document.querySelector('[data-tab="code"]').classList.add('active');
document.getElementById('code-tab').classList.add('active');
});
if (resetBtn) {
resetBtn.addEventListener('click', function() {
// Reset status
if (statusIndicator) {
statusIndicator.innerHTML = '<div class="status-dot status-ready"></div><span>Ready to deploy</span>';
}
// Switch back to code tab
if (tabs && tabs.length > 0) {
tabs.forEach(t => t.classList.remove('active'));
}
if (tabContents && tabContents.length > 0) {
tabContents.forEach(tc => tc.classList.remove('active'));
}
const codeTab = document.querySelector('[data-tab="code"]');
const codeTabContent = document.getElementById('code-tab');
if (codeTab) codeTab.classList.add('active');
if (codeTabContent) codeTabContent.classList.add('active');
});
}
});
</script>
</body>

View File

@ -111,7 +111,7 @@
</div>
</div>
<div class="cta-buttons">
<a href="ansible-sandbox.html" class="btn btn-primary">
<a href="ansible-sandbox.html" class="btn btn-primary" target="_blank">
<i class="fab fa-ansible btn-icon"></i>
<span class="btn-text">Try Ansible Sandbox</span>
</a>