ar / templates\ar_dashboard.html
gsstec's picture
Upload templates\ar_dashboard.html with huggingface_hub
4600893 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AEGIS BIO DIGITAL LAB 10 - AR Portal</title>
<meta name="description" content="AEGIS Bio Digital Lab 10 Augmented Reality Portal Dashboard">
<!-- Lucide Icons CDN -->
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
color: white;
min-height: 100vh;
overflow-x: hidden;
}
.header {
background: rgba(0, 0, 0, 0.4);
padding: 1.5rem 2rem;
backdrop-filter: blur(15px);
border-bottom: 1px solid rgba(0, 255, 255, 0.3);
position: sticky;
top: 0;
z-index: 100;
}
.header h1 {
font-size: 2.5rem;
margin-bottom: 0.5rem;
background: linear-gradient(45deg, #00FFFF, #0080FF);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-align: center;
animation: pulse 2s infinite;
}
.header .subtitle {
font-size: 1.2rem;
text-align: center;
opacity: 0.9;
color: #E3F2FD;
}
.status-bar {
display: flex;
justify-content: center;
align-items: center;
gap: 2rem;
margin-top: 1rem;
flex-wrap: wrap;
}
.status-item {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.9rem;
opacity: 0.8;
}
.status-online {
color: #4CAF50;
}
.status-offline {
color: #f44336;
}
.main-content {
padding: 2rem;
max-width: 1400px;
margin: 0 auto;
}
.hero-section {
text-align: center;
margin-bottom: 3rem;
}
.hero-section h2 {
font-size: 2rem;
margin-bottom: 1rem;
color: #00FFFF;
}
.hero-section p {
font-size: 1.1rem;
opacity: 0.9;
max-width: 600px;
margin: 0 auto;
line-height: 1.6;
}
.portals-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1.5rem;
margin-bottom: 3rem;
}
.portal-card {
background: rgba(0, 0, 0, 0.4);
border: 1px solid rgba(0, 255, 255, 0.3);
border-radius: 15px;
padding: 1.5rem;
text-align: center;
backdrop-filter: blur(10px);
transition: all 0.3s ease;
cursor: pointer;
position: relative;
overflow: hidden;
}
.portal-card::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(0, 255, 255, 0.1), transparent);
transition: left 0.5s;
}
.portal-card:hover::before {
left: 100%;
}
.portal-card:hover {
transform: translateY(-5px);
border-color: rgba(0, 255, 255, 0.6);
box-shadow: 0 10px 30px rgba(0, 255, 255, 0.2);
}
.portal-icon {
width: 60px;
height: 60px;
margin: 0 auto 1rem;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
z-index: 1;
}
.portal-card h3 {
font-size: 1.2rem;
margin-bottom: 0.5rem;
color: white;
position: relative;
z-index: 1;
}
.portal-card p {
font-size: 0.9rem;
opacity: 0.8;
margin-bottom: 1rem;
position: relative;
z-index: 1;
}
.launch-btn {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
background: rgba(0, 255, 255, 0.2);
border: 1px solid rgba(0, 255, 255, 0.4);
border-radius: 25px;
color: #00FFFF;
text-decoration: none;
font-size: 0.9rem;
font-weight: 500;
transition: all 0.3s ease;
position: relative;
z-index: 1;
}
.launch-btn:hover {
background: rgba(0, 255, 255, 0.3);
color: white;
}
/* Color variations for different portals */
.color-blue { background: linear-gradient(135deg, #2196F3, #1976D2); }
.color-green { background: linear-gradient(135deg, #4CAF50, #388E3C); }
.color-purple { background: linear-gradient(135deg, #9C27B0, #7B1FA2); }
.color-yellow { background: linear-gradient(135deg, #FF9800, #F57C00); }
.color-red { background: linear-gradient(135deg, #f44336, #D32F2F); }
.color-orange { background: linear-gradient(135deg, #FF5722, #E64A19); }
.color-indigo { background: linear-gradient(135deg, #3F51B5, #303F9F); }
.color-pink { background: linear-gradient(135deg, #E91E63, #C2185B); }
.color-teal { background: linear-gradient(135deg, #009688, #00796B); }
.color-cyan { background: linear-gradient(135deg, #00BCD4, #0097A7); }
.color-emerald { background: linear-gradient(135deg, #4CAF50, #2E7D32); }
.qr-section {
background: rgba(0, 0, 0, 0.3);
border: 1px solid rgba(0, 255, 255, 0.3);
border-radius: 15px;
padding: 2rem;
text-align: center;
margin-bottom: 2rem;
}
.qr-section h3 {
color: #00FFFF;
margin-bottom: 1rem;
font-size: 1.5rem;
}
.qr-code-container {
margin: 1rem 0;
}
.qr-code-container img {
max-width: 200px;
border-radius: 10px;
border: 2px solid rgba(0, 255, 255, 0.3);
}
.api-section {
background: rgba(0, 0, 0, 0.3);
border: 1px solid rgba(0, 255, 255, 0.3);
border-radius: 15px;
padding: 2rem;
margin-bottom: 2rem;
}
.api-section h3 {
color: #00FFFF;
margin-bottom: 1rem;
font-size: 1.5rem;
}
.api-endpoints {
display: grid;
gap: 0.5rem;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
}
.api-endpoint {
background: rgba(0, 0, 0, 0.4);
padding: 0.75rem;
border-radius: 8px;
border-left: 3px solid #00FFFF;
}
.footer {
background: rgba(0, 0, 0, 0.4);
padding: 2rem;
text-align: center;
border-top: 1px solid rgba(0, 255, 255, 0.3);
margin-top: 2rem;
}
.footer p {
opacity: 0.7;
margin-bottom: 0.5rem;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.8; }
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.animate-spin {
animation: spin 1s linear infinite;
}
.error-notification {
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
.portal-card {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.portal-card:active {
transform: translateY(-2px) scale(0.98);
}
@media (max-width: 768px) {
.header h1 {
font-size: 1.8rem;
}
.portals-grid {
grid-template-columns: 1fr;
gap: 1rem;
}
.status-bar {
flex-direction: column;
gap: 1rem;
}
}
</style>
</head>
<body>
<header class="header">
<h1>AEGIS BIO DIGITAL LAB 10</h1>
<div class="subtitle">AUGMENTED REALITY PORTAL DASHBOARD</div>
<div class="status-bar">
<div class="status-item">
<i data-lucide="globe"></i>
<span>10 Active Portals</span>
</div>
<div class="status-item" id="connection-status">
<i data-lucide="wifi" id="status-icon"></i>
<span id="status-text">Checking Connection...</span>
</div>
<div class="status-item">
<i data-lucide="clock"></i>
<span id="current-time"></span>
</div>
</div>
</header>
<main class="main-content">
<section class="hero-section">
<h2>🚀 Portal Access Dashboard</h2>
<p>
Welcome to the AEGIS Bio Digital Lab 10 AR Portal.
Access all system components through this unified interface.
Each portal provides specialized functionality for biological research and analysis.
</p>
</section>
<section class="portals-grid" id="portals-container">
<!-- Portals will be dynamically loaded here -->
</section>
<section class="api-section">
<h3>🔧 API Endpoints</h3>
<div class="api-endpoints">
<div class="api-endpoint">POST /api/update-urls - Update portal URLs</div>
<div class="api-endpoint">GET /api/status - System status</div>
<div class="api-endpoint">GET /health - Health check</div>
</div>
</section>
</main>
<footer class="footer">
<p>🔬 Advanced Biological Research Platform</p>
<p>🚀 Powered by AEGIS Technology</p>
<p>&copy; 2025 AEGIS Systems - All Rights Reserved</p>
</footer>
<script>
// Server-side data will be injected here if available
window.portalsData = null;
</script>
<script>
// Initialize Lucide icons
lucide.createIcons();
// Portal data with icons
const defaultPortals = [
{ name: 'Portal Control', url: '#', icon: 'settings', color: 'blue', description: 'Main control center' },
{ name: 'SciBERT Analysis', url: '#', icon: 'bar-chart-3', color: 'green', description: 'Scientific analysis tools' },
{ name: 'Conductor', url: '#', icon: 'cpu', color: 'purple', description: 'System orchestration' },
{ name: 'Economic Modal', url: '#', icon: 'dollar-sign', color: 'yellow', description: 'Economic modeling' },
{ name: 'War Modal', url: '#', icon: 'shield', color: 'red', description: 'Strategic analysis' },
{ name: 'Disease Modal', url: '#', icon: 'bug', color: 'orange', description: 'Disease tracking' },
{ name: 'DeepSeek', url: '#', icon: 'brain', color: 'indigo', description: 'AI deep analysis' },
{ name: 'Image Modal', url: '#', icon: 'image', color: 'pink', description: 'Image processing' },
{ name: 'Drug Development', url: '#', icon: 'pill', color: 'teal', description: 'Pharmaceutical research' },
{ name: 'Visual Kinetic', url: '#', icon: 'eye', color: 'cyan', description: 'Visual analytics' }
];
// Update time
function updateTime() {
const now = new Date();
document.getElementById('current-time').textContent = now.toLocaleString();
}
// Load portals from API or use defaults
async function loadPortals() {
const container = document.getElementById('portals-container');
// Show loading state
container.innerHTML = `
<div style="grid-column: 1 / -1; text-align: center; padding: 2rem;">
<i data-lucide="loader-2" class="animate-spin" style="width: 48px; height: 48px; margin-bottom: 1rem;"></i>
<p>Loading portals...</p>
</div>
`;
lucide.createIcons();
let portalsData = null;
// Try to load from API first
try {
const response = await fetch('/api/portals');
if (response.ok) {
const data = await response.json();
portalsData = data.portals;
}
} catch (error) {
console.warn('Failed to load portals from API:', error);
}
// Check if portals data is available from server-side injection
if (!portalsData && typeof window.portalsData !== 'undefined') {
portalsData = window.portalsData;
}
// Fallback to default portals if no data available
const portalsToUse = portalsData || defaultPortals;
container.innerHTML = portalsToUse.map(portal => `
<div class="portal-card" onclick="openPortal('${portal.url}', '${portal.name}')">
<div class="portal-icon color-${portal.color}">
<i data-lucide="${portal.icon}"></i>
</div>
<h3>${portal.name}</h3>
<p>${portal.description}</p>
<a href="${portal.url}" class="launch-btn" onclick="event.stopPropagation(); openPortal('${portal.url}', '${portal.name}')">
<span>Launch Portal</span>
<i data-lucide="external-link"></i>
</a>
</div>
`).join('');
lucide.createIcons();
}
// Open portal
function openPortal(url) {
if (url && url !== '#') {
window.open(url, '_blank', 'noopener,noreferrer');
}
}
// Check system status
async function checkStatus() {
try {
const response = await fetch('/api/status');
const data = await response.json();
const statusIcon = document.getElementById('status-icon');
const statusText = document.getElementById('status-text');
const connectionStatus = document.getElementById('connection-status');
if (data.status === 'online') {
statusIcon.setAttribute('data-lucide', 'wifi');
statusText.textContent = 'System Online';
connectionStatus.className = 'status-item status-online';
} else {
statusIcon.setAttribute('data-lucide', 'wifi-off');
statusText.textContent = 'System Offline';
connectionStatus.className = 'status-item status-offline';
}
lucide.createIcons();
} catch (error) {
const statusIcon = document.getElementById('status-icon');
const statusText = document.getElementById('status-text');
const connectionStatus = document.getElementById('connection-status');
statusIcon.setAttribute('data-lucide', 'wifi-off');
statusText.textContent = 'Connection Error';
connectionStatus.className = 'status-item status-offline';
lucide.createIcons();
}
}
// Update portal URLs
async function updatePortalUrls(newUrls) {
try {
const response = await fetch('/api/update-urls', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ urls: newUrls })
});
const data = await response.json();
if (data.success) {
loadPortals();
return true;
} else {
console.error('Failed to update URLs:', data.error);
return false;
}
} catch (error) {
console.error('Error updating URLs:', error);
return false;
}
}
// Initialize dashboard
function initDashboard() {
updateTime();
loadPortals();
checkStatus();
// Update time every second
setInterval(updateTime, 1000);
// Check status every 30 seconds
setInterval(checkStatus, 30000);
}
// Handle keyboard shortcuts
document.addEventListener('keydown', function(event) {
// Ctrl/Cmd + R to refresh portals
if ((event.ctrlKey || event.metaKey) && event.key === 'r') {
event.preventDefault();
loadPortals();
checkStatus();
}
});
// Handle window focus/blur for status updates
window.addEventListener('focus', function() {
checkStatus();
});
// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', initDashboard);
// Handle portal card animations
document.addEventListener('mouseover', function(event) {
if (event.target.closest('.portal-card')) {
event.target.closest('.portal-card').style.transform = 'translateY(-5px) scale(1.02)';
}
});
document.addEventListener('mouseout', function(event) {
if (event.target.closest('.portal-card')) {
event.target.closest('.portal-card').style.transform = 'translateY(0) scale(1)';
}
});
// Add loading states
function showLoading(elementId) {
const element = document.getElementById(elementId);
if (element) {
element.innerHTML = '<i data-lucide="loader-2" class="animate-spin"></i> Loading...';
lucide.createIcons();
}
}
function hideLoading(elementId, originalContent) {
const element = document.getElementById(elementId);
if (element) {
element.innerHTML = originalContent;
lucide.createIcons();
}
}
// Add error handling for portal launches
function handlePortalError(portalName, error) {
console.error(`Error launching ${portalName}:`, error);
// Show user-friendly error message
const errorDiv = document.createElement('div');
errorDiv.className = 'error-notification';
errorDiv.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
background: rgba(244, 67, 54, 0.9);
color: white;
padding: 1rem;
border-radius: 8px;
z-index: 1000;
max-width: 300px;
backdrop-filter: blur(10px);
`;
errorDiv.innerHTML = `
<div style="display: flex; align-items: center; gap: 0.5rem;">
<i data-lucide="alert-circle"></i>
<span>Failed to launch ${portalName}</span>
</div>
`;
document.body.appendChild(errorDiv);
lucide.createIcons();
// Remove error message after 5 seconds
setTimeout(() => {
if (errorDiv.parentNode) {
errorDiv.parentNode.removeChild(errorDiv);
}
}, 5000);
}
// Enhanced portal opening with error handling
function openPortalSafe(url, name) {
try {
if (url && url !== '#') {
const newWindow = window.open(url, '_blank', 'noopener,noreferrer');
// Check if popup was blocked
if (!newWindow || newWindow.closed || typeof newWindow.closed === 'undefined') {
throw new Error('Popup blocked or failed to open');
}
} else {
throw new Error('Invalid URL');
}
} catch (error) {
handlePortalError(name, error);
}
}
// Update the openPortal function to use the safer version
function openPortal(url, name = 'Portal') {
openPortalSafe(url, name);
}
// Add service worker registration for offline support
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/sw.js')
.then(function(registration) {
console.log('ServiceWorker registration successful');
})
.catch(function(error) {
console.log('ServiceWorker registration failed');
});
});
}
</script>
</body>
</html>