This commit is contained in:
Flatlogic Bot 2026-02-25 22:06:24 +00:00
parent 01072acc88
commit 3d02f25bbd
13 changed files with 531 additions and 16 deletions

View File

@ -0,0 +1,38 @@
<?php
namespace App\Controllers;
use App\Core\Controller;
class AIController extends Controller {
public function chat() {
header('Content-Type: application/json');
$input = json_decode(file_get_contents('php://input'), true);
$userMessage = $input['message'] ?? '';
if (empty($userMessage)) {
echo json_encode(['error' => 'Message is empty']);
return;
}
require_once __DIR__ . '/../../ai/LocalAIApi.php';
$systemPrompt = "You are a helpful assistant for " . get_setting('site_name', 'ApkNusa') . ", an APK downloader and tech blog site. Provide concise and accurate information about Android apps, games, and technology. Be youthful and professional.";
$resp = \LocalAIApi::createResponse([
'input' => [
['role' => 'system', 'content' => $systemPrompt],
['role' => 'user', 'content' => $userMessage],
],
]);
if (!empty($resp['success'])) {
$text = \LocalAIApi::extractText($resp);
echo json_encode(['reply' => $text]);
} else {
echo json_encode(['error' => 'AI Assistant is currently unavailable.']);
}
}
}

View File

