Refactor Ansible documentation and dashboard: Removed debug scripts, redesigned navigation and sidebar for improved user experience, added simulation mode toggle, and enhanced mobile responsiveness. Updated footer and alert popups for better functionality and visual consistency.
This commit is contained in:
parent
7d9df34dde
commit
c1a57b7694
|
@ -1,10 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script>
|
||||
console.log("DEBUG: ansible-docs.html is being loaded");
|
||||
// You can check this in your browser's developer console
|
||||
</script>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Ansible Sandbox Documentation | Argobox</title>
|
||||
|
@ -44,7 +40,6 @@
|
|||
--card-hover-bg: rgba(30, 41, 59, 0.95);
|
||||
--card-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3);
|
||||
--transition-normal: 0.3s ease;
|
||||
--glass-effect: blur(10px);
|
||||
}
|
||||
|
||||
* {
|
||||
|
@ -63,255 +58,333 @@
|
|||
radial-gradient(circle at 75% 60%, rgba(14, 165, 233, 0.1) 0%, transparent 50%);
|
||||
}
|
||||
|
||||
.navbar {
|
||||
background-color: rgba(15, 23, 42, 0.9);
|
||||
backdrop-filter: var(--glass-effect);
|
||||
-webkit-backdrop-filter: var(--glass-effect);
|
||||
.docs-container {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 280px;
|
||||
background-color: var(--sidebar-bg);
|
||||
border-right: 1px solid var(--border);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
padding: 1.25rem 0;
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--border) transparent;
|
||||
padding: 2rem 0;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.sidebar::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.sidebar::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.sidebar::-webkit-scrollbar-thumb {
|
||||
background-color: var(--border);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
padding: 0 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.back-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
color: var(--accent);
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
padding: 0.5rem 0;
|
||||
transition: all var(--transition-normal);
|
||||
}
|
||||
|
||||
.back-link:hover {
|
||||
color: var(--accent-darker);
|
||||
transform: translateX(-3px);
|
||||
}
|
||||
|
||||
.sidebar-section {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.sidebar-section-title {
|
||||
font-weight: 600;
|
||||
font-size: 0.85rem;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-secondary);
|
||||
letter-spacing: 0.05em;
|
||||
padding: 0 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.sidebar-nav {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.sidebar-nav-item {
|
||||
transition: all var(--transition-normal);
|
||||
}
|
||||
|
||||
.sidebar-nav-link {
|
||||
display: block;
|
||||
padding: 0.5rem 1.5rem;
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
transition: all var(--transition-normal);
|
||||
position: relative;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.sidebar-nav-link:hover {
|
||||
color: var(--text-primary);
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.sidebar-nav-link.active {
|
||||
color: var(--accent);
|
||||
background-color: rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
.sidebar-nav-link.active::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 3px;
|
||||
background: var(--accent-gradient);
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
margin-left: 280px;
|
||||
padding: 3rem;
|
||||
max-width: 1000px;
|
||||
}
|
||||
|
||||
.docs-header {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.docs-title {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.docs-subtitle {
|
||||
color: var(--text-secondary);
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.docs-section {
|
||||
margin-bottom: 3rem;
|
||||
scroll-margin-top: 2rem;
|
||||
}
|
||||
|
||||
.docs-section-title {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 1.5rem;
|
||||
color: var(--text-primary);
|
||||
position: relative;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.navbar .container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 0 1.5rem;
|
||||
.docs-subsection {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.logo a {
|
||||
color: var(--text-primary);
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.logo-text {
|
||||
background: var(--accent-gradient);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
font-size: 1.5rem;
|
||||
.docs-subsection-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.logo-dot {
|
||||
color: var(--text-secondary);
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.nav-menu {
|
||||
display: flex;
|
||||
gap: 2.5rem;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
transition: all var(--transition-normal);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-link.active,
|
||||
.nav-link:hover {
|
||||
margin-bottom: 1rem;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.nav-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.25rem;
|
||||
.docs-text {
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.dashboard-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.625rem 1.25rem;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
background-color: rgba(59, 130, 246, 0.1);
|
||||
border: 1px solid rgba(59, 130, 246, 0.2);
|
||||
.docs-list {
|
||||
list-style-type: disc;
|
||||
margin-left: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.docs-list li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.docs-code {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
background-color: var(--sidebar-bg);
|
||||
padding: 1.5rem;
|
||||
border-radius: 0.5rem;
|
||||
overflow-x: auto;
|
||||
margin-bottom: 1.5rem;
|
||||
border: 1px solid var(--border);
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.docs-code pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.docs-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.docs-table th {
|
||||
text-align: left;
|
||||
padding: 0.75rem 1rem;
|
||||
background-color: var(--sidebar-bg);
|
||||
color: var(--text-primary);
|
||||
font-weight: 600;
|
||||
border-bottom: 2px solid var(--border);
|
||||
}
|
||||
|
||||
.docs-table td {
|
||||
padding: 0.75rem 1rem;
|
||||
border-bottom: 1px solid var(--border);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.docs-note {
|
||||
background-color: rgba(59, 130, 246, 0.1);
|
||||
border-left: 4px solid var(--accent);
|
||||
padding: 1rem 1.5rem;
|
||||
border-radius: 0 0.5rem 0.5rem 0;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.docs-note-title {
|
||||
font-weight: 600;
|
||||
color: var(--accent);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.docs-warning {
|
||||
background-color: rgba(245, 158, 11, 0.1);
|
||||
border-left: 4px solid var(--warning);
|
||||
padding: 1rem 1.5rem;
|
||||
border-radius: 0 0.5rem 0.5rem 0;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.docs-warning-title {
|
||||
font-weight: 600;
|
||||
color: var(--warning);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.docs-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
background-color: var(--accent);
|
||||
color: white;
|
||||
padding: 0.75rem 1.25rem;
|
||||
border-radius: 0.5rem;
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
transition: all var(--transition-normal);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.dashboard-link:hover {
|
||||
.docs-button:hover {
|
||||
background-color: var(--accent-darker);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--card-shadow);
|
||||
}
|
||||
|
||||
.navbar .menu-toggle {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--text-primary);
|
||||
font-size: 1.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.navbar .menu-toggle i {
|
||||
transition: transform var(--transition-normal);
|
||||
}
|
||||
|
||||
.navbar .nav-menu.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.footer {
|
||||
background-color: var(--secondary-bg);
|
||||
padding: 2rem;
|
||||
color: var(--text-secondary);
|
||||
.docs-footer {
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.footer .container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.footer .footer-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.footer .footer-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.footer .footer-logo .logo-text {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.footer .footer-logo .logo-dot {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.footer .footer-links {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.footer .footer-links a {
|
||||
margin-top: 3rem;
|
||||
padding-top: 2rem;
|
||||
color: var(--text-secondary);
|
||||
text-decoration: none;
|
||||
font-size: 0.9rem;
|
||||
transition: color var(--transition-normal);
|
||||
}
|
||||
|
||||
.footer .footer-links a:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.footer .footer-social {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.footer .footer-social a {
|
||||
color: var(--text-secondary);
|
||||
font-size: 1.2rem;
|
||||
transition: color var(--transition-normal);
|
||||
}
|
||||
|
||||
.footer .footer-social a:hover {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.footer .footer-bottom {
|
||||
text-align: center;
|
||||
font-size: 0.9rem;
|
||||
.mobile-menu-toggle {
|
||||
display: none;
|
||||
position: fixed;
|
||||
bottom: 1.5rem;
|
||||
right: 1.5rem;
|
||||
background: var(--accent-gradient);
|
||||
color: white;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
position: fixed;
|
||||
bottom: 1.5rem;
|
||||
right: 1.5rem;
|
||||
background: var(--accent-gradient);
|
||||
color: white;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 1.5rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 20;
|
||||
box-shadow: var(--card-shadow);
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.navbar .nav-menu {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
background-color: var(--secondary-bg);
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
width: 200px;
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 0.5rem;
|
||||
.sidebar {
|
||||
transform: translateX(-100%);
|
||||
transition: transform var(--transition-normal);
|
||||
}
|
||||
|
||||
.navbar .nav-menu.show {
|
||||
.sidebar.active {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.main-content {
|
||||
margin-left: 0;
|
||||
padding: 2rem 1.5rem;
|
||||
}
|
||||
|
||||
.mobile-menu-toggle {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation Bar -->
|
||||
<nav class="navbar">
|
||||
<div class="container">
|
||||
<div class="logo">
|
||||
<a href="#home">
|
||||
<span class="logo-text-glow">ArgoBox</span><span class="logo-dot-glow">.com</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="nav-menu">
|
||||
<a href="#home" class="nav-link active">Home</a>
|
||||
<a href="#services" class="nav-link">Services</a>
|
||||
<a href="#lab" class="nav-link">Live Lab</a>
|
||||
<a href="#projects" class="nav-link">Projects</a>
|
||||
<a href="#experience" class="nav-link">Experience</a>
|
||||
<a href="#contact" class="nav-link">Contact</a>
|
||||
</div>
|
||||
<div class="nav-buttons">
|
||||
<a href="https://dashboard.argobox.com" class="dashboard-link" target="_blank">
|
||||
<span class="live-indicator"></span>
|
||||
<span>Live Dashboard</span>
|
||||
</a>
|
||||
<button class="menu-toggle" aria-label="Toggle menu">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Top Links -->
|
||||
<div class="top-links">
|
||||
<a href="https://laforceit.com" class="laforceit-link">
|
||||
<span class="logo-text-glow">LaForceIT</span><span class="logo-dot-glow">.com</span>
|
||||
</a>
|
||||
<a href="https://login.argobox.com" class="signin-button" target="_blank">
|
||||
<i class="fas fa-sign-in-alt"></i>
|
||||
<span>Sign In</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Under Construction Warning -->
|
||||
<div class="construction-warning">
|
||||
<div class="warning-content">
|
||||
<i class="fas fa-hard-hat"></i>
|
||||
<h2>Under Construction</h2>
|
||||
<p>This page is currently being developed. Some features may not be fully functional.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="docs-container">
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
|
@ -764,39 +837,18 @@ web-server/
|
|||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="docs-footer">
|
||||
<p>
|
||||
For questions or suggestions about the Ansible Sandbox, please contact <a href="mailto:contact@argobox.com">contact@argobox.com</a>.
|
||||
</p>
|
||||
<p>
|
||||
© <span id="current-year">2025</span> Argobox.com. All rights reserved.
|
||||
</p>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="footer-content">
|
||||
<div class="footer-logo">
|
||||
<span class="logo-text">Argobox</span>
|
||||
<span class="logo-dot">.com</span>
|
||||
</div>
|
||||
|
||||
<div class="footer-links">
|
||||
<a href="index.html#home">Home</a>
|
||||
<a href="index.html#services">Services</a>
|
||||
<a href="index.html#lab">Live Lab</a>
|
||||
<a href="index.html#projects">Projects</a>
|
||||
<a href="index.html#contact">Contact</a>
|
||||
</div>
|
||||
|
||||
<div class="footer-social">
|
||||
<a href="https://github.com/keyargo" target="_blank" aria-label="GitHub"><i class="fab fa-github"></i></a>
|
||||
<a href="https://www.linkedin.com/in/danlaforce" target="_blank" aria-label="LinkedIn"><i class="fab fa-linkedin"></i></a>
|
||||
<a href="mailto:daniel.laforce@argobox.com" aria-label="Email"><i class="fas fa-envelope"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-bottom">
|
||||
<p>© <span id="current-year"></span> All rights reserved. Inovin LLC</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<button class="mobile-menu-toggle">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
|
@ -882,23 +934,6 @@ web-server/
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Add mobile menu toggle functionality
|
||||
const menuToggleNav = document.querySelector('.menu-toggle');
|
||||
const navMenu = document.querySelector('.nav-menu');
|
||||
|
||||
menuToggleNav.addEventListener('click', function() {
|
||||
navMenu.classList.toggle('show');
|
||||
const icon = menuToggleNav.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');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
|
2702
ansible-sandbox.html
2702
ansible-sandbox.html
File diff suppressed because it is too large
Load Diff
524
dashboard.html
524
dashboard.html
|
@ -989,6 +989,220 @@
|
|||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Simulation toggle */
|
||||
.simulation-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.toggle-switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 46px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.toggle-switch input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.toggle-slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(148, 163, 184, 0.2);
|
||||
transition: .4s;
|
||||
border-radius: 24px;
|
||||
}
|
||||
|
||||
.toggle-slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
background-color: var(--text-secondary);
|
||||
transition: .4s;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
input:checked + .toggle-slider {
|
||||
background-color: rgba(59, 130, 246, 0.3);
|
||||
}
|
||||
|
||||
input:checked + .toggle-slider:before {
|
||||
transform: translateX(22px);
|
||||
background-color: var(--accent);
|
||||
}
|
||||
|
||||
.toggle-label {
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-secondary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.toggle-status {
|
||||
font-weight: 600;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* Status indicators - including offline state */
|
||||
.live-indicator.offline {
|
||||
background-color: var(--error);
|
||||
}
|
||||
|
||||
.live-indicator.offline::after {
|
||||
background-color: var(--error);
|
||||
}
|
||||
|
||||
.live-indicator-label.offline {
|
||||
background-color: rgba(239, 68, 68, 0.1);
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
/* Popup styles for settings and alerts */
|
||||
.popup-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(15, 23, 42, 0.8);
|
||||
backdrop-filter: blur(5px);
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
z-index: 1001;
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.popup-container {
|
||||
background-color: var(--secondary-bg);
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: var(--card-shadow);
|
||||
width: 90%;
|
||||
max-width: 500px;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.popup-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 1.25rem 1.5rem;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.popup-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.popup-close {
|
||||
font-size: 1.5rem;
|
||||
cursor: pointer;
|
||||
color: var(--text-secondary);
|
||||
transition: color var(--transition-normal);
|
||||
}
|
||||
|
||||
.popup-close:hover {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
/* Settings popup */
|
||||
.settings-section {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.settings-section:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.settings-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.settings-option {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.75rem 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.settings-option:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.settings-label {
|
||||
font-size: 0.95rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* Alerts popup */
|
||||
.alert-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.alert-item {
|
||||
background-color: rgba(30, 41, 59, 0.5);
|
||||
border-radius: 0.5rem;
|
||||
padding: 1rem;
|
||||
border-left: 3px solid var(--accent);
|
||||
}
|
||||
|
||||
.alert-item.error {
|
||||
border-left-color: var(--error);
|
||||
}
|
||||
|
||||
.alert-item.warning {
|
||||
border-left-color: var(--warning);
|
||||
}
|
||||
|
||||
.alert-item.success {
|
||||
border-left-color: var(--success);
|
||||
}
|
||||
|
||||
.alert-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.alert-title {
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.alert-time {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.alert-message {
|
||||
font-size: 0.9rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -1030,18 +1244,26 @@
|
|||
<span class="live-dot"></span>
|
||||
<span>Live</span>
|
||||
</div>
|
||||
<div class="simulation-toggle">
|
||||
<span class="toggle-label">Simulation Mode:</span>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" id="simulation-toggle">
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
<span class="toggle-status">Inactive</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-actions">
|
||||
<button class="dashboard-btn">
|
||||
<button class="dashboard-btn" id="refresh-btn">
|
||||
<i class="fas fa-sync-alt"></i>
|
||||
<span>Refresh</span>
|
||||
</button>
|
||||
<button class="dashboard-btn">
|
||||
<button class="dashboard-btn" id="alerts-btn">
|
||||
<i class="fas fa-bell"></i>
|
||||
<span>Alerts</span>
|
||||
</button>
|
||||
<button class="dashboard-btn">
|
||||
<button class="dashboard-btn" id="settings-btn">
|
||||
<i class="fas fa-cog"></i>
|
||||
<span>Settings</span>
|
||||
</button>
|
||||
|
@ -1386,6 +1608,144 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Settings Popup -->
|
||||
<div class="popup-overlay" id="settings-popup">
|
||||
<div class="popup-container">
|
||||
<div class="popup-header">
|
||||
<h3 class="popup-title">Dashboard Settings</h3>
|
||||
<div class="popup-close" id="close-settings">×</div>
|
||||
</div>
|
||||
<div class="popup-content">
|
||||
<div class="settings-section">
|
||||
<h4 class="settings-title">Display Options</h4>
|
||||
<div class="settings-option">
|
||||
<span class="settings-label">Dark mode</span>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="settings-option">
|
||||
<span class="settings-label">Auto-refresh</span>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="settings-option">
|
||||
<span class="settings-label">Refresh interval</span>
|
||||
<select class="settings-select">
|
||||
<option value="30">30 seconds</option>
|
||||
<option value="60" selected>1 minute</option>
|
||||
<option value="300">5 minutes</option>
|
||||
<option value="600">10 minutes</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-section">
|
||||
<h4 class="settings-title">Data Visualization</h4>
|
||||
<div class="settings-option">
|
||||
<span class="settings-label">Show metrics in header</span>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="settings-option">
|
||||
<span class="settings-label">Chart animation</span>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-section">
|
||||
<h4 class="settings-title">Notifications</h4>
|
||||
<div class="settings-option">
|
||||
<span class="settings-label">Email alerts</span>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox">
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="settings-option">
|
||||
<span class="settings-label">Browser notifications</span>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="settings-option">
|
||||
<span class="settings-label">Notify on system events</span>
|
||||
<label class="toggle-switch">
|
||||
<input type="checkbox" checked>
|
||||
<span class="toggle-slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alerts Popup -->
|
||||
<div class="popup-overlay" id="alerts-popup">
|
||||
<div class="popup-container">
|
||||
<div class="popup-header">
|
||||
<h3 class="popup-title">System Alerts</h3>
|
||||
<div class="popup-close" id="close-alerts">×</div>
|
||||
</div>
|
||||
<div class="popup-content">
|
||||
<div class="alert-list">
|
||||
<div class="alert-item warning">
|
||||
<div class="alert-header">
|
||||
<div class="alert-title">Memory usage above 70%</div>
|
||||
<div class="alert-time">20 minutes ago</div>
|
||||
</div>
|
||||
<div class="alert-message">
|
||||
The system memory usage has exceeded 70% threshold. Consider optimizing applications or adding more memory.
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert-item error">
|
||||
<div class="alert-header">
|
||||
<div class="alert-title">Container restart detected</div>
|
||||
<div class="alert-time">35 minutes ago</div>
|
||||
</div>
|
||||
<div class="alert-message">
|
||||
The "nginx-proxy" container has been restarted unexpectedly. Check the logs for more information.
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert-item info">
|
||||
<div class="alert-header">
|
||||
<div class="alert-title">System update available</div>
|
||||
<div class="alert-time">1 hour ago</div>
|
||||
</div>
|
||||
<div class="alert-message">
|
||||
A new system update is available for your server. Consider scheduling a maintenance window.
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert-item success">
|
||||
<div class="alert-header">
|
||||
<div class="alert-title">Backup completed successfully</div>
|
||||
<div class="alert-time">2 hours ago</div>
|
||||
</div>
|
||||
<div class="alert-message">
|
||||
Daily backup has been completed successfully. 12.3 GB of data has been backed up.
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert-item warning">
|
||||
<div class="alert-header">
|
||||
<div class="alert-title">Disk space running low</div>
|
||||
<div class="alert-time">3 hours ago</div>
|
||||
</div>
|
||||
<div class="alert-message">
|
||||
The "/data" partition is at 85% capacity. Consider cleaning up unused files or expanding storage.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
|
@ -1466,12 +1826,72 @@
|
|||
});
|
||||
|
||||
// Refresh button functionality
|
||||
const refreshBtn = document.querySelector('.dashboard-btn');
|
||||
const refreshBtn = document.getElementById('refresh-btn');
|
||||
|
||||
refreshBtn.addEventListener('click', function() {
|
||||
simulateRefresh();
|
||||
});
|
||||
|
||||
// Initialize simulation toggle
|
||||
const toggleInput = document.getElementById('simulation-toggle');
|
||||
const toggleStatus = document.querySelector('.toggle-status');
|
||||
const liveIndicator = document.querySelector('.live-dot');
|
||||
const liveLabel = document.querySelector('.live-indicator-label');
|
||||
|
||||
toggleInput.addEventListener('change', function() {
|
||||
if(this.checked) {
|
||||
toggleStatus.textContent = 'Active';
|
||||
document.body.classList.add('simulation-mode');
|
||||
liveIndicator.classList.add('offline');
|
||||
liveLabel.classList.add('offline');
|
||||
liveLabel.querySelector('span:last-child').textContent = 'Offline';
|
||||
} else {
|
||||
toggleStatus.textContent = 'Inactive';
|
||||
document.body.classList.remove('simulation-mode');
|
||||
liveIndicator.classList.remove('offline');
|
||||
liveLabel.classList.remove('offline');
|
||||
liveLabel.querySelector('span:last-child').textContent = 'Live';
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize simulation as active by default for demonstration
|
||||
toggleInput.checked = true;
|
||||
toggleInput.dispatchEvent(new Event('change'));
|
||||
|
||||
// Set up settings and alerts popup functionality
|
||||
const settingsBtn = document.getElementById('settings-btn');
|
||||
const alertsBtn = document.getElementById('alerts-btn');
|
||||
const settingsPopup = document.getElementById('settings-popup');
|
||||
const alertsPopup = document.getElementById('alerts-popup');
|
||||
const closeSettings = document.getElementById('close-settings');
|
||||
const closeAlerts = document.getElementById('close-alerts');
|
||||
|
||||
settingsBtn.addEventListener('click', function() {
|
||||
settingsPopup.style.display = 'flex';
|
||||
});
|
||||
|
||||
alertsBtn.addEventListener('click', function() {
|
||||
alertsPopup.style.display = 'flex';
|
||||
});
|
||||
|
||||
closeSettings.addEventListener('click', function() {
|
||||
settingsPopup.style.display = 'none';
|
||||
});
|
||||
|
||||
closeAlerts.addEventListener('click', function() {
|
||||
alertsPopup.style.display = 'none';
|
||||
});
|
||||
|
||||
// Close popups when clicking outside
|
||||
window.addEventListener('click', function(e) {
|
||||
if (e.target === settingsPopup) {
|
||||
settingsPopup.style.display = 'none';
|
||||
}
|
||||
if (e.target === alertsPopup) {
|
||||
alertsPopup.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Set up simulation of real-time data
|
||||
function simulateRefresh() {
|
||||
// Update metrics with random variations
|
||||
|
@ -1481,7 +1901,7 @@
|
|||
updateOverviewCard('Network', 15, 40);
|
||||
|
||||
// Update last refresh time
|
||||
document.getElementById('last-refresh').textContent = 'Just now';
|
||||
document.querySelector('.services-refresh span').textContent = 'Last updated: Just now';
|
||||
|
||||
// Add a new log entry
|
||||
addLogEntry();
|
||||
|
@ -1523,8 +1943,11 @@
|
|||
|
||||
function addLogEntry() {
|
||||
const logsContent = document.querySelector('.logs-content');
|
||||
|
||||
// Get current time in MST (UTC-7)
|
||||
const now = new Date();
|
||||
const timeString = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
|
||||
const mstTime = new Date(now.getTime() - (7 * 60 * 60 * 1000)); // Convert to MST
|
||||
const timeString = `${mstTime.getHours().toString().padStart(2, '0')}:${mstTime.getMinutes().toString().padStart(2, '0')}:${mstTime.getSeconds().toString().padStart(2, '0')}`;
|
||||
|
||||
const logTypes = ['info', 'success', 'warning', 'error'];
|
||||
const logType = logTypes[Math.floor(Math.random() * logTypes.length)];
|
||||
|
@ -1537,7 +1960,13 @@
|
|||
'Disk space cleanup completed',
|
||||
'User session timeout',
|
||||
'API rate limit approaching',
|
||||
'Security scan completed'
|
||||
'Security scan completed',
|
||||
'Database connection pool refreshed',
|
||||
'Cache invalidation triggered',
|
||||
'SSL certificate validity verified',
|
||||
'User authentication succeeded',
|
||||
'Scheduled task executed',
|
||||
'Configuration updated'
|
||||
];
|
||||
|
||||
const logMessage = logMessages[Math.floor(Math.random() * logMessages.length)];
|
||||
|
@ -1551,15 +1980,96 @@
|
|||
`;
|
||||
|
||||
logsContent.insertBefore(logEntry, logsContent.firstChild);
|
||||
|
||||
// Keep only the last 20 log entries
|
||||
const allEntries = logsContent.querySelectorAll('.log-entry');
|
||||
if (allEntries.length > 20) {
|
||||
for (let i = 20; i < allEntries.length; i++) {
|
||||
logsContent.removeChild(allEntries[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mobile menu toggle
|
||||
const menuToggle = document.querySelector('.menu-toggle');
|
||||
const navMenu = document.querySelector('.nav-menu');
|
||||
|
||||
if (menuToggle && navMenu) {
|
||||
menuToggle.addEventListener('click', function() {
|
||||
navMenu.classList.toggle('active');
|
||||
});
|
||||
}
|
||||
|
||||
// Generate initial log entries with timestamps ranging from 30-40 minutes ago to now
|
||||
function generateInitialLogs() {
|
||||
const logsContent = document.querySelector('.logs-content');
|
||||
if (!logsContent) return;
|
||||
|
||||
// Clear existing logs
|
||||
logsContent.innerHTML = '';
|
||||
|
||||
// Get current time in MST
|
||||
const now = new Date();
|
||||
const mstNow = new Date(now.getTime() - (7 * 60 * 60 * 1000)); // Convert to MST
|
||||
|
||||
// Generate entries from 40 minutes ago to now
|
||||
for (let i = 0; i < 15; i++) {
|
||||
const minutesAgo = Math.floor(Math.random() * 40) + 1; // 1-40 minutes ago
|
||||
const logTime = new Date(mstNow.getTime() - (minutesAgo * 60 * 1000));
|
||||
const timeString = `${logTime.getHours().toString().padStart(2, '0')}:${logTime.getMinutes().toString().padStart(2, '0')}:${logTime.getSeconds().toString().padStart(2, '0')}`;
|
||||
|
||||
const logTypes = ['info', 'success', 'warning', 'error'];
|
||||
const logType = logTypes[Math.floor(Math.random() * logTypes.length)];
|
||||
|
||||
const logMessages = [
|
||||
'System health check completed',
|
||||
'Container restarted automatically',
|
||||
'Network traffic spike detected',
|
||||
'Backup process initiated',
|
||||
'Disk space cleanup completed',
|
||||
'User session timeout',
|
||||
'API rate limit approaching',
|
||||
'Security scan completed',
|
||||
'Database connection pool refreshed',
|
||||
'Cache invalidation triggered',
|
||||
'SSL certificate validity verified',
|
||||
'User authentication succeeded',
|
||||
'Scheduled task executed',
|
||||
'Configuration updated'
|
||||
];
|
||||
|
||||
const logMessage = logMessages[Math.floor(Math.random() * logMessages.length)];
|
||||
|
||||
const logEntry = document.createElement('div');
|
||||
logEntry.className = 'log-entry';
|
||||
logEntry.innerHTML = `
|
||||
<span class="log-time">${timeString}</span>
|
||||
<span class="log-level log-level-${logType}">${logType.toUpperCase()}</span>
|
||||
<span class="log-message">${logMessage}</span>
|
||||
`;
|
||||
|
||||
// Sort logs by time (most recent at the top)
|
||||
if (logsContent.children.length === 0) {
|
||||
logsContent.appendChild(logEntry);
|
||||
} else {
|
||||
let inserted = false;
|
||||
for (let j = 0; j < logsContent.children.length; j++) {
|
||||
const existingTime = logsContent.children[j].querySelector('.log-time').textContent;
|
||||
if (timeString > existingTime) {
|
||||
logsContent.insertBefore(logEntry, logsContent.children[j]);
|
||||
inserted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!inserted) {
|
||||
logsContent.appendChild(logEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate initial logs
|
||||
generateInitialLogs();
|
||||
|
||||
// Auto refresh every 60 seconds
|
||||
setInterval(function() {
|
||||
|
|
|
@ -111,9 +111,10 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="cta-buttons">
|
||||
<a href="ansible-sandbox.html" class="btn btn-primary" target="_blank">
|
||||
<a href="ansible-sandbox.html" class="btn btn-danger" target="_blank">
|
||||
<i class="fab fa-ansible btn-icon"></i>
|
||||
<span class="btn-text">Try Ansible Sandbox</span>
|
||||
<span class="offline-badge">Offline</span>
|
||||
</a>
|
||||
<a href="#architecture" class="btn btn-outline">
|
||||
<i class="fas fa-network-wired btn-icon"></i>
|
||||
|
@ -468,9 +469,9 @@
|
|||
<h4 class="service-name">Ansible Sandbox</h4>
|
||||
<p class="service-description">Interactive environment for infrastructure automation</p>
|
||||
</div>
|
||||
<div class="service-status live">
|
||||
<div class="service-status offline">
|
||||
<span class="status-dot"></span>
|
||||
<span class="status-text">Public</span>
|
||||
<span class="status-text">Offline</span>
|
||||
</div>
|
||||
</a>
|
||||
<div class="service-item">
|
||||
|
@ -894,7 +895,7 @@
|
|||
</p>
|
||||
<div class="footer-evolution">
|
||||
<i class="fas fa-code-branch evolution-icon"></i>
|
||||
<span>Continuously evolving since 2013</span>
|
||||
<span>Continuously evolving since 2011</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
211
styles.css
211
styles.css
|
@ -2759,137 +2759,140 @@ section {
|
|||
}
|
||||
|
||||
/* Enhanced Mobile Optimizations */
|
||||
@media (max-width: 480px) {
|
||||
section {
|
||||
padding: 3rem 0;
|
||||
@media (max-width: 768px) {
|
||||
/* Improve readability on mobile */
|
||||
body {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1.75rem;
|
||||
/* Make buttons more tappable */
|
||||
.btn, .nav-link, .service-item, .tech-card, .project-card {
|
||||
padding: 0.8rem;
|
||||
}
|
||||
|
||||
.section-description {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
/* Architecture section mobile optimization */
|
||||
.architecture-diagram {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.diagram-wrapper {
|
||||
width: 100%;
|
||||
/* Better spacing for section headers on mobile */
|
||||
.section-header {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.architecture-details {
|
||||
width: 100%;
|
||||
.section-title {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
/* Improved mobile tech grid */
|
||||
.tech-grid {
|
||||
/* Improved hero section for mobile */
|
||||
.hero {
|
||||
padding: 6rem 0 3rem;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-size: 2rem;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.hero-description {
|
||||
font-size: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.cta-buttons {
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
/* Improved card layouts for touch */
|
||||
.tech-grid, .services-grid, .projects-grid, .dashboard-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.tech-card {
|
||||
padding: 1.5rem;
|
||||
.tech-card, .service-item, .project-card {
|
||||
padding: 1.25rem;
|
||||
}
|
||||
|
||||
/* Services optimization */
|
||||
.services-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.service-items {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
/* Contact form mobile friendly */
|
||||
.contact-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.contact-form {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
/* Top links mobile optimization */
|
||||
.top-links {
|
||||
padding: 0.5rem 1rem;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.laforceit-link, .signin-button {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
/* Projects section mobile */
|
||||
.projects-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
/* Dashboard section mobile */
|
||||
.dashboard-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Touch-friendly adjustments */
|
||||
@media (hover: none) {
|
||||
.btn:hover::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.service-item, .tech-card, .project-card, .dashboard-card {
|
||||
transition: transform 0.2s ease;
|
||||
/* Enhanced tap targets for touch */
|
||||
.service-item, .tech-card, .project-card, .dashboard-card, .footer-link {
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.service-item:active, .tech-card:active, .project-card:active, .dashboard-card:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.nav-link:active::after {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Improved scrolling for mobile */
|
||||
@media (max-width: 768px) {
|
||||
html {
|
||||
scroll-padding-top: var(--mobile-nav-height);
|
||||
/* Tablet-specific optimizations */
|
||||
@media (min-width: 481px) and (max-width: 1024px) {
|
||||
/* Two-column layouts for tablets */
|
||||
.tech-grid, .services-grid, .projects-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
/* Handle form inputs better on mobile */
|
||||
input, textarea, select, button {
|
||||
font-size: 16px !important; /* Prevents zoom on focus in iOS */
|
||||
/* Balanced spacing for tablets */
|
||||
section {
|
||||
padding: 4rem 0;
|
||||
}
|
||||
|
||||
/* Optimized footer for mobile */
|
||||
.footer-content {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.footer-info {
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
width: 100%;
|
||||
grid-template-columns: 1fr;
|
||||
/* Hero layout adjustments */
|
||||
.hero-content {
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.footer-links-column {
|
||||
text-align: center;
|
||||
/* Architecture diagram adjustments */
|
||||
.architecture-diagram {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Footer improvements */
|
||||
.footer-content {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
/* Phone-specific optimizations */
|
||||
@media (max-width: 480px) {
|
||||
.hero-stats {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
/* Single column layouts for phones */
|
||||
.contact-grid, .architecture-details {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
/* Improved form elements for touch */
|
||||
input, textarea, button {
|
||||
font-size: 16px; /* Prevents zoom on input focus on iOS */
|
||||
padding: 0.8rem;
|
||||
}
|
||||
|
||||
/* Navbar adjustments */
|
||||
.navbar .container {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Touch optimizations */
|
||||
@media (hover: none) {
|
||||
/* Disable hover effects on touch devices */
|
||||
.btn::before, .service-item:hover, .tech-card:hover {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
/* Use active states instead */
|
||||
.btn:active, .nav-link:active, .service-item:active {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* Larger tap targets */
|
||||
.nav-link, .footer-link, .dashboard-link {
|
||||
padding: 0.6rem;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue