camera_draw / public /admin.html
VISHAL18for4's picture
Rename public/Admin.html to public/admin.html
aee955b verified
Raw
History Blame Contribute Delete
6.92 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Admin Gallery</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: #0d0d1a;
color: #eee;
padding: 20px;
min-height: 100vh;
}
.login-container {
max-width: 400px;
margin: 100px auto;
background: #1a1a40;
padding: 40px;
border-radius: 16px;
border: 1px solid #533483;
text-align: center;
}
.login-container h1 { margin-bottom: 20px; color: #f5a623; }
.login-container input {
width: 100%;
padding: 12px;
margin: 10px 0;
border: 1px solid #533483;
border-radius: 8px;
background: #0d0d1a;
color: #fff;
font-size: 1rem;
}
.login-container button {
width: 100%;
padding: 12px;
background: #e94560;
border: none;
border-radius: 8px;
color: #fff;
font-size: 1.1rem;
cursor: pointer;
}
.login-container button:hover { background: #c73652; }
.error { color: #ff4444; margin-top: 10px; }
.gallery {
display: none;
max-width: 1400px;
margin: 0 auto;
}
.gallery-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 0 20px;
border-bottom: 1px solid #533483;
margin-bottom: 20px;
flex-wrap: wrap;
gap: 10px;
}
.gallery-header h1 { color: #f5a623; }
.gallery-header .badge {
background: #533483;
padding: 6px 16px;
border-radius: 20px;
font-size: 0.9rem;
}
.gallery-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
}
.gallery-item {
background: #1a1a40;
border-radius: 12px;
overflow: hidden;
border: 1px solid #2a2a5a;
}
.gallery-item img {
width: 100%;
height: 200px;
object-fit: cover;
display: block;
background: #111;
}
.gallery-item .info {
padding: 10px 14px;
font-size: 0.8rem;
color: #aaa;
display: flex;
justify-content: space-between;
align-items: center;
}
.gallery-item .info a {
color: #f5a623;
text-decoration: none;
font-weight: bold;
}
.empty-msg {
grid-column: 1 / -1;
text-align: center;
padding: 60px;
color: #666;
font-size: 1.2rem;
}
.refresh-btn, .back-btn, .logout-btn {
background: #533483;
border: none;
color: #fff;
padding: 8px 20px;
border-radius: 8px;
cursor: pointer;
}
.refresh-btn:hover, .back-btn:hover { background: #6a4a9a; }
.logout-btn { background: #333; }
.logout-btn:hover { background: #555; }
.back-btn { background: #2a2a5a; }
</style>
</head>
<body>
<div id="loginScreen" class="login-container">
<h1>πŸ” Admin Gallery</h1>
<p style="color:#aaa; margin-bottom:20px;">Enter password to view snapshots</p>
<input type="password" id="passwordInput" placeholder="Enter password" />
<button id="loginBtn">Unlock Gallery</button>
<div id="loginError" class="error"></div>
</div>
<div id="galleryScreen" class="gallery">
<div class="gallery-header">
<h1>πŸ“Έ Saved Snapshots</h1>
<div>
<button class="back-btn" id="backBtn">β¬… Back to Draw</button>
<span class="badge" id="countBadge">0 images</span>
<button class="refresh-btn" id="refreshBtn">⟳ Refresh</button>
<button class="logout-btn" id="logoutBtn">πŸšͺ Logout</button>
</div>
</div>
<div class="gallery-grid" id="galleryGrid">
<div class="empty-msg">Loading snapshots...</div>
</div>
</div>
<script>
const PASSWORD = '26jan24march';
const loginScreen = document.getElementById('loginScreen');
const galleryScreen = document.getElementById('galleryScreen');
const passwordInput = document.getElementById('passwordInput');
const loginBtn = document.getElementById('loginBtn');
const loginError = document.getElementById('loginError');
const galleryGrid = document.getElementById('galleryGrid');
const countBadge = document.getElementById('countBadge');
const refreshBtn = document.getElementById('refreshBtn');
const logoutBtn = document.getElementById('logoutBtn');
const backBtn = document.getElementById('backBtn');
backBtn.addEventListener('click', () => { window.location.href = '/'; });
if (sessionStorage.getItem('adminLoggedIn') === 'true') {
loginScreen.style.display = 'none';
galleryScreen.style.display = 'block';
loadSnapshots();
}
loginBtn.addEventListener('click', () => {
const pass = passwordInput.value.trim();
if (pass === PASSWORD) {
sessionStorage.setItem('adminLoggedIn', 'true');
loginScreen.style.display = 'none';
galleryScreen.style.display = 'block';
loginError.textContent = '';
loadSnapshots();
} else {
loginError.textContent = '❌ Incorrect password.';
passwordInput.value = '';
passwordInput.focus();
}
});
passwordInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter') loginBtn.click();
});
logoutBtn.addEventListener('click', () => {
sessionStorage.removeItem('adminLoggedIn');
galleryScreen.style.display = 'none';
loginScreen.style.display = 'block';
passwordInput.value = '';
loginError.textContent = '';
});
refreshBtn.addEventListener('click', loadSnapshots);
async function loadSnapshots() {
galleryGrid.innerHTML = '<div class="empty-msg">Loading snapshots...</div>';
try {
const response = await fetch('/api/snapshots/list');
const data = await response.json();
if (!data.success || !data.files || data.files.length === 0) {
galleryGrid.innerHTML = '<div class="empty-msg">πŸ“­ No snapshots saved yet.</div>';
countBadge.textContent = '0 images';
return;
}
const files = data.files.sort().reverse();
countBadge.textContent = `${files.length} images`;
let html = '';
files.forEach(filename => {
html += `
<div class="gallery-item">
<img src="/snapshots/${filename}" alt="${filename}" loading="lazy" />
<div class="info">
<span>${filename}</span>
<a href="/snapshots/${filename}" target="_blank">πŸ”— View</a>
</div>
</div>
`;
});
galleryGrid.innerHTML = html;
} catch (err) {
galleryGrid.innerHTML = '<div class="empty-msg">❌ Error loading snapshots.</div>';
}
}
setInterval(() => {
if (sessionStorage.getItem('adminLoggedIn') === 'true') {
loadSnapshots();
}
}, 30000);
</script>
</body>
</html>