277 lines
10 KiB
HTML
277 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Admin - Free Alberta Food</title>
|
|
<meta name="robots" content="noindex, nofollow">
|
|
|
|
<!-- Google Fonts - Roboto to match MkDocs Material theme -->
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700;900&display=swap" rel="stylesheet">
|
|
|
|
<!-- Custom CSS -->
|
|
<link rel="stylesheet" href="/css/styles.css">
|
|
</head>
|
|
<body>
|
|
<!-- Header -->
|
|
<header class="header">
|
|
<div class="header-content">
|
|
<a href="/" class="logo">
|
|
<span class="logo-icon">🍽</span>
|
|
<span class="logo-text">Free Alberta Food</span>
|
|
</a>
|
|
<nav class="nav">
|
|
<span class="admin-badge">Admin Panel</span>
|
|
<button id="logoutBtn" class="nav-link logout-btn hidden">Logout</button>
|
|
</nav>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Main Content -->
|
|
<main class="main-content">
|
|
<!-- Login Section -->
|
|
<div id="loginSection" class="admin-login-section">
|
|
<div class="login-card">
|
|
<h1>Admin Login</h1>
|
|
<p>Enter the admin password to access the dashboard.</p>
|
|
<form id="loginForm">
|
|
<div class="form-group">
|
|
<label for="adminPassword">Password</label>
|
|
<input type="password" id="adminPassword" required autocomplete="current-password">
|
|
</div>
|
|
<div id="loginError" class="error-message hidden"></div>
|
|
<button type="submit" class="resource-action-btn primary full-width">Login</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Admin Dashboard -->
|
|
<div id="adminDashboard" class="hidden">
|
|
<!-- Section Selector -->
|
|
<div class="admin-section-tabs">
|
|
<button class="admin-section-tab active" data-section="updates">Update Requests</button>
|
|
<button class="admin-section-tab" data-section="listings">New Listings</button>
|
|
<button class="admin-section-tab" data-section="geocoding">Geocoding</button>
|
|
</div>
|
|
|
|
<!-- Update Requests Section -->
|
|
<div id="updatesSection" class="admin-section">
|
|
<h2 class="section-title">Update Requests</h2>
|
|
<!-- Stats Bar -->
|
|
<div class="admin-stats-bar">
|
|
<div class="stat-card">
|
|
<span class="stat-value" id="pendingCount">0</span>
|
|
<span class="stat-label">Pending</span>
|
|
</div>
|
|
<div class="stat-card">
|
|
<span class="stat-value" id="approvedCount">0</span>
|
|
<span class="stat-label">Approved</span>
|
|
</div>
|
|
<div class="stat-card">
|
|
<span class="stat-value" id="rejectedCount">0</span>
|
|
<span class="stat-label">Rejected</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filter Tabs -->
|
|
<div class="admin-tabs">
|
|
<button class="admin-tab active" data-status="pending" data-section="updates">Pending</button>
|
|
<button class="admin-tab" data-status="approved" data-section="updates">Approved</button>
|
|
<button class="admin-tab" data-status="rejected" data-section="updates">Rejected</button>
|
|
</div>
|
|
|
|
<!-- Requests List -->
|
|
<div id="requestsList" class="requests-list">
|
|
<!-- Requests will be loaded here -->
|
|
</div>
|
|
|
|
<div id="noRequests" class="no-results hidden">
|
|
<p>No update requests found.</p>
|
|
</div>
|
|
|
|
<div id="loadingRequests" class="loading-indicator hidden">
|
|
<div class="spinner"></div>
|
|
<span>Loading requests...</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- New Listings Section -->
|
|
<div id="listingsSection" class="admin-section hidden">
|
|
<h2 class="section-title">New Listing Submissions</h2>
|
|
<!-- Stats Bar -->
|
|
<div class="admin-stats-bar">
|
|
<div class="stat-card">
|
|
<span class="stat-value" id="listingPendingCount">0</span>
|
|
<span class="stat-label">Pending</span>
|
|
</div>
|
|
<div class="stat-card">
|
|
<span class="stat-value" id="listingApprovedCount">0</span>
|
|
<span class="stat-label">Approved</span>
|
|
</div>
|
|
<div class="stat-card">
|
|
<span class="stat-value" id="listingRejectedCount">0</span>
|
|
<span class="stat-label">Rejected</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filter Tabs -->
|
|
<div class="admin-tabs">
|
|
<button class="admin-tab active" data-status="pending" data-section="listings">Pending</button>
|
|
<button class="admin-tab" data-status="approved" data-section="listings">Approved</button>
|
|
<button class="admin-tab" data-status="rejected" data-section="listings">Rejected</button>
|
|
</div>
|
|
|
|
<!-- Listings List -->
|
|
<div id="listingsList" class="requests-list">
|
|
<!-- Listings will be loaded here -->
|
|
</div>
|
|
|
|
<div id="noListings" class="no-results hidden">
|
|
<p>No listing submissions found.</p>
|
|
</div>
|
|
|
|
<div id="loadingListings" class="loading-indicator hidden">
|
|
<div class="spinner"></div>
|
|
<span>Loading submissions...</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Geocoding Section -->
|
|
<div id="geocodingSection" class="admin-section hidden">
|
|
<h2 class="section-title">Geocoding Management</h2>
|
|
<!-- Stats Bar -->
|
|
<div class="admin-stats-bar">
|
|
<div class="stat-card">
|
|
<span class="stat-value" id="geoTotalCount">0</span>
|
|
<span class="stat-label">Total</span>
|
|
</div>
|
|
<div class="stat-card" style="border-left-color:#10b981">
|
|
<span class="stat-value" id="geoHighCount">0</span>
|
|
<span class="stat-label">High (80%+)</span>
|
|
</div>
|
|
<div class="stat-card" style="border-left-color:#f59e0b">
|
|
<span class="stat-value" id="geoMediumCount">0</span>
|
|
<span class="stat-label">Medium (50-79%)</span>
|
|
</div>
|
|
<div class="stat-card" style="border-left-color:#ef4444">
|
|
<span class="stat-value" id="geoLowCount">0</span>
|
|
<span class="stat-label">Low (<50%)</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filter Tabs -->
|
|
<div class="admin-tabs">
|
|
<button class="admin-tab active" data-filter="all" data-section="geocoding">All</button>
|
|
<button class="admin-tab" data-filter="low" data-section="geocoding">Low Confidence</button>
|
|
<button class="admin-tab" data-filter="missing" data-section="geocoding">Missing Coords</button>
|
|
</div>
|
|
|
|
<!-- Resources List -->
|
|
<div id="geocodingList" class="requests-list">
|
|
<!-- Resources will be loaded here -->
|
|
</div>
|
|
|
|
<div id="noGeoResources" class="no-results hidden">
|
|
<p>No resources found.</p>
|
|
</div>
|
|
|
|
<div id="loadingGeoResources" class="loading-indicator hidden">
|
|
<div class="spinner"></div>
|
|
<span>Loading resources...</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<!-- Request Detail Modal -->
|
|
<div id="requestModal" class="modal hidden">
|
|
<div class="modal-overlay"></div>
|
|
<div class="modal-content modal-large">
|
|
<button class="modal-close">×</button>
|
|
<div id="requestModalBody">
|
|
<!-- Request details will be loaded here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Listing Submission Detail Modal -->
|
|
<div id="listingModal" class="modal hidden">
|
|
<div class="modal-overlay"></div>
|
|
<div class="modal-content modal-large">
|
|
<button class="modal-close">×</button>
|
|
<div id="listingModalBody">
|
|
<!-- Listing details will be loaded here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Geocoding Detail Modal -->
|
|
<div id="geocodingModal" class="modal hidden">
|
|
<div class="modal-overlay"></div>
|
|
<div class="modal-content modal-large">
|
|
<button class="modal-close">×</button>
|
|
<div id="geocodingModalBody">
|
|
<!-- Resource geocoding details will be loaded here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Theme Toggle Button -->
|
|
<button id="themeToggle" class="theme-toggle" title="Toggle dark mode">
|
|
<svg class="sun-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<circle cx="12" cy="12" r="5"></circle>
|
|
<line x1="12" y1="1" x2="12" y2="3"></line>
|
|
<line x1="12" y1="21" x2="12" y2="23"></line>
|
|
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
|
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
|
<line x1="1" y1="12" x2="3" y2="12"></line>
|
|
<line x1="21" y1="12" x2="23" y2="12"></line>
|
|
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
|
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
|
</svg>
|
|
<svg class="moon-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
|
|
</svg>
|
|
</button>
|
|
|
|
<!-- Footer -->
|
|
<footer class="footer">
|
|
<div class="footer-content">
|
|
<p>© 2025 <a href="https://freealberta.org">Free Alberta</a>. Admin Panel.</p>
|
|
</div>
|
|
</footer>
|
|
|
|
<!-- Theme Toggle Script - Dark mode is default -->
|
|
<script>
|
|
// Initialize theme on page load
|
|
(function() {
|
|
const savedTheme = localStorage.getItem('theme');
|
|
const prefersLight = window.matchMedia('(prefers-color-scheme: light)').matches;
|
|
// Only set light mode if explicitly saved or system prefers light
|
|
if (savedTheme === 'light' || (!savedTheme && prefersLight)) {
|
|
document.documentElement.setAttribute('data-theme', 'light');
|
|
}
|
|
// Dark is default, no attribute needed
|
|
})();
|
|
|
|
// Theme toggle handler
|
|
document.getElementById('themeToggle').addEventListener('click', function() {
|
|
const currentTheme = document.documentElement.getAttribute('data-theme');
|
|
const isLight = currentTheme === 'light';
|
|
if (isLight) {
|
|
document.documentElement.removeAttribute('data-theme');
|
|
localStorage.setItem('theme', 'dark');
|
|
} else {
|
|
document.documentElement.setAttribute('data-theme', 'light');
|
|
localStorage.setItem('theme', 'light');
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<!-- Custom JS -->
|
|
<script src="/js/admin.js"></script>
|
|
</body>
|
|
</html>
|