Enhance user interface and functionality across multiple pages: Added contact information section with improved styling, updated footer layout for better organization, and implemented live indicators for system status. Enhanced navigation links and added offline notice for the dashboard. Improved overall responsiveness and visual consistency.
This commit is contained in:
parent
c1a57b7694
commit
3bb2816c7b
|
@ -382,6 +382,19 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contact-info {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-info p {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-email {
|
||||||
|
color: #60a5fa; /* Lighter blue color for better readability */
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -838,13 +851,55 @@ web-server/
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<footer class="docs-footer">
|
<!-- Footer -->
|
||||||
<p>
|
<footer class="footer">
|
||||||
For questions or suggestions about the Ansible Sandbox, please contact <a href="mailto:contact@argobox.com">contact@argobox.com</a>.
|
<div class="container">
|
||||||
</p>
|
<div class="footer-content">
|
||||||
<p>
|
<div class="footer-info">
|
||||||
© <span id="current-year">2025</span> Argobox.com. All rights reserved.
|
<div class="footer-logo">
|
||||||
</p>
|
<span class="logo-text-glow">ArgoBox</span>
|
||||||
|
<span class="logo-dot-glow">.com</span>
|
||||||
|
</div>
|
||||||
|
<p class="footer-description">
|
||||||
|
Enterprise-grade home lab environment for DevOps experimentation, infrastructure automation, and containerized application deployment.
|
||||||
|
</p>
|
||||||
|
<div class="footer-evolution">
|
||||||
|
<i class="fas fa-code-branch evolution-icon"></i>
|
||||||
|
<span>Continuously evolving since 2011</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-links">
|
||||||
|
<div class="footer-links-column">
|
||||||
|
<h3 class="footer-heading">Platforms</h3>
|
||||||
|
<a href="https://dashboard.argobox.com" class="footer-link">Dashboard</a>
|
||||||
|
<a href="ansible-sandbox.html" class="footer-link">Ansible Sandbox</a>
|
||||||
|
<a href="https://git.argobox.com" class="footer-link">Gitea</a>
|
||||||
|
<a href="https://ai.argobox.com" class="footer-link">OpenWebUI</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-links-column">
|
||||||
|
<h3 class="footer-heading">Documentation</h3>
|
||||||
|
<a href="construction.html" class="footer-link">Architecture</a>
|
||||||
|
<a href="construction.html" class="footer-link">Kubernetes</a>
|
||||||
|
<a href="construction.html" class="footer-link">Ansible</a>
|
||||||
|
<a href="construction.html" class="footer-link">Network</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-links-column">
|
||||||
|
<h3 class="footer-heading">Resources</h3>
|
||||||
|
<a href="construction.html" class="footer-link">Ansible Playbooks</a>
|
||||||
|
<a href="construction.html" class="footer-link">K8s Manifests</a>
|
||||||
|
<a href="construction.html" class="footer-link">Shell Scripts</a>
|
||||||
|
<a href="construction.html" class="footer-link">Configuration Files</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-bottom">
|
||||||
|
<p>© <span id="current-year"></span> All rights reserved. Inovin LLC</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -392,6 +392,81 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.live-indicator {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background-color: var(--success);
|
||||||
|
border-radius: 50%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.live-indicator.offline {
|
||||||
|
background-color: var(--error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.live-indicator::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: var(--success);
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.live-indicator.offline::after {
|
||||||
|
background-color: var(--error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-text-glow, .logo-dot-glow {
|
||||||
|
transition: all var(--transition-normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-text-glow {
|
||||||
|
text-shadow: 0 0 10px rgba(59, 130, 246, 0.5);
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-dot-glow {
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-links {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
gap: 1.5rem;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 1001;
|
||||||
|
}
|
||||||
|
|
||||||
|
.laforceit-link {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signin-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 0.25rem 0.75rem;
|
||||||
|
background: rgba(30, 41, 59, 0.8);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
transition: all var(--transition-normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.signin-button:hover {
|
||||||
|
background: rgba(30, 41, 59, 1);
|
||||||
|
border-color: var(--accent);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -400,21 +475,20 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<a href="index.html">
|
<a href="index.html">
|
||||||
<span class="logo-text">Argobox</span>
|
<span class="logo-text-glow">ArgoBox</span><span class="logo-dot-glow">.com</span>
|
||||||
<span class="logo-dot">.com</span>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-menu">
|
<div class="nav-menu">
|
||||||
<a href="index.html#home" class="nav-link">Home</a>
|
<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#services" class="nav-link">Services</a>
|
||||||
<a href="index.html#lab" class="nav-link active">Live Lab</a>
|
|
||||||
<a href="index.html#projects" class="nav-link">Projects</a>
|
<a href="index.html#projects" class="nav-link">Projects</a>
|
||||||
<a href="index.html#experience" class="nav-link">Experience</a>
|
<a href="index.html#dashboards" class="nav-link">Dashboards</a>
|
||||||
<a href="index.html#contact" class="nav-link">Contact</a>
|
<a href="index.html#contact" class="nav-link">Contact</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-buttons">
|
<div class="nav-buttons">
|
||||||
<a href="dashboard.html" class="dashboard-link" target="_blank">
|
<a href="https://dashboard.argobox.com" class="dashboard-link" target="_blank">
|
||||||
<span class="live-indicator"></span>
|
<span class="live-indicator offline"></span>
|
||||||
<span>Live Dashboard</span>
|
<span>Live Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
<button class="menu-toggle" aria-label="Toggle menu">
|
<button class="menu-toggle" aria-label="Toggle menu">
|
||||||
|
@ -424,6 +498,17 @@
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</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="construction.html" class="signin-button" target="_blank">
|
||||||
|
<i class="fas fa-sign-in-alt"></i>
|
||||||
|
<span>Sign In</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="help-header">
|
<div class="help-header">
|
||||||
<a href="ansible-sandbox.html" class="back-link">
|
<a href="ansible-sandbox.html" class="back-link">
|
||||||
|
@ -603,23 +688,44 @@
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="footer-content">
|
<div class="footer-content">
|
||||||
<div class="footer-logo">
|
<div class="footer-info">
|
||||||
<span class="logo-text">Argobox</span>
|
<div class="footer-logo">
|
||||||
<span class="logo-dot">.com</span>
|
<span class="logo-text-glow">ArgoBox</span>
|
||||||
|
<span class="logo-dot-glow">.com</span>
|
||||||
|
</div>
|
||||||
|
<p class="footer-description">
|
||||||
|
Enterprise-grade home lab environment for DevOps experimentation, infrastructure automation, and containerized application deployment.
|
||||||
|
</p>
|
||||||
|
<div class="footer-evolution">
|
||||||
|
<i class="fas fa-code-branch evolution-icon"></i>
|
||||||
|
<span>Continuously evolving since 2011</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer-links">
|
<div class="footer-links">
|
||||||
<a href="index.html#home">Home</a>
|
<div class="footer-links-column">
|
||||||
<a href="index.html#services">Services</a>
|
<h3 class="footer-heading">Platforms</h3>
|
||||||
<a href="index.html#lab">Live Lab</a>
|
<a href="https://dashboard.argobox.com" class="footer-link">Dashboard</a>
|
||||||
<a href="index.html#projects">Projects</a>
|
<a href="ansible-sandbox.html" class="footer-link">Ansible Sandbox</a>
|
||||||
<a href="index.html#contact">Contact</a>
|
<a href="https://git.argobox.com" class="footer-link">Gitea</a>
|
||||||
</div>
|
<a href="https://ai.argobox.com" class="footer-link">OpenWebUI</a>
|
||||||
|
</div>
|
||||||
<div class="footer-social">
|
|
||||||
<a href="https://github.com/keyargo" target="_blank" aria-label="GitHub"><i class="fab fa-github"></i></a>
|
<div class="footer-links-column">
|
||||||
<a href="https://www.linkedin.com/in/danlaforce" target="_blank" aria-label="LinkedIn"><i class="fab fa-linkedin"></i></a>
|
<h3 class="footer-heading">Documentation</h3>
|
||||||
<a href="mailto:daniel.laforce@argobox.com" aria-label="Email"><i class="fas fa-envelope"></i></a>
|
<a href="construction.html" class="footer-link">Architecture</a>
|
||||||
|
<a href="construction.html" class="footer-link">Kubernetes</a>
|
||||||
|
<a href="construction.html" class="footer-link">Ansible</a>
|
||||||
|
<a href="construction.html" class="footer-link">Network</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-links-column">
|
||||||
|
<h3 class="footer-heading">Resources</h3>
|
||||||
|
<a href="construction.html" class="footer-link">Ansible Playbooks</a>
|
||||||
|
<a href="construction.html" class="footer-link">K8s Manifests</a>
|
||||||
|
<a href="construction.html" class="footer-link">Shell Scripts</a>
|
||||||
|
<a href="construction.html" class="footer-link">Configuration Files</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -702,35 +702,43 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.offline-notice {
|
.offline-notice {
|
||||||
background-color: rgba(239, 68, 68, 0.1);
|
display: none;
|
||||||
border: 1px solid rgba(239, 68, 68, 0.3);
|
background-color: rgba(220, 38, 38, 0.1);
|
||||||
|
border: 1px solid rgba(220, 38, 38, 0.3);
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
margin-bottom: 2rem;
|
margin: 1rem 0;
|
||||||
display: flex;
|
color: var(--text-primary);
|
||||||
|
font-size: 0.9rem;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.offline-notice-icon {
|
.offline-notice-icon {
|
||||||
font-size: 1.5rem;
|
background-color: rgba(220, 38, 38, 0.2);
|
||||||
color: var(--error);
|
border-radius: 50%;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 0.75rem;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.offline-notice-text {
|
.offline-notice-text {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.offline-notice h3 {
|
.offline-notice-text h4 {
|
||||||
color: var(--error);
|
margin: 0 0 0.25rem 0;
|
||||||
margin-bottom: 0.5rem;
|
font-weight: 600;
|
||||||
font-size: 1.1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.offline-notice p {
|
.offline-notice-text p {
|
||||||
color: var(--text-secondary);
|
|
||||||
font-size: 0.9rem;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.85rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* View tab placeholders */
|
/* View tab placeholders */
|
||||||
|
@ -945,7 +953,7 @@
|
||||||
gap: 0.75rem;
|
gap: 0.75rem;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lamp-component {
|
.lamp-component {
|
||||||
display: flex;
|
display: flex;
|
||||||
background-color: rgba(15, 23, 42, 0.3);
|
background-color: rgba(15, 23, 42, 0.3);
|
||||||
|
@ -981,7 +989,7 @@
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.php-info-preview {
|
.php-info-preview {
|
||||||
background-color: rgba(15, 23, 42, 0.3);
|
background-color: rgba(15, 23, 42, 0.3);
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
|
@ -1172,8 +1180,10 @@
|
||||||
.toggle-switch {
|
.toggle-switch {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 46px;
|
width: 40px;
|
||||||
height: 24px;
|
height: 22px;
|
||||||
|
margin: 0 0.75rem;
|
||||||
|
pointer-events: none; /* Make toggle non-interactive */
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-switch input {
|
.toggle-switch input {
|
||||||
|
@ -1185,33 +1195,46 @@
|
||||||
.toggle-slider {
|
.toggle-slider {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background-color: #ccc;
|
background-color: #374151;
|
||||||
transition: .4s;
|
transition: 0.4s;
|
||||||
border-radius: 24px;
|
border-radius: 34px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-slider:before {
|
.toggle-slider:before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
content: "";
|
content: "";
|
||||||
height: 18px;
|
height: 16px;
|
||||||
width: 18px;
|
width: 16px;
|
||||||
left: 3px;
|
left: 3px;
|
||||||
bottom: 3px;
|
bottom: 3px;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
transition: .4s;
|
transition: 0.4s;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
input:checked + .toggle-slider {
|
input:checked + .toggle-slider {
|
||||||
background-color: var(--primary);
|
background-color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
input:checked + .toggle-slider:before {
|
input:checked + .toggle-slider:before {
|
||||||
transform: translateX(22px);
|
transform: translateX(18px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.simulation-toggle {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-label, .toggle-status {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Web server styles */
|
/* Web server styles */
|
||||||
|
@ -1240,7 +1263,7 @@
|
||||||
.website-control {
|
.website-control {
|
||||||
width: 12px;
|
width: 12px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.website-control.close {
|
.website-control.close {
|
||||||
|
@ -1263,8 +1286,8 @@
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
font-family: 'JetBrains Mono', monospace;
|
font-family: 'JetBrains Mono', monospace;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1277,7 +1300,7 @@
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
@ -1298,12 +1321,12 @@
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.web-subtitle {
|
.web-subtitle {
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Additional styles for simulation toggle */
|
/* Additional styles for simulation toggle */
|
||||||
.simulation-toggle {
|
.simulation-toggle {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -1336,11 +1359,11 @@
|
||||||
|
|
||||||
.toggle-slider {
|
.toggle-slider {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
background-color: #ccc;
|
background-color: #ccc;
|
||||||
transition: .4s;
|
transition: .4s;
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
|
@ -1392,6 +1415,35 @@
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.live-indicator {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background-color: var(--success);
|
||||||
|
border-radius: 50%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.live-indicator.offline {
|
||||||
|
background-color: var(--error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.live-indicator::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: var(--success);
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.live-indicator.offline::after {
|
||||||
|
background-color: var(--error);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -1413,7 +1465,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-buttons">
|
<div class="nav-buttons">
|
||||||
<a href="https://dashboard.argobox.com" class="dashboard-link" target="_blank">
|
<a href="https://dashboard.argobox.com" class="dashboard-link" target="_blank">
|
||||||
<span class="live-indicator"></span>
|
<span class="live-indicator offline"></span>
|
||||||
<span>Live Dashboard</span>
|
<span>Live Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
<button class="menu-toggle" aria-label="Toggle menu">
|
<button class="menu-toggle" aria-label="Toggle menu">
|
||||||
|
@ -1441,7 +1493,7 @@
|
||||||
<div class="simulation-toggle">
|
<div class="simulation-toggle">
|
||||||
<span class="toggle-label">Simulation Mode</span>
|
<span class="toggle-label">Simulation Mode</span>
|
||||||
<label class="toggle-switch">
|
<label class="toggle-switch">
|
||||||
<input type="checkbox" checked>
|
<input type="checkbox" id="simulation-toggle" checked>
|
||||||
<span class="toggle-slider"></span>
|
<span class="toggle-slider"></span>
|
||||||
</label>
|
</label>
|
||||||
<span class="toggle-status">Active</span>
|
<span class="toggle-status">Active</span>
|
||||||
|
@ -2533,24 +2585,95 @@
|
||||||
|
|
||||||
tabs.forEach(tab => {
|
tabs.forEach(tab => {
|
||||||
tab.addEventListener('click', function() {
|
tab.addEventListener('click', function() {
|
||||||
const tabId = this.getAttribute('data-tab');
|
// Remove active class from all tabs
|
||||||
|
|
||||||
tabs.forEach(t => t.classList.remove('active'));
|
tabs.forEach(t => t.classList.remove('active'));
|
||||||
tabContents.forEach(tc => tc.classList.remove('active'));
|
// Add active class to clicked tab
|
||||||
|
|
||||||
this.classList.add('active');
|
this.classList.add('active');
|
||||||
document.getElementById(`${tabId}-tab`).classList.add('active');
|
|
||||||
|
// Hide all tab contents
|
||||||
|
tabContents.forEach(content => content.classList.remove('active'));
|
||||||
|
// Show tab content corresponding to clicked tab
|
||||||
|
const tabContent = document.querySelector(`.tab-content[data-tab="${this.dataset.tab}"]`);
|
||||||
|
tabContent.classList.add('active');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Playbook selection
|
// Playbook selection
|
||||||
const playbooks = document.querySelectorAll('.playbook-card');
|
const playbooks = document.querySelectorAll('.playbook-card');
|
||||||
const previewTitle = document.querySelector('.preview-title span');
|
const previewTitle = document.querySelector('.preview-title');
|
||||||
const codeEditor = document.querySelector('.code-editor');
|
const statusIndicator = document.querySelector('.status-indicator');
|
||||||
|
const codeEditor = document.querySelector('.code-preview code');
|
||||||
|
const simulationToggle = document.getElementById('simulation-toggle');
|
||||||
|
|
||||||
// Define a content mapper for different playbooks
|
// Set simulation toggle to checked and disable it
|
||||||
const playbookContents = {
|
if (simulationToggle) {
|
||||||
'web-server': codeEditor.innerHTML, // Save the current web server content as default
|
simulationToggle.checked = true;
|
||||||
|
document.querySelector('.toggle-status').textContent = 'Active';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content mapper for different playbooks
|
||||||
|
const contentMapper = {
|
||||||
|
'web-server': `---
|
||||||
|
# Ansible Playbook for Nginx Web Server Deployment
|
||||||
|
- name: Deploy Nginx Web Server
|
||||||
|
hosts: web_servers
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
web_root: /var/www/html
|
||||||
|
site_name: example.com
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Update apt cache
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
||||||
|
cache_valid_time: 3600
|
||||||
|
|
||||||
|
- name: Install Nginx
|
||||||
|
apt:
|
||||||
|
name: nginx
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create web root directory
|
||||||
|
file:
|
||||||
|
path: "{{ web_root }}"
|
||||||
|
state: directory
|
||||||
|
owner: www-data
|
||||||
|
group: www-data
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: Deploy website content
|
||||||
|
copy:
|
||||||
|
src: files/index.html
|
||||||
|
dest: "{{ web_root }}/index.html"
|
||||||
|
owner: www-data
|
||||||
|
group: www-data
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
- name: Configure Nginx site
|
||||||
|
template:
|
||||||
|
src: templates/nginx-site.conf.j2
|
||||||
|
dest: /etc/nginx/sites-available/{{ site_name }}
|
||||||
|
notify: Restart Nginx
|
||||||
|
|
||||||
|
- name: Enable Nginx site
|
||||||
|
file:
|
||||||
|
src: /etc/nginx/sites-available/{{ site_name }}
|
||||||
|
dest: /etc/nginx/sites-enabled/{{ site_name }}
|
||||||
|
state: link
|
||||||
|
notify: Restart Nginx
|
||||||
|
|
||||||
|
- name: Ensure default site is disabled
|
||||||
|
file:
|
||||||
|
path: /etc/nginx/sites-enabled/default
|
||||||
|
state: absent
|
||||||
|
notify: Restart Nginx
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
- name: Restart Nginx
|
||||||
|
service:
|
||||||
|
name: nginx
|
||||||
|
state: restarted
|
||||||
|
enabled: yes`,
|
||||||
'docker-compose': `
|
'docker-compose': `
|
||||||
<div class="code-line"><span class="line-number">1</span><span class="line-content code-comment">---</span></div>
|
<div class="code-line"><span class="line-number">1</span><span class="line-content code-comment">---</span></div>
|
||||||
<div class="code-line"><span class="line-number">2</span><span class="line-content code-comment"># Docker Compose Stack Playbook</span></div>
|
<div class="code-line"><span class="line-number">2</span><span class="line-content code-comment"># Docker Compose Stack Playbook</span></div>
|
||||||
|
@ -2674,8 +2797,8 @@
|
||||||
previewTitle.textContent = playbookName;
|
previewTitle.textContent = playbookName;
|
||||||
|
|
||||||
// Update code editor content if we have content for this playbook
|
// Update code editor content if we have content for this playbook
|
||||||
if (playbookContents[playbookType]) {
|
if (contentMapper[playbookType]) {
|
||||||
codeEditor.innerHTML = playbookContents[playbookType];
|
codeEditor.innerHTML = contentMapper[playbookType];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the status to "Ready to deploy"
|
// Reset the status to "Ready to deploy"
|
||||||
|
|
205
dashboard.html
205
dashboard.html
|
@ -187,6 +187,10 @@
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.live-indicator.offline {
|
||||||
|
background-color: var(--error);
|
||||||
|
}
|
||||||
|
|
||||||
.live-indicator::after {
|
.live-indicator::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -200,6 +204,10 @@
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.live-indicator.offline::after {
|
||||||
|
background-color: var(--error);
|
||||||
|
}
|
||||||
|
|
||||||
.menu-toggle {
|
.menu-toggle {
|
||||||
display: none;
|
display: none;
|
||||||
background: none;
|
background: none;
|
||||||
|
@ -1003,6 +1011,7 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 46px;
|
width: 46px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
|
pointer-events: none; /* Make toggle non-interactive */
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-switch input {
|
.toggle-switch input {
|
||||||
|
@ -1013,7 +1022,6 @@
|
||||||
|
|
||||||
.toggle-slider {
|
.toggle-slider {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
cursor: pointer;
|
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
@ -1068,6 +1076,36 @@
|
||||||
background-color: rgba(239, 68, 68, 0.1);
|
background-color: rgba(239, 68, 68, 0.1);
|
||||||
color: var(--error);
|
color: var(--error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* System offline notice */
|
||||||
|
.offline-notice {
|
||||||
|
background-color: rgba(239, 68, 68, 0.1);
|
||||||
|
border: 1px solid rgba(239, 68, 68, 0.3);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.offline-notice-icon {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: var(--error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.offline-notice-text h3 {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
color: var(--error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.offline-notice-text p {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Popup styles for settings and alerts */
|
/* Popup styles for settings and alerts */
|
||||||
.popup-overlay {
|
.popup-overlay {
|
||||||
|
@ -1211,21 +1249,20 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
<a href="index.html">
|
<a href="index.html">
|
||||||
<span class="logo-text">Argobox</span>
|
<span class="logo-text-glow">ArgoBox</span><span class="logo-dot-glow">.com</span>
|
||||||
<span class="logo-dot">.com</span>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-menu">
|
<div class="nav-menu">
|
||||||
<a href="index.html#home" class="nav-link">Home</a>
|
<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#services" class="nav-link">Services</a>
|
||||||
<a href="index.html#lab" class="nav-link">Live Lab</a>
|
|
||||||
<a href="index.html#projects" class="nav-link">Projects</a>
|
<a href="index.html#projects" class="nav-link">Projects</a>
|
||||||
<a href="index.html#experience" class="nav-link">Experience</a>
|
<a href="index.html#dashboards" class="nav-link">Dashboards</a>
|
||||||
<a href="index.html#contact" class="nav-link">Contact</a>
|
<a href="index.html#contact" class="nav-link">Contact</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-buttons">
|
<div class="nav-buttons">
|
||||||
<a href="dashboard.html" class="dashboard-link" target="_blank">
|
<a href="https://dashboard.argobox.com" class="dashboard-link" target="_blank">
|
||||||
<span class="live-indicator"></span>
|
<span class="live-indicator offline"></span>
|
||||||
<span>Live Dashboard</span>
|
<span>Live Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
<button class="menu-toggle" aria-label="Toggle menu">
|
<button class="menu-toggle" aria-label="Toggle menu">
|
||||||
|
@ -1235,6 +1272,28 @@
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</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="construction.html" class="signin-button" target="_blank">
|
||||||
|
<i class="fas fa-sign-in-alt"></i>
|
||||||
|
<span>Sign In</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Add offline notice banner after the top links but push it down below the navbar -->
|
||||||
|
<div class="offline-notice" id="offline-notice" style="display: block; margin-top: 8rem;">
|
||||||
|
<div class="offline-notice-icon">
|
||||||
|
<i class="fas fa-exclamation-triangle"></i>
|
||||||
|
</div>
|
||||||
|
<div class="offline-notice-text">
|
||||||
|
<h3>Dashboard is Currently Offline</h3>
|
||||||
|
<p>The live dashboard is currently in simulation mode. You can explore the interface, but real-time data is not available. We're working to restore full functionality soon.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="dashboard-container">
|
<div class="dashboard-container">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="dashboard-header">
|
<div class="dashboard-header">
|
||||||
|
@ -1750,23 +1809,44 @@
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="footer-content">
|
<div class="footer-content">
|
||||||
<div class="footer-logo">
|
<div class="footer-info">
|
||||||
<span class="logo-text">Argobox</span>
|
<div class="footer-logo">
|
||||||
<span class="logo-dot">.com</span>
|
<span class="logo-text-glow">ArgoBox</span>
|
||||||
|
<span class="logo-dot-glow">.com</span>
|
||||||
|
</div>
|
||||||
|
<p class="footer-description">
|
||||||
|
Enterprise-grade home lab environment for DevOps experimentation, infrastructure automation, and containerized application deployment.
|
||||||
|
</p>
|
||||||
|
<div class="footer-evolution">
|
||||||
|
<i class="fas fa-code-branch evolution-icon"></i>
|
||||||
|
<span>Continuously evolving since 2011</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer-links">
|
<div class="footer-links">
|
||||||
<a href="index.html">Home</a>
|
<div class="footer-links-column">
|
||||||
<a href="index.html#services">Services</a>
|
<h3 class="footer-heading">Platforms</h3>
|
||||||
<a href="index.html#lab">Live Lab</a>
|
<a href="https://dashboard.argobox.com" class="footer-link">Dashboard</a>
|
||||||
<a href="index.html#projects">Projects</a>
|
<a href="ansible-sandbox.html" class="footer-link">Ansible Sandbox</a>
|
||||||
<a href="index.html#experience">Experience</a>
|
<a href="https://git.argobox.com" class="footer-link">Gitea</a>
|
||||||
<a href="index.html#contact">Contact</a>
|
<a href="https://ai.argobox.com" class="footer-link">OpenWebUI</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer-social">
|
<div class="footer-links-column">
|
||||||
<a href="https://linkedin.com/in/danlaforce" target="_blank"><i class="fab fa-linkedin"></i></a>
|
<h3 class="footer-heading">Documentation</h3>
|
||||||
<a href="https://github.com/keyargo" target="_blank"><i class="fab fa-github"></i></a>
|
<a href="construction.html" class="footer-link">Architecture</a>
|
||||||
|
<a href="construction.html" class="footer-link">Kubernetes</a>
|
||||||
|
<a href="construction.html" class="footer-link">Ansible</a>
|
||||||
|
<a href="construction.html" class="footer-link">Network</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer-links-column">
|
||||||
|
<h3 class="footer-heading">Resources</h3>
|
||||||
|
<a href="construction.html" class="footer-link">Ansible Playbooks</a>
|
||||||
|
<a href="construction.html" class="footer-link">K8s Manifests</a>
|
||||||
|
<a href="construction.html" class="footer-link">Shell Scripts</a>
|
||||||
|
<a href="construction.html" class="footer-link">Configuration Files</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1832,31 +1912,76 @@
|
||||||
simulateRefresh();
|
simulateRefresh();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize simulation toggle
|
// Initialize simulation toggle based on system status
|
||||||
const toggleInput = document.getElementById('simulation-toggle');
|
const toggleInput = document.getElementById('simulation-toggle');
|
||||||
const toggleStatus = document.querySelector('.toggle-status');
|
const toggleStatus = document.querySelector('.toggle-status');
|
||||||
const liveIndicator = document.querySelector('.live-dot');
|
const liveIndicator = document.querySelector('.live-dot');
|
||||||
const liveLabel = document.querySelector('.live-indicator-label');
|
const liveLabel = document.querySelector('.live-indicator-label');
|
||||||
|
|
||||||
toggleInput.addEventListener('change', function() {
|
// System status is set to offline by default
|
||||||
if(this.checked) {
|
if (liveIndicator) {
|
||||||
toggleStatus.textContent = 'Active';
|
liveIndicator.classList.add('offline');
|
||||||
document.body.classList.add('simulation-mode');
|
}
|
||||||
liveIndicator.classList.add('offline');
|
if (liveLabel) {
|
||||||
liveLabel.classList.add('offline');
|
liveLabel.textContent = 'Offline';
|
||||||
liveLabel.querySelector('span:last-child').textContent = 'Offline';
|
liveLabel.classList.add('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
|
// Set simulation toggle to checked and non-interactive
|
||||||
toggleInput.checked = true;
|
if (toggleInput) {
|
||||||
toggleInput.dispatchEvent(new Event('change'));
|
toggleInput.checked = true;
|
||||||
|
toggleStatus.textContent = 'Active';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate a ping check to determine if system is online
|
||||||
|
// In a real implementation, this would be an actual API call
|
||||||
|
function checkSystemStatus() {
|
||||||
|
// For demonstration, we'll hardcode to offline (true)
|
||||||
|
// In a real implementation, this would check connectivity
|
||||||
|
const isOffline = true;
|
||||||
|
|
||||||
|
if (isOffline) {
|
||||||
|
// System is offline
|
||||||
|
if (toggleInput) {
|
||||||
|
toggleInput.checked = true;
|
||||||
|
toggleStatus.textContent = 'Active';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelector('.offline-notice').style.display = 'block';
|
||||||
|
|
||||||
|
if (liveIndicator) {
|
||||||
|
liveIndicator.classList.add('offline');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (liveLabel) {
|
||||||
|
liveLabel.textContent = 'Offline';
|
||||||
|
liveLabel.classList.add('offline');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// System is online
|
||||||
|
if (toggleInput) {
|
||||||
|
toggleInput.checked = false;
|
||||||
|
toggleStatus.textContent = 'Inactive';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelector('.offline-notice').style.display = 'none';
|
||||||
|
|
||||||
|
if (liveIndicator) {
|
||||||
|
liveIndicator.classList.remove('offline');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (liveLabel) {
|
||||||
|
liveLabel.textContent = 'Online';
|
||||||
|
liveLabel.classList.remove('offline');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check system status on page load
|
||||||
|
checkSystemStatus();
|
||||||
|
|
||||||
|
// Periodically check system status (every 30 seconds)
|
||||||
|
setInterval(checkSystemStatus, 30000);
|
||||||
|
|
||||||
// Set up settings and alerts popup functionality
|
// Set up settings and alerts popup functionality
|
||||||
const settingsBtn = document.getElementById('settings-btn');
|
const settingsBtn = document.getElementById('settings-btn');
|
||||||
|
|
15
index.html
15
index.html
|
@ -27,6 +27,17 @@
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* Add the CSS for the offline indicator */
|
||||||
|
.live-indicator.offline {
|
||||||
|
background-color: #ef4444 !important; /* Red color */
|
||||||
|
}
|
||||||
|
|
||||||
|
.live-indicator.offline::after {
|
||||||
|
background-color: #ef4444 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Navigation Bar -->
|
<!-- Navigation Bar -->
|
||||||
|
@ -47,7 +58,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-buttons">
|
<div class="nav-buttons">
|
||||||
<a href="https://dashboard.argobox.com" class="dashboard-link" target="_blank">
|
<a href="https://dashboard.argobox.com" class="dashboard-link" target="_blank">
|
||||||
<span class="live-indicator"></span>
|
<span class="live-indicator offline"></span>
|
||||||
<span>Live Dashboard</span>
|
<span>Live Dashboard</span>
|
||||||
</a>
|
</a>
|
||||||
<button class="menu-toggle" aria-label="Toggle menu">
|
<button class="menu-toggle" aria-label="Toggle menu">
|
||||||
|
@ -111,7 +122,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="cta-buttons">
|
<div class="cta-buttons">
|
||||||
<a href="ansible-sandbox.html" class="btn btn-danger" target="_blank">
|
<a href="ansible-sandbox.html" class="btn btn-danger" target="_blank" id="ansible-sandbox-btn">
|
||||||
<i class="fab fa-ansible btn-icon"></i>
|
<i class="fab fa-ansible btn-icon"></i>
|
||||||
<span class="btn-text">Try Ansible Sandbox</span>
|
<span class="btn-text">Try Ansible Sandbox</span>
|
||||||
<span class="offline-badge">Offline</span>
|
<span class="offline-badge">Offline</span>
|
||||||
|
|
Loading…
Reference in New Issue