this push will conclude the majority of pulls. this repos will now, not be actively be managed or any further code pushes will not be frequent.
509 lines
29 KiB
HTML
509 lines
29 KiB
HTML
{{ define "layout" }}
|
|
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<link rel="icon" type="image/x-icon" href="../../static/favicon.ico">
|
|
|
|
<title>{{if .Title}}{{.Title}}{{else}}Poll System{{end}}</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<script src="//unpkg.com/alpinejs" defer></script>
|
|
|
|
<link
|
|
rel="stylesheet"
|
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"
|
|
/>
|
|
<script>
|
|
tailwind.config = {
|
|
theme: {
|
|
extend: {
|
|
colors: {
|
|
"custom-gray": "#f8fafc",
|
|
"sidebar-gray": "#ffffff",
|
|
"border-gray": "#e2e8f0",
|
|
"text-primary": "#1e293b",
|
|
"text-secondary": "#64748b",
|
|
"blue-primary": "#3b82f6",
|
|
"blue-light": "#eff6ff",
|
|
},
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
<style>
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
|
|
font-size: 14px;
|
|
}
|
|
|
|
/* Mobile sidebar overlay */
|
|
.sidebar-overlay {
|
|
display: none;
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
z-index: 40;
|
|
}
|
|
|
|
.sidebar-overlay.active {
|
|
display: block;
|
|
}
|
|
|
|
/* Desktop layout - sidebar always visible */
|
|
@media (min-width: 768px) {
|
|
.main-content-container {
|
|
margin-left: 240px; /* Match sidebar width */
|
|
}
|
|
}
|
|
|
|
/* Mobile sidebar positioning */
|
|
@media (max-width: 767px) {
|
|
#sidebar {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
height: 100vh;
|
|
z-index: 50;
|
|
transform: translateX(-100%);
|
|
transition: transform 0.3s ease-in-out;
|
|
}
|
|
|
|
#sidebar.active {
|
|
transform: translateX(0);
|
|
}
|
|
|
|
.main-content-container {
|
|
margin-left: 0;
|
|
}
|
|
}
|
|
|
|
/* Ensure sidebar has fixed positioning on desktop */
|
|
@media (min-width: 768px) {
|
|
#sidebar {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
height: 100vh;
|
|
z-index: 30;
|
|
}
|
|
}
|
|
|
|
/* Hide scrollbars but keep functionality */
|
|
.hide-scrollbar {
|
|
-ms-overflow-style: none;
|
|
scrollbar-width: none;
|
|
}
|
|
.hide-scrollbar::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="bg-custom-gray">
|
|
{{ if .IsAuthenticated }}
|
|
<!-- Authenticated User Interface -->
|
|
<div class="min-h-screen">
|
|
|
|
<!-- Mobile sidebar overlay -->
|
|
<div id="sidebar-overlay" class="sidebar-overlay" onclick="toggleSidebar()"></div>
|
|
|
|
<!-- Sidebar -->
|
|
<div id="sidebar" class="w-60 bg-sidebar-gray border-r border-border-gray flex flex-col">
|
|
<!-- Logo/Header -->
|
|
<div class="flex items-center justify-between p-6 border-b border-border-gray">
|
|
<div class="flex items-center">
|
|
<div class="w-7 h-7 bg-blue-primary rounded-full flex items-center justify-center mr-3">
|
|
<img src="../../static/icon-512.png" alt="Logo" class="w-4 h-4"/>
|
|
</div>
|
|
<span class="font-semibold text-text-primary text-base">Poll System</span>
|
|
</div>
|
|
<!-- Mobile close button -->
|
|
<button id="sidebar-close" class="md:hidden text-text-secondary hover:text-text-primary" onclick="toggleSidebar()">
|
|
<i class="fas fa-times text-lg"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Navigation -->
|
|
<nav class="flex-1 py-4">
|
|
<div class="space-y-1 px-3">
|
|
{{ if .ShowAdminNav }}
|
|
<a href="/dashboard" class="flex items-center px-3 py-2.5 text-sm {{if eq .ActiveSection "dashboard"}}bg-blue-light text-blue-primary border-r-4 border-blue-primary pl-2 rounded-none{{else}}text-text-secondary hover:bg-gray-50 rounded-md{{end}} group">
|
|
<i class="fas fa-chart-pie w-5 {{if eq .ActiveSection "dashboard"}}text-blue-primary{{else}}text-gray-400{{end}} mr-3"></i>
|
|
<span {{if eq .ActiveSection "dashboard"}}class="font-medium"{{end}}>Dashboard</span>
|
|
</a>
|
|
<a href="/volunteers" class="flex items-center px-3 py-2.5 text-sm {{if eq .ActiveSection "volunteer"}}bg-blue-light text-blue-primary border-r-4 border-blue-primary pl-2 rounded-none{{else}}text-text-secondary hover:bg-gray-50 rounded-md{{end}} group">
|
|
<i class="fas fa-users w-5 {{if eq .ActiveSection "volunteer"}}text-blue-primary{{else}}text-gray-400{{end}} mr-3"></i>
|
|
<span {{if eq .ActiveSection "volunteer"}}class="font-medium"{{end}}>Volunteers</span>
|
|
</a>
|
|
<a href="/team_builder" class="flex items-center px-3 py-2.5 text-sm {{if eq .ActiveSection "team_builder"}}bg-blue-light text-blue-primary border-r-4 border-blue-primary pl-2 rounded-none{{else}}text-text-secondary hover:bg-gray-50 rounded-md{{end}} group">
|
|
<i class="fas fa-user-friends w-5 {{if eq .ActiveSection "team_builder"}}text-blue-primary{{else}}text-gray-400{{end}} mr-3"></i>
|
|
<span {{if eq .ActiveSection "team_builder"}}class="font-medium"{{end}}>Team Builder</span>
|
|
</a>
|
|
<a href="/addresses" class="flex items-center px-3 py-2.5 text-sm {{if eq .ActiveSection "address"}}bg-blue-light text-blue-primary border-r-4 border-blue-primary pl-2 rounded-none{{else}}text-text-secondary hover:bg-gray-50 rounded-md{{end}} group">
|
|
<i class="fas fa-map-marked-alt w-5 {{if eq .ActiveSection "address"}}text-blue-primary{{else}}text-gray-400{{end}} mr-3"></i>
|
|
<span {{if eq .ActiveSection "address"}}class="font-medium"{{end}}>Addresses</span>
|
|
</a>
|
|
<a href="/posts" class="flex items-center px-3 py-2.5 text-sm {{if eq .ActiveSection "posts"}}bg-blue-light text-blue-primary border-r-4 border-blue-primary pl-2 rounded-none{{else}}text-text-secondary hover:bg-gray-50 rounded-md{{end}} group">
|
|
<i class="fas fa-list w-5 {{if eq .ActiveSection "posts"}}text-blue-primary{{else}}text-gray-400{{end}} mr-3"></i>
|
|
<span {{if eq .ActiveSection "posts"}}class="font-medium"{{end}}>Posts</span>
|
|
</a>
|
|
<a href="/reports" class="flex items-center px-3 py-2.5 text-sm {{if eq .ActiveSection "reports"}}bg-blue-light text-blue-primary border-r-4 border-blue-primary pl-2 rounded-none{{else}}text-text-secondary hover:bg-gray-50 rounded-md{{end}} group">
|
|
<i class="fas fa-table w-5 {{if eq .ActiveSection "reports"}}text-blue-primary{{else}}text-gray-400{{end}} mr-3"></i>
|
|
<span {{if eq .ActiveSection "reports"}}class="font-medium"{{end}}>Reports</span>
|
|
</a>
|
|
{{ end }}
|
|
|
|
{{ if .ShowVolunteerNav }}
|
|
<a href="/volunteer/dashboard" class="flex items-center px-3 py-2.5 text-sm {{if eq .ActiveSection "dashboard"}}bg-blue-light text-blue-primary border-r-4 border-blue-primary pl-2 rounded-none{{else}}text-text-secondary hover:bg-gray-50 rounded-md{{end}} group">
|
|
<i class="fas fa-chart-pie w-5 {{if eq .ActiveSection "dashboard"}}text-blue-primary{{else}}text-gray-400{{end}} mr-3"></i>
|
|
<span {{if eq .ActiveSection "dashboard"}}class="font-medium"{{end}}>Dashboard</span>
|
|
</a>
|
|
<a href="/volunteer/addresses" class="flex items-center px-3 py-2.5 text-sm {{if eq .ActiveSection "address"}}bg-blue-light text-blue-primary border-r-4 border-blue-primary pl-2 rounded-none{{else}}text-text-secondary hover:bg-gray-50 rounded-md{{end}} group">
|
|
<i class="fas fa-home w-5 {{if eq .ActiveSection "address"}}text-blue-primary{{else}}text-gray-400{{end}} mr-3"></i>
|
|
<span {{if eq .ActiveSection "address"}}class="font-medium"{{end}}>Assigned Address</span>
|
|
</a>
|
|
<a href="/volunteer/schedule" class="flex items-center px-3 py-2.5 text-sm {{if eq .ActiveSection "schedule"}}bg-blue-light text-blue-primary border-r-4 border-blue-primary pl-2 rounded-none{{else}}text-text-secondary hover:bg-gray-50 rounded-md{{end}} group">
|
|
<i class="fas fa-calendar-day w-5 {{if eq .ActiveSection "schedule"}}text-blue-primary{{else}}text-gray-400{{end}} mr-3"></i>
|
|
<span {{if eq .ActiveSection "schedule"}}class="font-medium"{{end}}>Schedule</span>
|
|
</a>
|
|
{{ end }}
|
|
|
|
<a href="/logout" class="flex items-center px-3 py-2.5 text-sm text-text-secondary hover:bg-gray-50 rounded-md group">
|
|
<i class="fas fa-sign-out-alt w-5 text-gray-400 mr-3"></i>
|
|
<span>Logout</span>
|
|
</a>
|
|
</div>
|
|
</nav>
|
|
</div>
|
|
|
|
<!-- Main Content Container -->
|
|
<div class="main-content-container min-h-screen flex flex-col bg-custom-gray">
|
|
<!-- Top Header -->
|
|
<div class="fixed top-0 left-0 right-0 z-20 bg-white border-b border-border-gray px-4 md:px-6 py-4">
|
|
<div class="flex items-center justify-between">
|
|
<!-- Hamburger (left aligned with consistent spacing) -->
|
|
<div class="flex items-center">
|
|
<button id="menu-toggle" class="md:hidden text-text-secondary hover:text-text-primary p-2 -ml-2" onclick="toggleSidebar()">
|
|
<i class="fas fa-bars text-lg"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Right side -->
|
|
<div class="flex items-center space-x-2 md:space-x-4">
|
|
<!-- Dark mode -->
|
|
<a href="/logout" class="text-text-secondary hover:text-text-primary p-2">
|
|
<i class="fa-solid fa-arrow-right-from-bracket text-lg"></i>
|
|
</a>
|
|
|
|
<!-- Profile (hover dropdown on desktop, click on mobile) -->
|
|
<div class="relative group cursor-pointer">
|
|
<div class="flex items-center space-x-2 md:space-x-3" onclick="toggleProfileMenu()">
|
|
<span class="text-sm font-medium text-text-primary hidden sm:block">{{.UserName}}</span>
|
|
<div class="w-8 h-8 rounded-full bg-blue-primary flex items-center justify-center text-white font-medium">
|
|
{{slice .UserName 0 1}}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Dropdown -->
|
|
<div id="profile-menu" class="absolute right-0 mt-2 w-40 bg-white border border-border-gray rounded-md shadow-lg opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50">
|
|
<a href="/profile" class="block px-4 py-2 text-sm text-text-primary hover:bg-gray-100">Profile</a>
|
|
<a href="/profile" class="block px-4 py-2 text-sm text-text-primary hover:bg-gray-100">Settings</a>
|
|
<a href="/logout" class="block px-4 py-2 text-sm text-red-600 hover:bg-gray-100">Logout</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Page Content -->
|
|
<div class="flex-1 mt-20">
|
|
{{ template "content" . }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{else}}
|
|
<!-- Split Screen Login/Register Page -->
|
|
<div class="min-h-screen flex" x-data="{ isLogin: true }">
|
|
|
|
<!-- Left Side - Image -->
|
|
<div class="hidden lg:flex flex-1 relative overflow-hidden">
|
|
<!-- Background overlay for better text readability -->
|
|
<div class="absolute inset-0 bg-gradient-to-br from-blue-500/20 to-blue-700/40 z-10"></div>
|
|
|
|
<!-- Background Image -->
|
|
<img src="../../static/feature-mobile1.jpg" alt="Welcome to Poll System" class="object-cover w-full h-full"/>
|
|
|
|
<!-- Logo and branding overlay -->
|
|
<div class="absolute top-8 left-8 z-20 flex items-center gap-3">
|
|
<div class="w-10 h-10 bg-white/20 backdrop-blur-sm rounded-full flex items-center justify-center">
|
|
<img src="../../static/icon-512.png" alt="Logo" class="w-6 h-6"/>
|
|
</div>
|
|
<span class="text-2xl font-bold text-white">Linq</span>
|
|
</div>
|
|
|
|
<!-- Welcome text overlay -->
|
|
<div class="absolute bottom-8 left-8 right-8 z-20 text-white">
|
|
<h1 class="text-4xl font-bold mb-4">Welcome to Poll System</h1>
|
|
<p class="text-xl opacity-90">Streamline your polling operations with our comprehensive management platform</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right Side - Login/Register Forms -->
|
|
<div class="flex-1 flex items-center justify-center p-6 lg:p-12 bg-white">
|
|
<div class="w-full max-w-md">
|
|
|
|
<!-- Mobile Logo (visible only on small screens) -->
|
|
<div class="lg:hidden flex items-center justify-center gap-3 mb-8">
|
|
<div class="w-10 h-10 bg-blue-primary rounded-full flex items-center justify-center">
|
|
<img src="../../static/icon-512.png" alt="Logo" class="w-6 h-6"/>
|
|
</div>
|
|
<span class="text-2xl font-bold text-text-primary">Linq</span>
|
|
</div>
|
|
|
|
<!-- Toggle Buttons -->
|
|
<div class="flex justify-center gap-1 mb-8 p-1 bg-gray-100 rounded-lg">
|
|
<button @click="isLogin = true" :class="isLogin ? 'bg-white text-blue-primary shadow-sm' : 'text-gray-600'" class="flex-1 px-4 py-2 rounded-md font-medium transition-all duration-200">
|
|
Sign In
|
|
</button>
|
|
<button @click="isLogin = false" :class="!isLogin ? 'bg-white text-blue-primary shadow-sm' : 'text-gray-600'" class="flex-1 px-4 py-2 rounded-md font-medium transition-all duration-200">
|
|
Register
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Login Form -->
|
|
<div x-show="isLogin" x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0 transform translate-x-4" x-transition:enter-end="opacity-100 transform translate-x-0">
|
|
<form action="/login" method="POST" class="space-y-6">
|
|
<div class="text-center mb-6">
|
|
<h2 class="text-3xl font-bold text-text-primary">Welcome back</h2>
|
|
<p class="text-text-secondary mt-2">Please sign in to your account</p>
|
|
</div>
|
|
|
|
<div>
|
|
<label for="login_email" class="block text-sm font-medium text-text-primary mb-2">Email Address</label>
|
|
<input type="email"
|
|
id="login_email"
|
|
name="email"
|
|
required
|
|
placeholder="Enter your email"
|
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-primary focus:border-transparent transition-colors"/>
|
|
</div>
|
|
|
|
<div>
|
|
<label for="login_password" class="block text-sm font-medium text-text-primary mb-2">Password</label>
|
|
<input type="password"
|
|
id="login_password"
|
|
name="password"
|
|
required
|
|
placeholder="Enter your password"
|
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-primary focus:border-transparent transition-colors"/>
|
|
</div>
|
|
|
|
<div class="flex items-center justify-between">
|
|
<label class="flex items-center">
|
|
<input type="checkbox" class="h-4 w-4 text-blue-primary focus:ring-blue-primary border-gray-300 rounded">
|
|
<span class="ml-2 text-sm text-text-secondary">Remember me</span>
|
|
</label>
|
|
<a href="#" class="text-sm text-blue-primary hover:text-blue-600">Forgot password?</a>
|
|
</div>
|
|
|
|
<button type="submit" class="w-full bg-blue-primary text-white py-3 rounded-lg hover:bg-blue-600 focus:ring-2 focus:ring-blue-primary focus:ring-offset-2 transition-colors font-medium">
|
|
Sign In
|
|
</button>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Register Form -->
|
|
<div x-show="!isLogin" x-transition:enter="transition ease-out duration-300" x-transition:enter-start="opacity-0 transform translate-x-4" x-transition:enter-end="opacity-100 transform translate-x-0">
|
|
<form action="/register" method="POST" class="space-y-6">
|
|
<div class="text-center mb-6">
|
|
<h2 class="text-3xl font-bold text-text-primary">Create Account</h2>
|
|
<p class="text-text-secondary mt-2">Join our polling platform today</p>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-text-primary mb-2">First Name</label>
|
|
<input type="text"
|
|
name="first_name"
|
|
required
|
|
placeholder="First Name"
|
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-primary focus:border-transparent transition-colors"/>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-text-primary mb-2">Last Name</label>
|
|
<input type="text"
|
|
name="last_name"
|
|
required
|
|
placeholder="Last Name"
|
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-primary focus:border-transparent transition-colors"/>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-text-primary mb-2">Email Address</label>
|
|
<input type="email"
|
|
name="email"
|
|
required
|
|
placeholder="Enter your email"
|
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-primary focus:border-transparent transition-colors"/>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-text-primary mb-2">Phone</label>
|
|
<input type="tel"
|
|
name="phone"
|
|
required
|
|
placeholder="Phone number"
|
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-primary focus:border-transparent transition-colors"/>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-text-primary mb-2">Role</label>
|
|
<select name="role"
|
|
required
|
|
onchange="toggleAdminCodeField()"
|
|
id="role"
|
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-primary focus:border-transparent transition-colors">
|
|
<option value="">Select Role</option>
|
|
<option value="1">Admin</option>
|
|
<option value="3">Volunteer</option>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Admin/Team Leader Code Field (hidden by default) -->
|
|
<div id="adminCodeField" class="hidden">
|
|
<label class="block text-sm font-medium text-text-primary mb-2">Access Code</label>
|
|
<input type="password"
|
|
name="admin_code"
|
|
placeholder="Enter access code"
|
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-primary focus:border-transparent transition-colors"/>
|
|
<p class="text-xs text-text-secondary mt-1">Required for Admin and Team Leader roles</p>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-text-primary mb-2">Password</label>
|
|
<input type="password"
|
|
name="password"
|
|
required
|
|
placeholder="Create a password"
|
|
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-primary focus:border-transparent transition-colors"/>
|
|
</div>
|
|
|
|
<button type="submit" class="w-full bg-blue-primary text-white py-3 rounded-lg hover:bg-blue-600 focus:ring-2 focus:ring-blue-primary focus:ring-offset-2 transition-colors font-medium">
|
|
Create Account
|
|
</button>
|
|
</form>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
<script>
|
|
// Sidebar functionality for authenticated users
|
|
function toggleSidebar() {
|
|
const sidebar = document.getElementById('sidebar');
|
|
const sidebarOverlay = document.getElementById('sidebar-overlay');
|
|
|
|
if (sidebar && sidebarOverlay) {
|
|
sidebar.classList.toggle('active');
|
|
sidebarOverlay.classList.toggle('active');
|
|
}
|
|
}
|
|
|
|
function toggleProfileMenu() {
|
|
const menu = document.getElementById('profile-menu');
|
|
if (menu) {
|
|
const isVisible = !menu.classList.contains('invisible');
|
|
if (isVisible) {
|
|
// Hide it
|
|
menu.classList.add('opacity-0', 'invisible');
|
|
menu.classList.remove('opacity-100', 'visible');
|
|
document.removeEventListener('click', outsideClickListener);
|
|
} else {
|
|
// Show it
|
|
menu.classList.remove('opacity-0', 'invisible');
|
|
menu.classList.add('opacity-100', 'visible');
|
|
setTimeout(() => {
|
|
document.addEventListener('click', outsideClickListener);
|
|
}, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
function outsideClickListener(event) {
|
|
const menu = document.getElementById('profile-menu');
|
|
const trigger = event.target.closest('.group'); // The profile button wrapper
|
|
|
|
if (menu && !menu.contains(event.target) && !trigger) {
|
|
// Hide menu
|
|
menu.classList.add('opacity-0', 'invisible');
|
|
menu.classList.remove('opacity-100', 'visible');
|
|
document.removeEventListener('click', outsideClickListener);
|
|
}
|
|
}
|
|
|
|
// Admin code field toggle for registration
|
|
function toggleAdminCodeField() {
|
|
const role = document.getElementById("role");
|
|
const field = document.getElementById("adminCodeField");
|
|
|
|
if (role && field) {
|
|
const roleValue = role.value;
|
|
if (roleValue === "1") { // Admin or Team Leader
|
|
field.classList.add("hidden");
|
|
} else {
|
|
field.classList.remove("hidden");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Close sidebar on ESC key
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape') {
|
|
const sidebar = document.getElementById('sidebar');
|
|
const sidebarOverlay = document.getElementById('sidebar-overlay');
|
|
const body = document.body;
|
|
|
|
if (sidebar && sidebarOverlay && sidebar.classList.contains('active')) {
|
|
sidebar.classList.remove('active');
|
|
sidebarOverlay.classList.remove('active');
|
|
body.style.overflow = '';
|
|
}
|
|
}
|
|
});
|
|
|
|
// Handle window resize to ensure proper mobile behavior
|
|
window.addEventListener('resize', function() {
|
|
if (window.innerWidth >= 768) {
|
|
const sidebar = document.getElementById('sidebar');
|
|
const sidebarOverlay = document.getElementById('sidebar-overlay');
|
|
const body = document.body;
|
|
|
|
if (sidebar && sidebarOverlay) {
|
|
sidebar.classList.remove('active');
|
|
sidebarOverlay.classList.remove('active');
|
|
body.style.overflow = '';
|
|
}
|
|
}
|
|
});
|
|
|
|
// Close sidebar when clicking on overlay
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const sidebarOverlay = document.getElementById('sidebar-overlay');
|
|
if (sidebarOverlay) {
|
|
sidebarOverlay.addEventListener('click', function() {
|
|
toggleSidebar();
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|
|
{{end}}
|