@ -54,11 +54,18 @@ class AdminController extends Controller {
'total_downloads' => $this->getTotalDownloads(),
'total_users' => $db->query("SELECT COUNT(*) FROM users")->fetchColumn(),
'pending_withdrawals' => $db->query("SELECT COUNT(*) FROM withdrawals WHERE status = 'pending'")->fetchColumn(),
'recent_apks' => array_slice($apkService->getAllApks(), 0, 5)
'recent_apks' => array_slice($apkService->getAllApks(), 0, 5),
'referral_stats' => $this->getReferralStats()
];
$this->view('admin/dashboard', $stats);
}
private function getReferralStats() {
$db = db_pdo();
$stmt = $db->query("SELECT DATE(created_at) as date, COUNT(*) as count FROM referral_downloads WHERE created_at > DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY DATE(created_at) ORDER BY date ASC");
return $stmt->fetchAll();
}
private function getTotalDownloads() {
$db = db_pdo();
return $db->query("SELECT SUM(total_downloads) FROM apks")->fetchColumn() ?: 0;
@ -239,6 +246,7 @@ class AdminController extends Controller {
$this->checkAuth();
$settings = [
'site_name' => get_setting('site_name'),
'contact_email' => get_setting('contact_email'),
'site_icon' => get_setting('site_icon'),
'site_favicon' => get_setting('site_favicon'),
'meta_description' => get_setting('meta_description'),
@ -251,6 +259,7 @@ class AdminController extends Controller {
'github_url' => get_setting('github_url'),
'telegram_url' => get_setting('telegram_url'),
'whatsapp_url' => get_setting('whatsapp_url'),
'maintenance_mode' => get_setting('maintenance_mode'),
];
$this->view('admin/settings', ['settings' => $settings]);
}
@ -260,7 +269,7 @@ class AdminController extends Controller {
$db = db_pdo();
$fields = [
'site_name', 'meta_description', 'meta_keywords', 'head_js', 'body_js',
'site_name', 'contact_email', 'meta_description', 'meta_keywords', 'head_js', 'body_js',
'facebook_url', 'twitter_url', 'instagram_url', 'github_url', 'telegram_url', 'whatsapp_url'
];
foreach ($fields as $field) {

View File

@ -0,0 +1,45 @@
<?php
namespace App\Controllers;
use App\Core\Controller;
use MailService;
class ContactController extends Controller {
public function index() {
$this->view('contact', [
'title' => __('contact_us') . ' - ' . get_setting('site_name', 'ApkNusa')
]);
}
public function submit() {
$name = $_POST['name'] ?? '';
$email = $_POST['email'] ?? '';
$subject = $_POST['subject'] ?? 'New Contact Message';
$message = $_POST['message'] ?? '';
if (empty($name) || empty($email) || empty($message)) {
$_SESSION['error'] = 'All fields are required.';
$this->redirect('/contact');
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$_SESSION['error'] = 'Invalid email address.';
$this->redirect('/contact');
}
require_once __DIR__ . '/../../mail/MailService.php';
$res = \MailService::sendContactMessage($name, $email, $message, null, $subject);
if (!empty($res['success'])) {
$_SESSION['success'] = 'Your message has been sent successfully!';
} else {
$_SESSION['error'] = 'Failed to send message. Please try again later.';
// Log error if needed: error_log($res['error']);
}
$this->redirect('/contact');
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\Controllers;
use App\Core\Controller;
class NewsletterController extends Controller {
public function subscribe() {
header('Content-Type: application/json');
$input = json_decode(file_get_contents('php://input'), true);
$email = $input['email'] ?? '';
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo json_encode(['error' => 'Please provide a valid email address.']);
return;
}
$db = db_pdo();
try {
$stmt = $db->prepare("INSERT INTO newsletter_subscribers (email) VALUES (?)");
$stmt->execute([$email]);
echo json_encode(['success' => 'Thank you for subscribing!']);
} catch (\PDOException $e) {
if ($e->getCode() == 23000) { // Duplicate entry
echo json_encode(['success' => 'You are already subscribed!']);
} else {
echo json_encode(['error' => 'An error occurred. Please try again.']);
}
}
}
}

View File

@ -38,10 +38,21 @@ class SitemapController extends Controller {
echo '</url>';
}
// Blog Posts
$posts = $db->query("SELECT * FROM posts WHERE status = 'published'")->fetchAll();
foreach ($posts as $post) {
echo '<url>';
echo '<loc>' . $baseUrl . '/blog/' . htmlspecialchars($post['slug']) . '</loc>';
echo '<lastmod>' . date('Y-m-d', strtotime($post['created_at'] ?? 'now')) . '</lastmod>';
echo '<priority>0.7</priority>';
echo '<changefreq>monthly</changefreq>';
echo '</url>';
}
// Categories (if you have category pages, assuming /category/slug)
foreach ($categories as $category) {
echo '<url>';
echo '<loc>' . $baseUrl . '/category/' . htmlspecialchars($category['slug']) . '</loc>';
echo '<loc>' . $baseUrl . '/?category=' . htmlspecialchars($category['slug']) . '</loc>';
echo '<priority>0.6</priority>';
echo '<changefreq>weekly</changefreq>';
echo '</url>';

View File

@ -91,13 +91,6 @@ document.addEventListener('DOMContentLoaded', () => {
dropdownBtn.innerHTML = `${categoryName} <i class="bi bi-chevron-down ms-1 small"></i>`;
}
// Update title if not searching
if (latestTitle && !url.includes('search=')) {
// We could use translations here but for simplicity we'll just use the category name
// if it's All Categories, we'll reset to original (usually "Latest APKs")
// However, we'll just keep it simple for now.
}
// Update URL without refreshing
window.history.pushState({ category: category }, '', url);
})
@ -115,6 +108,90 @@ document.addEventListener('DOMContentLoaded', () => {
});
};
// AI Chat Assistant Logic
const initAIChat = () => {
const toggleBtn = document.getElementById('toggle-ai-chat');
const closeBtn = document.getElementById('close-ai-chat');
const chatWindow = document.getElementById('ai-chat-window');
const chatInput = document.getElementById('ai-chat-input');
const sendBtn = document.getElementById('send-ai-chat');
const messagesContainer = document.getElementById('ai-chat-messages');
if (!toggleBtn || !chatWindow) return;
toggleBtn.addEventListener('click', () => {
chatWindow.classList.toggle('d-none');
if (!chatWindow.classList.contains('d-none')) {
chatInput.focus();
}
});
closeBtn.addEventListener('click', () => {
chatWindow.classList.add('d-none');
});
const appendMessage = (message, isUser = false) => {
const div = document.createElement('div');
div.className = 'mb-3 d-flex ' + (isUser ? 'justify-content-end' : '');
const content = document.createElement('div');
content.className = (isUser ? 'bg-success text-white' : 'bg-white') + ' p-3 rounded-4 shadow-sm small';
content.style.maxWidth = '85%';
if (isUser) {
content.style.borderBottomRightRadius = '0';
} else {
content.style.borderBottomLeftRadius = '0';
}
content.textContent = message;
div.appendChild(content);
messagesContainer.appendChild(div);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
};
const sendMessage = () => {
const message = chatInput.value.trim();
if (!message) return;
appendMessage(message, true);
chatInput.value = '';
// Loading state
const loadingDiv = document.createElement('div');
loadingDiv.className = 'mb-3 d-flex';
loadingDiv.innerHTML = '<div class="bg-white p-3 rounded-4 shadow-sm small" style="border-bottom-left-radius: 0 !important;"><div class="spinner-border spinner-border-sm text-success" role="status"></div> Thinking...</div>';
messagesContainer.appendChild(loadingDiv);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
fetch('/api/ai/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ message: message })
})
.then(response => response.json())
.then(data => {
messagesContainer.removeChild(loadingDiv);
if (data.reply) {
appendMessage(data.reply);
} else {
appendMessage(data.error || 'Sorry, something went wrong.');
}
})
.catch(err => {
messagesContainer.removeChild(loadingDiv);
appendMessage('Error connecting to AI assistant.');
console.error(err);
});
};
sendBtn.addEventListener('click', sendMessage);
chatInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') sendMessage();
});
};
// Initial Sync
const currentTheme = html.getAttribute('data-theme') || 'light';
updateIcons(currentTheme);
@ -132,6 +209,7 @@ document.addEventListener('DOMContentLoaded', () => {
initThemeToggle('theme-toggle');
initThemeToggle('theme-toggle-mobile');
initCategoryAjax();
initAIChat();
console.log('ApkNusa ready.');
});
});

