Sindbad~EG File Manager
<?php
if (!defined('APP_NAME')) {
require_once __DIR__ . '/../config/config.php';
}
$pageTitle = $pageTitle ?? APP_NAME;
$currentPage = basename($_SERVER['PHP_SELF'], '.php');
// Get settings for header
$db = Database::getInstance()->getConnection();
$stmt = $db->query("SELECT * FROM general_settings ORDER BY id DESC LIMIT 1");
$headerSettings = $stmt->fetch();
// Default settings if none exist
$headerSettings = array_merge([
'site_title' => APP_NAME,
'theme_primary_color' => '#1E40AF',
'theme_secondary_color' => '#F97316'
], $headerSettings ?: []);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title><?php echo htmlspecialchars($pageTitle); ?></title>
<!-- PWA Meta Tags -->
<meta name="description" content="Comprehensive church management application for members and administrators">
<meta name="theme-color" content="#1E40AF">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="ChurchApp">
<meta name="mobile-web-app-capable" content="yes">
<!-- PWA Manifest -->
<link rel="manifest" href="<?php echo BASE_URL; ?>manifest.json">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" sizes="72x72" href="<?php echo BASE_URL; ?>assets/icons/icon-72x72.png">
<link rel="apple-touch-icon" sizes="96x96" href="<?php echo BASE_URL; ?>assets/icons/icon-96x96.png">
<link rel="apple-touch-icon" sizes="128x128" href="<?php echo BASE_URL; ?>assets/icons/icon-128x128.png">
<link rel="apple-touch-icon" sizes="144x144" href="<?php echo BASE_URL; ?>assets/icons/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="<?php echo BASE_URL; ?>assets/icons/icon-152x152.png">
<link rel="apple-touch-icon" sizes="192x192" href="<?php echo BASE_URL; ?>assets/icons/icon-192x192.png">
<link rel="apple-touch-icon" sizes="384x384" href="<?php echo BASE_URL; ?>assets/icons/icon-384x384.png">
<link rel="apple-touch-icon" sizes="512x512" href="<?php echo BASE_URL; ?>assets/icons/icon-512x512.png">
<!-- Standard Icons -->
<link rel="icon" type="image/png" sizes="32x32" href="<?php echo BASE_URL; ?>assets/icons/icon-72x72.png">
<link rel="icon" type="image/png" sizes="16x16" href="<?php echo BASE_URL; ?>assets/icons/icon-72x72.png">
<!-- Microsoft Tiles -->
<meta name="msapplication-TileColor" content="#1E40AF">
<meta name="msapplication-TileImage" content="<?php echo BASE_URL; ?>assets/icons/icon-144x144.png">
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Custom Tailwind Config -->
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#1E40AF',
secondary: '#F97316',
accent: '#9333EA',
golden: '#FBBF24'
}
}
}
}
</script>
<!-- Font Awesome for Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<!-- Custom Styles -->
<style>
* {
font-family: 'Inter', sans-serif;
}
.gradient-bg {
background: linear-gradient(135deg, #1E40AF 0%, #9333EA 50%, #F97316 100%);
}
.gradient-primary {
background: linear-gradient(135deg, #1E40AF 0%, #9333EA 100%);
}
.gradient-secondary {
background: linear-gradient(135deg, #F97316 0%, #FBBF24 100%);
}
.gradient-tertiary {
background: linear-gradient(135deg, #9333EA 0%, #F97316 100%);
}
.gradient-text {
background: linear-gradient(135deg, #1E40AF 0%, #F97316 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.card-hover {
transition: all 0.3s ease;
}
.card-hover:hover {
transform: translateY(-5px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
}
.btn-gradient {
background: linear-gradient(135deg, #1E40AF 0%, #9333EA 100%);
transition: all 0.3s ease;
}
.btn-gradient:hover {
box-shadow: 0 10px 30px rgba(30, 64, 175, 0.4);
transform: translateY(-2px);
}
.btn-gradient-orange {
background: linear-gradient(135deg, #F97316 0%, #FBBF24 100%);
transition: all 0.3s ease;
}
.btn-gradient-orange:hover {
box-shadow: 0 10px 30px rgba(249, 115, 22, 0.4);
transform: translateY(-2px);
}
.sidebar {
transition: transform 0.3s ease;
}
@media (max-width: 768px) {
.sidebar-hidden {
transform: translateX(-100%);
}
}
.notification-badge {
position: absolute;
top: -5px;
right: -5px;
background: #EF4444;
color: white;
border-radius: 9999px;
padding: 2px 6px;
font-size: 0.75rem;
}
/* PWA Install Button Styles */
#pwa-install-btn {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 1000;
display: none;
}
@keyframes animate-bounce {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-10px);
}
}
.animate-bounce {
animation: animate-bounce 1s infinite;
}
</style>
<!-- PWA Install Script -->
<script src="<?php echo BASE_URL; ?>assets/js/pwa-install.js" defer></script>
<!-- Service Worker Registration -->
<script>
// Register Service Worker for PWA
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('<?php echo BASE_URL; ?>service-worker.js')
.then((registration) => {
console.log('Service Worker registered successfully:', registration.scope);
// Check for updates every hour
setInterval(() => {
registration.update();
}, 3600000);
// Handle service worker updates
registration.addEventListener('updatefound', () => {
const newWorker = registration.installing;
newWorker.addEventListener('statechange', () => {
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
// New service worker available
console.log('New service worker available');
}
});
});
})
.catch((error) => {
console.log('Service Worker registration failed:', error);
});
});
}
// Handle online/offline status
window.addEventListener('online', () => {
console.log('Back online');
// Optionally show notification
});
window.addEventListener('offline', () => {
console.log('Gone offline');
// Optionally show notification
});
</script>
<!-- Auto-dismiss Messages Script -->
<script>
// Global function to dismiss message boxes
function dismissMessage(elementId) {
const element = document.getElementById(elementId);
if (element) {
element.style.opacity = '0';
element.style.transform = 'translateY(-10px)';
setTimeout(function() {
element.style.display = 'none';
}, 300);
}
}
// Auto-dismiss messages after page load
document.addEventListener('DOMContentLoaded', function() {
// Find all success and error messages
const successMessages = document.querySelectorAll('[id*="success"], [id*="Success"], .success-message, .alert-success');
const errorMessages = document.querySelectorAll('[id*="error"], [id*="Error"], .error-message, .alert-danger');
// Auto-dismiss success messages after 5 seconds
setTimeout(function() {
successMessages.forEach(msg => {
if (msg.id) dismissMessage(msg.id);
else {
msg.style.opacity = '0';
msg.style.transform = 'translateY(-10px)';
setTimeout(() => msg.style.display = 'none', 300);
}
});
}, 5000);
// Auto-dismiss error messages after 8 seconds (longer for errors)
setTimeout(function() {
errorMessages.forEach(msg => {
if (msg.id) dismissMessage(msg.id);
else {
msg.style.opacity = '0';
msg.style.transform = 'translateY(-10px)';
setTimeout(() => msg.style.display = 'none', 300);
}
});
}, 8000);
});
</script>
</head>
<body class="bg-gray-50 min-h-screen">
<?php if (isLoggedIn()): ?>
<!-- Navigation Bar -->
<nav class="gradient-bg shadow-lg sticky top-0 z-50">
<div class="container mx-auto px-4">
<div class="flex items-center justify-between h-16">
<!-- Logo & Title -->
<div class="flex items-center space-x-3">
<button id="sidebarToggle" class="md:hidden text-white hover:text-yellow-200 transition">
<i class="fas fa-bars text-xl"></i>
</button>
<a href="<?php echo BASE_URL; ?>" class="flex items-center space-x-2">
<i class="fas fa-church text-2xl text-white"></i>
<span class="text-white font-bold text-lg hidden sm:inline"><?php echo htmlspecialchars($headerSettings['site_title']); ?></span>
</a>
</div>
<!-- Right Side Menu -->
<div class="flex items-center space-x-4">
<!-- Time & Weather -->
<div class="hidden lg:flex items-center space-x-4 text-white text-sm">
<div id="currentTime" class="flex items-center space-x-1">
<i class="fas fa-clock"></i>
<span></span>
</div>
<div id="currentWeather" class="flex items-center space-x-1">
<i class="fas fa-cloud-sun"></i>
<span>Loading...</span>
</div>
</div>
<!-- Notifications -->
<div class="relative">
<button id="notificationBtn" class="text-white hover:text-yellow-200 transition relative">
<i class="fas fa-bell text-xl"></i>
<span id="notificationCount" class="notification-badge hidden">0</span>
</button>
<!-- Notification Dropdown -->
<div id="notificationDropdown" class="hidden absolute right-0 mt-2 w-80 bg-white rounded-lg shadow-xl overflow-hidden z-50">
<div class="p-4 text-white gradient-bg">
<h3 class="font-semibold">Notifications</h3>
</div>
<div id="notificationList" class="max-h-96 overflow-y-auto">
<!-- Notifications will be loaded here -->
</div>
</div>
</div>
<!-- User Menu -->
<div class="relative">
<button id="userMenuBtn" class="flex items-center space-x-2 text-white hover:text-yellow-200 transition">
<img src="<?php echo getCurrentUserPhoto(); ?>"
alt="Profile"
class="w-8 h-8 rounded-full border-2 border-white object-cover">
<span class="hidden md:inline font-medium"><?php echo htmlspecialchars(getCurrentUserName()); ?></span>
<i class="fas fa-chevron-down text-xs"></i>
</button>
<!-- User Dropdown -->
<div id="userDropdown" class="hidden absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-xl overflow-hidden z-50">
<a href="<?php echo BASE_URL; ?>profile.php" class="block px-4 py-3 hover:bg-gray-100 transition">
<i class="fas fa-user mr-2 text-blue-500"></i> Profile
</a>
<a href="<?php echo BASE_URL; ?>modules/settings/index.php" class="block px-4 py-3 hover:bg-gray-100 transition">
<i class="fas fa-cog mr-2 text-gray-500"></i> Settings
</a>
<hr class="my-1">
<a href="<?php echo BASE_URL; ?>logout.php" class="block px-4 py-3 hover:bg-red-50 text-red-600 transition">
<i class="fas fa-sign-out-alt mr-2"></i> Logout
</a>
</div>
</div>
</div>
</div>
</div>
</nav>
<?php endif; ?>
<script>
// Toggle dropdowns
document.addEventListener('DOMContentLoaded', function() {
// Notification dropdown
const notificationBtn = document.getElementById('notificationBtn');
const notificationDropdown = document.getElementById('notificationDropdown');
if (notificationBtn) {
notificationBtn.addEventListener('click', function(e) {
e.stopPropagation();
notificationDropdown.classList.toggle('hidden');
document.getElementById('userDropdown')?.classList.add('hidden');
loadNotifications();
});
}
// User dropdown
const userMenuBtn = document.getElementById('userMenuBtn');
const userDropdown = document.getElementById('userDropdown');
if (userMenuBtn) {
userMenuBtn.addEventListener('click', function(e) {
e.stopPropagation();
userDropdown.classList.toggle('hidden');
notificationDropdown?.classList.add('hidden');
});
}
// Close dropdowns when clicking outside
document.addEventListener('click', function() {
notificationDropdown?.classList.add('hidden');
userDropdown?.classList.add('hidden');
});
// Update time
function updateTime() {
const now = new Date();
const timeStr = now.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
const timeElement = document.querySelector('#currentTime span');
if (timeElement) {
timeElement.textContent = timeStr;
}
}
updateTime();
setInterval(updateTime, 1000);
// Load weather
loadWeather();
// Load notification count
loadNotificationCount();
});
// Load weather
function loadWeather() {
// Using OpenWeatherMap API (you'll need to add your API key)
const weatherElement = document.querySelector('#currentWeather span');
if (weatherElement) {
weatherElement.textContent = '25°C Sunny';
}
}
// Load notification count
function loadNotificationCount() {
fetch('<?php echo BASE_URL; ?>api/notifications.php?action=count')
.then(response => response.json())
.then(data => {
if (data.count > 0) {
document.getElementById('notificationCount').textContent = data.count;
document.getElementById('notificationCount').classList.remove('hidden');
}
});
}
// Load notifications
function loadNotifications() {
fetch('<?php echo BASE_URL; ?>api/notifications.php?action=list')
.then(response => response.json())
.then(data => {
const list = document.getElementById('notificationList');
if (data.notifications && data.notifications.length > 0) {
list.innerHTML = data.notifications.map(n => `
<div class="p-4 border-b hover:bg-gray-50 cursor-pointer ${n.is_read ? 'opacity-60' : ''}">
<div class="flex justify-between items-start">
<div class="flex-1">
<h4 class="font-semibold text-sm text-gray-800">${n.title}</h4>
<p class="text-xs text-gray-600 mt-1">${n.message}</p>
<span class="text-xs text-gray-400 mt-1 block">${n.time_ago}</span>
</div>
${!n.is_read ? '<div class="w-2 h-2 bg-blue-500 rounded-full ml-2"></div>' : ''}
</div>
</div>
`).join('');
} else {
list.innerHTML = '<div class="p-8 text-center text-gray-500"><i class="fas fa-bell-slash text-3xl mb-2"></i><p>No notifications</p></div>';
}
});
}
</script>
<!-- PWA Install Button -->
<button id="pwa-install-btn"
onclick="installPWA()"
class="flex items-center justify-center w-16 h-16 rounded-full shadow-2xl text-white hover:scale-110 transition-transform duration-300"
style="background: linear-gradient(135deg, #1E40AF 0%, #9333EA 50%, #F97316 100%);"
title="Install App">
<i class="fas fa-download text-2xl"></i>
</button>
</body>
</html>
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists