recreate project
This commit is contained in:
@@ -0,0 +1,347 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<!--meta name="csrf-token" content="<--?= csrf_hash() ?>"-->
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Al Rahma Sunday School</title>
|
||||
<link rel="icon" href="<?= base_url('assets/images/favicon.ico') ?>">
|
||||
<!-- Google Fonts -->
|
||||
<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=Heebo:wght@400;500;600&family=Inter:wght@600&display=swap" rel="stylesheet">
|
||||
|
||||
<!-- Icon Fonts -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.0/css/all.min.css">
|
||||
|
||||
<!-- Bootstrap 5.3.3 CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
<!-- External Libraries CSS -->
|
||||
<link rel="stylesheet" href="<?= base_url('lib/animate/animate.min.css') ?>">
|
||||
<link rel="stylesheet" href="<?= base_url('lib/owlcarousel/assets/owl.carousel.min.css') ?>">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/main.min.css">
|
||||
|
||||
<!-- Custom CSS -->
|
||||
<link rel="stylesheet" href="<?= base_url('assets/css/style.css') ?>">
|
||||
<link rel="stylesheet" href="<?= base_url('assets/css/landing_page.css?v=1.1') ?>">
|
||||
<link rel="stylesheet" href="<?= base_url('assets/css/custom.css') ?>">
|
||||
|
||||
<?php
|
||||
// Accent + menu palettes (shared with management layout)
|
||||
$styleCfg = config('Style');
|
||||
$sess = session();
|
||||
// Default parent/teacher accents to green unless a style is explicitly chosen
|
||||
$role = strtolower((string)($sess->get('role') ?? ''));
|
||||
$roleDefaultStyle = in_array($role, ['parent', 'teacher', 'teacher_assistant'], true)
|
||||
? 'green'
|
||||
: ($styleCfg->defaultStyle ?? 'blue');
|
||||
$styleKey = $sess->get('style_color') ?? $roleDefaultStyle;
|
||||
// Default parent/teacher menu to a greenish palette (emerald)
|
||||
$roleDefaultMenu = in_array($role, ['parent', 'teacher', 'teacher_assistant'], true)
|
||||
? 'emerald'
|
||||
: ($styleCfg->defaultMenu ?? 'white');
|
||||
$menuKey = $sess->get('menu_color') ?? $roleDefaultMenu;
|
||||
$style = $styleCfg->stylePalettes[$styleKey] ?? ($styleCfg->stylePalettes[$styleCfg->defaultStyle] ?? [
|
||||
'primary' => '#4da3ff',
|
||||
]);
|
||||
if ($menuKey === 'custom') {
|
||||
$menu = [
|
||||
'bg' => (string)($sess->get('menu_custom_bg') ?? '#0f172a'),
|
||||
'text' => (string)($sess->get('menu_custom_text') ?? '#e2e8f0'),
|
||||
'mode' => (string)($sess->get('menu_custom_mode') ?? 'dark'),
|
||||
];
|
||||
} else {
|
||||
$menu = $styleCfg->menuPalettes[$menuKey] ?? ($styleCfg->menuPalettes[$styleCfg->defaultMenu] ?? [
|
||||
'bg' => '#ffffff',
|
||||
'text' => '#334155',
|
||||
'mode' => 'light',
|
||||
]);
|
||||
}
|
||||
$resolveMenuMode = function (string $mode, string $bg): string {
|
||||
$mode = strtolower(trim($mode));
|
||||
if ($mode === 'light' || $mode === 'dark') return $mode;
|
||||
$hex = ltrim(trim($bg), '#');
|
||||
if (strlen($hex) === 3) {
|
||||
$hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
|
||||
}
|
||||
if (strlen($hex) !== 6) return 'dark';
|
||||
$r = hexdec(substr($hex, 0, 2));
|
||||
$g = hexdec(substr($hex, 2, 2));
|
||||
$b = hexdec(substr($hex, 4, 2));
|
||||
$lum = (0.2126 * $r + 0.7152 * $g + 0.0722 * $b) / 255.0;
|
||||
return ($lum < 0.5) ? 'dark' : 'light';
|
||||
};
|
||||
$appMenuMode = $resolveMenuMode((string)($menu['mode'] ?? 'light'), (string)($menu['bg'] ?? '#0f172a'));
|
||||
?>
|
||||
<!-- Landing layout theme overrides: configurable accent + navbar menu colors -->
|
||||
<style>
|
||||
:root {
|
||||
/* App primary equals selected accent (also maps to template's --primary) */
|
||||
--app-primary: <?= esc($style['primary']) ?>;
|
||||
--primary: var(--app-primary);
|
||||
|
||||
/* Parity with management variables so UI bits look identical */
|
||||
--mgmt-primary: <?= esc($style['primary']) ?>;
|
||||
--mgmt-primary-hover: <?= esc($style['primary_hover'] ?? $style['primary']) ?>;
|
||||
--mgmt-menu-bg: <?= esc($menu['bg']) ?>;
|
||||
--mgmt-menu-text: <?= esc($menu['text']) ?>;
|
||||
}
|
||||
|
||||
/* Top landing navbar driven by menu palette */
|
||||
.custom-navbar {
|
||||
/* Override any gradients from external CSS */
|
||||
background: var(--mgmt-menu-bg) !important;
|
||||
color: var(--mgmt-menu-text) !important;
|
||||
border-bottom: 1px solid rgba(2, 6, 23, 0.06);
|
||||
}
|
||||
/* Ensure collapsed area (mobile) matches selected menu */
|
||||
.custom-navbar .navbar-collapse { background: var(--mgmt-menu-bg) !important; color: var(--mgmt-menu-text) !important; }
|
||||
.custom-navbar .navbar-collapse .nav-link { color: var(--mgmt-menu-text) !important; }
|
||||
.custom-navbar .navbar-brand,
|
||||
.custom-navbar .navbar-brand strong,
|
||||
.custom-navbar .nav-link { color: var(--mgmt-menu-text) !important; }
|
||||
.custom-navbar .nav-link:hover,
|
||||
.custom-navbar .dropdown-item:hover { color: var(--app-primary) !important; }
|
||||
.custom-navbar .dropdown-menu { z-index: 2050 !important; }
|
||||
|
||||
/* Improve toggler contrast on dark menus */
|
||||
body[data-app-menu-mode="dark"] .custom-navbar .navbar-toggler { border-color: var(--mgmt-menu-text); }
|
||||
body[data-app-menu-mode="dark"] .custom-navbar .navbar-toggler-icon { filter: invert(1) brightness(2); }
|
||||
</style>
|
||||
|
||||
<!-- Calendar JS (optional early load) -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@5.10.1/main.min.js"></script>
|
||||
<style>
|
||||
.comment-review {
|
||||
background-color: #f8f9fa;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
min-width: 180px;
|
||||
white-space: pre-wrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.table {
|
||||
width: 100%;
|
||||
margin-bottom: 1rem;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.table th {
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.table td {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.container-fluid {
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
/* Prevent horizontal scrollbars from stray overflows */
|
||||
html, body { overflow-x: hidden; }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body data-app-menu-mode="<?= esc($appMenuMode) ?>">
|
||||
<?php include(__DIR__ . '/../partials/navbar.php'); ?>
|
||||
|
||||
<?php
|
||||
$uri = service('uri');
|
||||
$path = trim($uri->getPath(), '/');
|
||||
$widePaths = [
|
||||
'teacher/class_view',
|
||||
'teacher/scores',
|
||||
'teacher/addHomework',
|
||||
'teacher/addQuiz',
|
||||
'teacher/addProject',
|
||||
'student/score-card',
|
||||
'student/score-card/list',
|
||||
];
|
||||
$mainContainerClass = in_array($path, $widePaths) ? 'container-fluid' : 'container';
|
||||
|
||||
// Teacher class switcher (page-level, outside navbar)
|
||||
$role = strtolower((string)(session()->get('role') ?? 'guest'));
|
||||
$isTeacher = in_array($role, ['teacher', 'teacher_assistant'], true);
|
||||
$classOptions = [];
|
||||
$activeClassId = (int)(session()->get('class_section_id') ?? 0);
|
||||
if ($isTeacher) {
|
||||
$cfg = new \App\Models\ConfigurationModel();
|
||||
$tcModel = new \App\Models\TeacherClassModel();
|
||||
$sy = (string)($cfg->getConfig('school_year') ?? '');
|
||||
$sem = (string)($cfg->getConfig('semester') ?? '');
|
||||
$uid = (int)(session()->get('user_id') ?? 0);
|
||||
if ($uid) {
|
||||
$classOptions = $tcModel->getClassAssignmentsByUserId($uid, $sy, $sem);
|
||||
}
|
||||
}
|
||||
$qsBody = $_SERVER['QUERY_STRING'] ?? '';
|
||||
$redirectBody = current_url() . ($qsBody ? '?' . $qsBody : '');
|
||||
$switchFormId = 'pageClassSwitchForm';
|
||||
$switchInputId = 'pageClassSwitchValue';
|
||||
?>
|
||||
|
||||
<main class="<?= $mainContainerClass ?> mt-4">
|
||||
<?php if (!empty($classOptions) && count($classOptions) > 1): ?>
|
||||
<div class="mb-3">
|
||||
<form id="<?= $switchFormId ?>" class="d-flex align-items-center gap-2 flex-wrap" method="post" action="<?= base_url('/teacher/switch-class'); ?>">
|
||||
<?= csrf_field(); ?>
|
||||
<input type="hidden" name="redirect_to" value="<?= esc($redirectBody) ?>">
|
||||
<input type="hidden" name="class_section_id" id="<?= $switchInputId ?>" value="<?= $activeClassId ?>">
|
||||
<label class="fw-semibold mb-0">Switch class:</label>
|
||||
<div class="d-flex align-items-center flex-wrap gap-2">
|
||||
<?php foreach ($classOptions as $opt): ?>
|
||||
<?php $cid = (int)($opt['class_section_id'] ?? 0); ?>
|
||||
<?php $isActive = $cid === $activeClassId; ?>
|
||||
<button type="button"
|
||||
class="btn btn-sm <?= $isActive ? 'btn-success text-white' : 'btn-outline-success' ?>"
|
||||
data-cid="<?= $cid ?>" data-target="<?= $switchInputId ?>">
|
||||
<?= esc($opt['class_section_name'] ?? 'Class'); ?>
|
||||
</button>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</form>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
const form = document.getElementById('<?= $switchFormId ?>');
|
||||
const hiddenInput = document.getElementById('<?= $switchInputId ?>');
|
||||
if (!form || !hiddenInput) return;
|
||||
form.querySelectorAll('[data-cid][data-target]').forEach(btn => {
|
||||
btn.addEventListener('click', function(e){
|
||||
e.preventDefault();
|
||||
hiddenInput.value = this.getAttribute('data-cid') || '';
|
||||
form.submit();
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?= $this->renderSection('content') ?>
|
||||
</main>
|
||||
|
||||
<?php include(__DIR__ . '/../partials/footer.php'); ?>
|
||||
|
||||
<!-- Family Card Modal -->
|
||||
<div class="modal fade" id="familyCardModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-xl modal-dialog-scrollable">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Family</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-0">
|
||||
<div id="familyCardContent"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||
tooltipTriggerList.forEach(function(tooltipTriggerEl) {
|
||||
new bootstrap.Tooltip(tooltipTriggerEl);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Bootstrap Bundle (with Popper) -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- Additional JS Libraries -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
|
||||
<script src="<?= base_url('lib/wow/wow.min.js') ?>"></script>
|
||||
<script src="<?= base_url('lib/easing/easing.min.js') ?>"></script>
|
||||
<script src="<?= base_url('lib/waypoints/waypoints.min.js') ?>"></script>
|
||||
<script src="<?= base_url('lib/owlcarousel/owl.carousel.min.js') ?>"></script>
|
||||
|
||||
<!-- Template JS -->
|
||||
<script src="<?= base_url('js/main.js') ?>"></script>
|
||||
|
||||
<!-- Family Card loader (shared for teacher/parent views) -->
|
||||
<script>
|
||||
(function(){
|
||||
const modalEl = document.getElementById('familyCardModal');
|
||||
let modal;
|
||||
function ensureModal(){
|
||||
if (!modalEl) return null;
|
||||
if (!modal) modal = new bootstrap.Modal(modalEl);
|
||||
return modal;
|
||||
}
|
||||
async function loadFamilyCard(params){
|
||||
try {
|
||||
const usp = new URLSearchParams(params);
|
||||
const url = '<?= site_url('family/card') ?>' + '?' + usp.toString();
|
||||
const resp = await fetch(url, { headers: { 'Accept': 'text/html' } });
|
||||
if (!resp.ok) throw new Error('Failed to load family card');
|
||||
const html = await resp.text();
|
||||
const target = document.getElementById('familyCardContent');
|
||||
if (target) target.innerHTML = html;
|
||||
try {
|
||||
const root = target ? target.querySelector('[data-family-title]') : null;
|
||||
const title = root ? root.getAttribute('data-family-title') : '';
|
||||
const headerTitle = document.querySelector('#familyCardModal .modal-title');
|
||||
if (headerTitle) headerTitle.textContent = title || 'Family';
|
||||
} catch (_) {}
|
||||
|
||||
const m = ensureModal();
|
||||
if (m) m.show();
|
||||
} catch (e) {
|
||||
try {
|
||||
const gid = params && params.guardian_id;
|
||||
const sid = params && params.student_id;
|
||||
if (gid) window.location.href = '<?= site_url('family') ?>' + '?guardian_id=' + encodeURIComponent(gid);
|
||||
else if (sid) window.location.href = '<?= site_url('family') ?>' + '?student_id=' + encodeURIComponent(sid);
|
||||
} catch(_) {}
|
||||
}
|
||||
}
|
||||
window.openFamilyCard = loadFamilyCard;
|
||||
|
||||
document.addEventListener('click', function(e){
|
||||
const link = e.target.closest('[data-family-student-id], [data-family-guardian-id], [data-family-id]');
|
||||
if (!link) return;
|
||||
e.preventDefault();
|
||||
const sid = link.getAttribute('data-family-student-id');
|
||||
const gid = link.getAttribute('data-family-guardian-id');
|
||||
const fid = link.getAttribute('data-family-id');
|
||||
const params = {};
|
||||
if (fid) params.family_id = fid;
|
||||
else if (sid) params.student_id = sid;
|
||||
else if (gid) params.guardian_id = gid;
|
||||
if (Object.keys(params).length) loadFamilyCard(params);
|
||||
});
|
||||
|
||||
document.addEventListener('click', function(e){
|
||||
const link = e.target.closest('[data-family-student-id], [data-family-guardian-id], [data-family-id]');
|
||||
if (!link) return;
|
||||
e.preventDefault();
|
||||
const sid = link.getAttribute('data-family-student-id');
|
||||
const gid = link.getAttribute('data-family-guardian-id');
|
||||
const fid = link.getAttribute('data-family-id');
|
||||
const params = {};
|
||||
if (fid) params.family_id = fid;
|
||||
else if (sid) params.student_id = sid;
|
||||
else if (gid) params.guardian_id = gid;
|
||||
if (Object.keys(params).length) loadFamilyCard(params);
|
||||
}, true);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<?= $this->renderSection('scripts') ?>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user