View File

@ -28,7 +28,19 @@ session_start();
use App\Core\Router;
// Maintenance Mode Check
if (get_setting('maintenance_mode') === '1') {
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$isAdmin = strpos($uri, '/admin') === 0 || strpos($uri, '/login') === 0 || strpos($uri, '/logout') === 0;
if (!$isAdmin && !isset($_SESSION['admin_id'])) {
require_once 'views/maintenance.php';
exit;
}
}
$router = new Router();
$router->post('/api/newsletter/subscribe', 'NewsletterController@subscribe');
$router->post('/api/ai/chat', 'AIController@chat');
// Sitemap
$router->get('/sitemap.xml', 'SitemapController@index');
@ -51,6 +63,8 @@ $router->get('/blog', 'BlogController@index');
$router->get('/blog/:slug', 'BlogController@detail');
// Static Pages
$router->get('/contact', 'ContactController@index');
$router->post('/contact', 'ContactController@submit');
$router->get('/help-center', 'HomeController@helpCenter');
$router->get('/privacy-policy', 'HomeController@privacyPolicy');
$router->get('/terms-of-service', 'HomeController@termsOfService');

View File

@ -1,8 +1,12 @@
<?php include __DIR__ . '/../header.php'; ?>
<div class="container-fluid py-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<div class="d-flex align-items-center mb-4">
<h1 class="h3 mb-0 text-gray-800">Manage APKs</h1>
<form action="/admin/apks" method="GET" class="d-flex gap-2 ms-auto me-3">
<input type="text" name="search" class="form-control form-control-sm" placeholder="Search APKs..." value="<?php echo htmlspecialchars($_GET['search'] ?? ''); ?>">
<button type="submit" class="btn btn-sm btn-outline-secondary"><i class="bi bi-search"></i></button>
</form>
<a href="/admin/apks/add" class="btn btn-primary shadow-sm">
<i class="bi bi-plus-lg me-1"></i> Add New APK
</a>

View File

@ -79,6 +79,68 @@
</div>
</div>
<div class="row mb-4">
<div class="col-12">
<div class="card shadow-sm border-0 rounded-4 bg-white">
<div class="card-header bg-white py-3 border-bottom border-light d-flex justify-content-between align-items-center">
<h6 class="m-0 font-weight-bold text-primary fw-bold">Referral Downloads (Last 7 Days)</h6>
</div>
<div class="card-body">
<canvas id="referralChart" style="height: 300px; width: 100%;"></canvas>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const ctx = document.getElementById('referralChart').getContext('2d');
const stats = <?php echo json_encode($referral_stats); ?>;
const labels = stats.map(s => s.date);
const counts = stats.map(s => s.count);
new Chart(ctx, {
type: 'line',
data: {
labels: labels.length ? labels : ['No Data'],
datasets: [{
label: 'Referral Downloads',
data: counts.length ? counts : [0],
borderColor: '#10B981',
backgroundColor: 'rgba(16, 185, 129, 0.1)',
fill: true,
tension: 0.4,
pointRadius: 5,
pointBackgroundColor: '#10B981'
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
scales: {
y: {
beginAtZero: true,
grid: {
color: 'rgba(0, 0, 0, 0.05)'
}
},
x: {
grid: {
display: false
}
}
}
}
});
});
</script>
<div class="row g-4">
<div class="col-lg-8">
<div class="card shadow-sm border-0 rounded-4 mb-4 bg-white">

View File

@ -10,6 +10,10 @@
<div class="card-body p-4">
<form action="/admin/settings" method="POST" enctype="multipart/form-data">
<div class="mb-4">
<div class="mb-4">
<label class="form-label fw-semibold">Contact Email</label>
<input type="email" name="contact_email" class="form-control" value="<?php echo htmlspecialchars($settings['contact_email'] ?? ''); ?>" placeholder="support@yourdomain.com">
</div>
<label class="form-label fw-semibold"><?php echo __('site_name'); ?></label>
<input type="text" name="site_name" class="form-control form-control-lg" value="<?php echo htmlspecialchars($settings['site_name']); ?>" required>
</div>
@ -35,6 +39,16 @@
</div>
</div>
<div class="mb-4 p-3 bg-light rounded border">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="maintenance_mode" value="1" id="maintenanceMode" <?php echo ($settings['maintenance_mode'] ?? '0') === '1' ? 'checked' : ''; ?>>
<label class="form-check-label fw-bold" for="maintenanceMode">
<i class="fas fa-tools me-2 text-warning"></i>Maintenance Mode
</label>
</div>
<div class="form-text mt-1">When enabled, regular visitors will see a maintenance page. Admins can still access the site.</div>
</div>
<hr class="my-4">
<h5 class="fw-bold mb-3"><i class="fas fa-share-alt me-2"></i>Social Media Settings</h5>
@ -129,4 +143,4 @@
</div>
</div>
<?php include 'footer.php'; ?>
<?php include 'footer.php'; ?>

78
views/contact.php Normal file
View File

