Files
cms-gov/app/Views/admin/layout.php

152 lines
6.0 KiB
PHP
Raw Permalink Normal View History

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<meta name="csrf-token" content="<?= csrf_hash() ?>" />
<meta name="csrf-header" content="<?= csrf_header() ?>" />
<title><?= esc($title ?? 'Admin Dashboard') ?> - Bapenda Garut</title>
<link rel="icon" type="image/png" href="<?= base_url('assets/images/favicon_1762970389090.png') ?>" />
<link rel="shortcut icon" type="image/png" href="<?= base_url('assets/images/favicon_1762970389090.png') ?>" />
<link rel="stylesheet" href="<?= base_url('assets/css/app.css') ?>">
<style>
/* Fix Editor.js toolbar z-index to stay below header */
.ce-toolbar,
.ce-inline-toolbar,
.ce-popover,
.ce-conversion-toolbar,
.ce-settings,
.ce-block-settings,
.ce-toolbar__plus,
.ce-toolbar__settings-btn,
.ce-popover__item,
.ce-popover__items,
.ce-settings__button,
.ce-toolbar__content,
.ce-toolbar__actions {
z-index: 10 !important;
}
header,
header[class*="sticky"],
header[class*="fixed"],
header.sticky,
header.fixed {
z-index: 99999 !important;
position: relative;
}
</style>
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script>
// Apply dark mode immediately if stored (before Alpine loads)
(function() {
const darkMode = JSON.parse(localStorage.getItem('darkMode') || 'false');
if (darkMode) {
document.documentElement.classList.add('dark');
}
})();
// Initialize Alpine store for dark mode
document.addEventListener('alpine:init', () => {
Alpine.store('darkMode', {
enabled: JSON.parse(localStorage.getItem('darkMode') || 'false'),
toggle() {
this.enabled = !this.enabled;
localStorage.setItem('darkMode', JSON.stringify(this.enabled));
if (this.enabled) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}
});
});
</script>
</head>
<body
x-data="{ sidebarToggle: false }"
:class="{'bg-gray-900': $store.darkMode.enabled}"
>
<!-- ===== Page Wrapper Start ===== -->
<div class="flex h-screen overflow-hidden">
<!-- ===== Sidebar Start ===== -->
<?= $this->include('admin/partials/sidebar') ?>
<!-- ===== Sidebar End ===== -->
<!-- ===== Content Area Start ===== -->
<div class="relative flex flex-col flex-1 overflow-x-hidden overflow-y-auto">
<!-- ===== Header Start ===== -->
<?= $this->include('admin/partials/navbar') ?>
<!-- ===== Header End ===== -->
<!-- ===== Main Content Start ===== -->
<main>
<div class="p-4 mx-auto max-w-7xl md:p-6">
<?php if (session()->getFlashdata('success')): ?>
<div class="mb-4 p-4 bg-green-50 border border-green-200 rounded-lg">
<p class="text-sm text-green-800"><?= esc(session()->getFlashdata('success')) ?></p>
</div>
<?php endif; ?>
<?php if (session()->getFlashdata('error')): ?>
<div class="mb-4 p-4 bg-red-50 border border-red-200 rounded-lg">
<p class="text-sm text-red-800"><?= esc(session()->getFlashdata('error')) ?></p>
</div>
<?php endif; ?>
<?= $this->renderSection('content') ?>
</div>
</main>
<!-- ===== Main Content End ===== -->
</div>
<!-- ===== Content Area End ===== -->
</div>
<!-- ===== Page Wrapper End ===== -->
<script src="<?= base_url('assets/js/app.js') ?>"></script>
<script>
// CSRF Helper for AJAX/Fetch requests
function withCsrf(options = {}) {
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
const csrfHeader = document.querySelector('meta[name="csrf-header"]')?.getAttribute('content');
if (!csrfToken || !csrfHeader) {
console.warn('CSRF token not found');
return options;
}
// Merge headers
options.headers = {
...options.headers,
[csrfHeader]: csrfToken,
};
return options;
}
// Override fetch to automatically include CSRF token
const originalFetch = window.fetch;
window.fetch = function(url, options = {}) {
// Only add CSRF for same-origin POST/PUT/DELETE requests
if (typeof url === 'string' && (url.startsWith('/') || url.startsWith(window.location.origin))) {
const method = (options.method || 'GET').toUpperCase();
if (['POST', 'PUT', 'DELETE', 'PATCH'].includes(method)) {
options = withCsrf(options);
}
}
return originalFetch(url, options);
};
// Update CSRF token in meta tags after form submission
document.addEventListener('DOMContentLoaded', function() {
// Listen for form submissions and update CSRF token from response
document.addEventListener('submit', function(e) {
// After form submit, the new CSRF token will be in the response
// We'll update it when the page reloads or via AJAX response
});
});
</script>
<?= $this->renderSection('scripts') ?>
</body>
</html>