@ -0,0 +1,78 @@
<?php include 'header.php'; ?>
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card shadow border-0 rounded-4 overflow-hidden">
<div class="row g-0">
<div class="col-lg-5 bg-success p-5 text-white d-flex flex-column justify-content-center">
<h2 class="fw-bold mb-4">Get in Touch</h2>
<p class="mb-4 opacity-75">Have questions or feedback about our APKs? We'd love to hear from you. Send us a message and we'll respond as soon as possible.</p>
<div class="d-flex align-items-center mb-3">
<i class="bi bi-geo-alt-fill me-3 fs-4"></i>
<span>Jakarta, Indonesia</span>
</div>
<div class="d-flex align-items-center mb-3">
<i class="bi bi-envelope-fill me-3 fs-4"></i>
<span><?php echo get_setting('contact_email', 'support@apknusa.com'); ?></span>
</div>
<div class="mt-4 pt-4 border-top border-white border-opacity-25">
<h6 class="fw-bold mb-3">Follow Us</h6>
<div class="d-flex gap-3">
<?php if($fb = get_setting('facebook_url')): ?><a href="<?php echo $fb; ?>" class="text-white fs-5"><i class="bi bi-facebook"></i></a><?php endif; ?>
<?php if($tw = get_setting('twitter_url')): ?><a href="<?php echo $tw; ?>" class="text-white fs-5"><i class="bi bi-twitter-x"></i></a><?php endif; ?>
<?php if($ig = get_setting('instagram_url')): ?><a href="<?php echo $ig; ?>" class="text-white fs-5"><i class="bi bi-instagram"></i></a><?php endif; ?>
<?php if($tg = get_setting('telegram_url')): ?><a href="<?php echo $tg; ?>" class="text-white fs-5"><i class="bi bi-telegram"></i></a><?php endif; ?>
</div>
</div>
</div>
<div class="col-lg-7 p-5 bg-white">
<?php if (isset($_SESSION['success'])): ?>
<div class="alert alert-success alert-dismissible fade show rounded-3 mb-4" role="alert">
<i class="bi bi-check-circle-fill me-2"></i>
<?php echo $_SESSION['success']; unset($_SESSION['success']); ?>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<?php if (isset($_SESSION['error'])): ?>
<div class="alert alert-danger alert-dismissible fade show rounded-3 mb-4" role="alert">
<i class="bi bi-exclamation-triangle-fill me-2"></i>
<?php echo $_SESSION['error']; unset($_SESSION['error']); ?>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<form action="/contact" method="POST">
<div class="mb-3">
<label class="form-label fw-bold small text-uppercase">Full Name</label>
<input type="text" name="name" class="form-control form-control-lg bg-light border-0 px-4" placeholder="Your Name" required>
</div>
<div class="mb-3">
<label class="form-label fw-bold small text-uppercase">Email Address</label>
<input type="email" name="email" class="form-control form-control-lg bg-light border-0 px-4" placeholder="name@example.com" required>
</div>
<div class="mb-3">
<label class="form-label fw-bold small text-uppercase">Subject</label>
<input type="text" name="subject" class="form-control form-control-lg bg-light border-0 px-4" placeholder="How can we help?">
</div>
<div class="mb-4">
<label class="form-label fw-bold small text-uppercase">Message</label>
<textarea name="message" class="form-control bg-light border-0 px-4 py-3" rows="4" placeholder="Your message here..." required></textarea>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-success btn-lg rounded-pill py-3 fw-bold">
Send Message <i class="bi bi-send-fill ms-2"></i>
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<?php include 'footer.php'; ?>

View File

@ -30,15 +30,17 @@
<li><a href="/help-center" class="text-muted text-decoration-none py-1 d-block small"><?php echo __('support_center'); ?></a></li>
<li><a href="/terms-of-service" class="text-muted text-decoration-none py-1 d-block small"><?php echo __('terms_of_service'); ?></a></li>
<li><a href="/privacy-policy" class="text-muted text-decoration-none py-1 d-block small"><?php echo __('privacy_policy'); ?></a></li>
<li><a href="/contact" class="text-muted text-decoration-none py-1 d-block small">Contact Us</a></li>
</ul>
</div>
<div class="col-lg-4">
<h6 class="fw-bold mb-3"><?php echo __('subscribe'); ?></h6>
<p class="text-muted small"><?php echo __('subscribe_text'); ?></p>
<div class="input-group">
<input type="email" class="form-control border-light-subtle" placeholder="<?php echo __('email_placeholder'); ?>">
<button class="btn btn-success px-3" type="button"><?php echo __('subscribe'); ?></button>
<input type="email" id="newsletter-email" class="form-control border-light-subtle" placeholder="<?php echo __('email_placeholder'); ?>">
<button class="btn btn-success px-3" id="newsletter-btn" type="button"><?php echo __('subscribe'); ?></button>
</div>
<div id="newsletter-msg" class="mt-2 small"></div>
</div>
</div>
<hr class="my-5 text-black-50 opacity-25">
@ -71,8 +73,85 @@
</div>
</div>
</footer>
<!-- AI Chat Assistant -->
<div id="ai-chat-wrapper" class="fixed-bottom p-3 d-flex flex-column align-items-end" style="z-index: 1050; pointer-events: none;">
<div id="ai-chat-window" class="card shadow-lg border-0 mb-3 d-none" style="width: 350px; max-width: 90vw; height: 450px; pointer-events: auto; border-radius: 20px;">
<div class="card-header bg-success text-white py-3 d-flex justify-content-between align-items-center" style="border-radius: 20px 20px 0 0;">
<div class="d-flex align-items-center">
<div class="bg-white rounded-circle p-1 me-2">
<i class="bi bi-robot text-success"></i>
</div>
<span class="fw-bold">ApkNusa AI</span>
</div>
<button type="button" class="btn-close btn-close-white" id="close-ai-chat"></button>
</div>
<div class="card-body overflow-auto p-3" id="ai-chat-messages" style="background: var(--subtle-bg);">
<div class="mb-3">
<div class="bg-white p-3 rounded-4 shadow-sm small" style="max-width: 85%; border-bottom-left-radius: 0 !important;">
Hello! How can I help you today?
</div>
</div>
</div>
<div class="card-footer bg-white border-0 p-3" style="border-radius: 0 0 20px 20px;">
<div class="input-group">
<input type="text" id="ai-chat-input" class="form-control border-light-subtle rounded-pill-start px-3" placeholder="Type a message...">
<button class="btn btn-success rounded-pill-end px-3" id="send-ai-chat">
<i class="bi bi-send-fill"></i>
</button>
</div>
</div>
</div>
<button class="btn btn-success shadow-lg d-flex align-items-center justify-content-center p-0 rounded-circle" id="toggle-ai-chat" style="width: 60px; height: 60px; pointer-events: auto;">
<i class="bi bi-chat-dots-fill fs-3"></i>
</button>
</div>
<style>
#ai-chat-messages::-webkit-scrollbar {
width: 4px;
}
#ai-chat-messages::-webkit-scrollbar-thumb {
background: #10B981;
border-radius: 10px;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="/assets/js/main.js?v=<?php echo time(); ?>"></script>
<script>
document.getElementById('newsletter-btn').addEventListener('click', function() {
const email = document.getElementById('newsletter-email').value;
const msg = document.getElementById('newsletter-msg');
if (!email) return;
this.disabled = true;
this.innerHTML = '<span class="spinner-border spinner-border-sm"></span>';
fetch('/api/newsletter/subscribe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: email })
})
.then(res => res.json())
.then(data => {
this.disabled = false;
this.innerHTML = '<?php echo __("subscribe"); ?>';
if (data.success) {
msg.innerHTML = '<span class="text-success">' + data.success + '</span>';
document.getElementById('newsletter-email').value = '';
} else {
msg.innerHTML = '<span class="text-danger">' + data.error + '</span>';
}
})
.catch(err => {
this.disabled = false;
this.innerHTML = '<?php echo __("subscribe"); ?>';
msg.innerHTML = '<span class="text-danger">An error occurred.</span>';
});
});
</script>
<?php echo get_setting('body_js'); ?>
</body>
</html>
</html>

50
views/maintenance.php Normal file
View File

@ -0,0 +1,50 @@
<?php
$currentTheme = \App\Services\ThemeService::getCurrent();
?>
<!DOCTYPE html>
<html lang="en" data-theme="<?php echo $currentTheme; ?>">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Under Maintenance - <?php echo htmlspecialchars(get_setting('site_name', 'ApkNusa')); ?></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
<link rel="stylesheet" href="/assets/css/custom.css?v=<?php echo time(); ?>">
<style>
body {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
text-align: center;
background: var(--bg-color);
color: var(--text-color);
}
.maintenance-container {
max-width: 500px;
padding: 2rem;
background: var(--card-bg);
border-radius: 24px;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
border: 1px solid var(--border-color);
}
.icon-wrapper {
font-size: 5rem;
color: #10B981;
margin-bottom: 1.5rem;
}
</style>
</head>
<body>
<div class="maintenance-container">
<div class="icon-wrapper">
<i class="bi bi-tools"></i>
</div>
<h1 class="fw-bold mb-3">Under Maintenance</h1>
<p class="text-muted mb-4">We're currently performing some scheduled maintenance. We'll be back shortly. Thank you for your patience!</p>
<div class="d-flex justify-content-center gap-3">
<a href="mailto:<?php echo get_setting('contact_email'); ?>" class="btn btn-outline-success rounded-pill px-4">Contact Support</a>
</div>
</div>
</body>
</html>