702 lines
34 KiB
PHP
702 lines
34 KiB
PHP
<?php
|
||
// Get and normalize the role
|
||
$rawRole = session()->get('role');
|
||
if (is_array($rawRole)) {
|
||
$rawRole = $rawRole[0] ?? 'guest';
|
||
}
|
||
$role = strtolower((string)($rawRole ?? 'guest'));
|
||
|
||
// Set dashboard path based on role
|
||
switch ($role) {
|
||
case 'parent':
|
||
$dashboard = base_url('/parent_dashboard');
|
||
break;
|
||
case 'teacher':
|
||
$dashboard = base_url('/teacher_dashboard');
|
||
break;
|
||
case 'teacher_assistant':
|
||
$dashboard = base_url('/teacher_dashboard');
|
||
break;
|
||
case 'student':
|
||
$dashboard = base_url('/landing_page/student_dashboard');
|
||
break;
|
||
case 'guest':
|
||
$dashboard = base_url('/landing_page/guest_dashboard');
|
||
break;
|
||
default:
|
||
$dashboard = base_url('/login');
|
||
break;
|
||
}
|
||
?>
|
||
<?php
|
||
// Build user display (avatar initials + info)
|
||
$userName = trim((string) (session()->get('user_name') ?? ''));
|
||
$userEmail = trim((string) (session()->get('user_email') ?? ''));
|
||
$initials = 'U';
|
||
if ($userName !== '') {
|
||
$parts = preg_split('/\s+/', $userName);
|
||
$first = $parts[0] ?? '';
|
||
$last = count($parts) > 1 ? end($parts) : '';
|
||
$initials = strtoupper(substr($first, 0, 1) . ($last !== '' ? substr($last, 0, 1) : ''));
|
||
} elseif ($userEmail !== '') {
|
||
$initials = strtoupper(substr($userEmail, 0, 1));
|
||
}
|
||
|
||
// Score card picker (parent/teacher only)
|
||
$scoreCardStudents = [];
|
||
$scoreCardEnabledRole = in_array($role, ['parent', 'parent_dashboard', 'teacher', 'teacher_assistant', 'teacher_dashboard'], true);
|
||
if ($scoreCardEnabledRole) {
|
||
try {
|
||
$studentModel = new \App\Models\StudentModel();
|
||
if (in_array($role, ['parent', 'parent_dashboard'], true)) {
|
||
$parentId = (int)(session()->get('user_id') ?? 0);
|
||
if ($parentId > 0) {
|
||
$scoreCardStudents = $studentModel
|
||
->select('id, school_id, firstname, lastname')
|
||
->where('parent_id', $parentId)
|
||
->orderBy('lastname', 'ASC')
|
||
->orderBy('firstname', 'ASC')
|
||
->findAll();
|
||
}
|
||
} else {
|
||
$configModel = new \App\Models\ConfigurationModel();
|
||
$schoolYear = session()->get('school_year') ?? $configModel->getConfig('school_year');
|
||
$classSectionId = (int)($class_section_id ?? session()->get('class_section_id') ?? 0);
|
||
if ($classSectionId > 0 && !empty($schoolYear)) {
|
||
$scoreCardStudents = $studentModel->getByClassAndYear($classSectionId, $schoolYear);
|
||
}
|
||
if (empty($scoreCardStudents)) {
|
||
$userId = (int)(session()->get('user_id') ?? 0);
|
||
if ($userId > 0 && !empty($schoolYear)) {
|
||
$db = \Config\Database::connect();
|
||
$sectionRows = $db->table('teacher_class')
|
||
->select('class_section_id')
|
||
->where('teacher_id', $userId)
|
||
->where('school_year', (string)$schoolYear)
|
||
->get()
|
||
->getResultArray();
|
||
$sectionIds = array_values(array_filter(array_unique(array_map(
|
||
static fn($r) => (int)($r['class_section_id'] ?? 0),
|
||
$sectionRows
|
||
)), static fn($v) => $v > 0));
|
||
if (!empty($sectionIds)) {
|
||
$studentClassModel = new \App\Models\StudentClassModel();
|
||
$rows = $studentClassModel->getStudentsByClassSectionIds($sectionIds);
|
||
$unique = [];
|
||
foreach ($rows as $r) {
|
||
$sid = (int)($r['student_id'] ?? 0);
|
||
if ($sid > 0) {
|
||
$unique[$sid] = [
|
||
'id' => $sid,
|
||
'school_id' => $r['school_id'] ?? '',
|
||
'firstname' => $r['firstname'] ?? '',
|
||
'lastname' => $r['lastname'] ?? '',
|
||
];
|
||
}
|
||
}
|
||
$scoreCardStudents = array_values($unique);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} catch (\Throwable $e) {
|
||
$scoreCardStudents = [];
|
||
}
|
||
}
|
||
?>
|
||
<style>
|
||
@media (max-width: 576px) {
|
||
.mobile-adjust {
|
||
margin-right: 5px !important;
|
||
transform: translateX(-10px);
|
||
}
|
||
}
|
||
|
||
/* Collapse fills remaining space */
|
||
.navbar-collapse-center { flex: 1 1 auto; }
|
||
|
||
/* At lg+, center only the main nav items while avatar stays right */
|
||
@media (min-width: 992px) {
|
||
.navbar-collapse-center { display: flex; align-items: center; flex-wrap: wrap; }
|
||
.navbar-collapse-center .nav-center { margin-left: auto; margin-right: auto; }
|
||
}
|
||
|
||
.role-nav-grid {
|
||
display: flex;
|
||
flex-wrap: nowrap;
|
||
gap: 0.15rem;
|
||
justify-content: flex-start;
|
||
align-items: stretch;
|
||
width: 100%;
|
||
margin-top: 0.15rem;
|
||
padding-bottom: 0.15rem;
|
||
overflow-x: auto;
|
||
-ms-overflow-style: none;
|
||
scrollbar-width: none;
|
||
}
|
||
|
||
.role-nav-grid::-webkit-scrollbar {
|
||
display: none;
|
||
}
|
||
|
||
.role-nav-link {
|
||
position: relative;
|
||
flex: 0 0 auto;
|
||
max-width: 8rem;
|
||
min-width: 6rem;
|
||
padding: 0.2rem 0.4rem;
|
||
border-radius: 0.6rem;
|
||
border: 1px solid rgba(255, 255, 255, 0.35);
|
||
background: transparent;
|
||
color: inherit;
|
||
text-decoration: none;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
text-align: center;
|
||
line-height: 1;
|
||
transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.navbar.navbar-dark .role-nav-link {
|
||
border-color: rgba(255, 255, 255, 0.6);
|
||
box-shadow: 0 5px 12px rgba(0, 0, 0, 0.25);
|
||
}
|
||
|
||
.navbar.navbar-light .role-nav-link {
|
||
border-color: rgba(15, 23, 42, 0.35);
|
||
color: #0d2c54;
|
||
box-shadow: 0 4px 8px rgba(15, 23, 42, 0.12);
|
||
}
|
||
|
||
.role-nav-link:hover,
|
||
.role-nav-link:focus {
|
||
transform: translateY(-2px);
|
||
border-color: rgba(255, 255, 255, 0.6);
|
||
box-shadow: 0 12px 36px rgba(0, 0, 0, 0.15);
|
||
text-decoration: none;
|
||
}
|
||
|
||
.role-nav-icon {
|
||
font-size: 1.1rem;
|
||
margin-bottom: 0.1rem;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.role-nav-label {
|
||
font-size: 0.75rem;
|
||
font-weight: 500;
|
||
line-height: 1;
|
||
}
|
||
|
||
.role-nav-badge {
|
||
position: absolute;
|
||
top: 0.45rem;
|
||
right: 0.45rem;
|
||
font-size: 0.65rem;
|
||
font-weight: 600;
|
||
padding: 0.25rem 0.45rem;
|
||
border-radius: 999px;
|
||
background: #d92b2b;
|
||
color: #fff;
|
||
}
|
||
|
||
@media (max-width: 992px) {
|
||
.role-nav-link {
|
||
min-width: 6rem;
|
||
max-width: 7.5rem;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.role-nav-grid {
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
gap: 0.2rem;
|
||
overflow-x: visible;
|
||
}
|
||
|
||
.role-nav-link {
|
||
flex: 1 1 calc(50% - 0.3rem);
|
||
max-width: calc(50% - 0.3rem);
|
||
min-width: 0;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 576px) {
|
||
.role-nav-link {
|
||
min-width: 6.2rem;
|
||
}
|
||
}
|
||
</style>
|
||
|
||
<?php
|
||
// Read menu mode to set appropriate navbar-* class for contrast parity with admin
|
||
$styleCfg = config('Style');
|
||
$sess = session();
|
||
$menuKeyLP = $sess->get('menu_color') ?? ($styleCfg->defaultMenu ?? 'white');
|
||
if ($menuKeyLP === 'custom') {
|
||
$menuMode = (string)($sess->get('menu_custom_mode') ?? 'auto');
|
||
$menuBg = (string)($sess->get('menu_custom_bg') ?? '#0f172a');
|
||
$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';
|
||
};
|
||
$menuModeEffective = $resolveMenuMode($menuMode, $menuBg);
|
||
$navModeCls = ($menuModeEffective === 'dark') ? 'navbar-dark' : 'navbar-light';
|
||
} else {
|
||
$menuLP = $styleCfg->menuPalettes[$menuKeyLP] ?? ($styleCfg->menuPalettes[$styleCfg->defaultMenu] ?? ['mode' => 'light']);
|
||
$navModeCls = (isset($menuLP['mode']) && $menuLP['mode'] === 'dark') ? 'navbar-dark' : 'navbar-light';
|
||
}
|
||
|
||
// Provide active event count for parent role if not already injected by the controller
|
||
if (!isset($activeEventCount) && ($role ?? '') === 'parent') {
|
||
$configModel = new \App\Models\ConfigurationModel();
|
||
$eventModel = new \App\Models\EventModel();
|
||
$year = $sess->get('school_year') ?? $configModel->getConfig('school_year');
|
||
$semester = $sess->get('semester') ?? $configModel->getConfig('semester');
|
||
$activeEventCount = count($eventModel->getActiveEvents($year, $semester) ?? []);
|
||
}
|
||
?>
|
||
<nav class="navbar navbar-expand-lg <?= esc($navModeCls) ?> sticky-top shadow custom-navbar">
|
||
<a href="<?= $dashboard ?>" class="navbar-brand d-flex align-items-center ms-3">
|
||
<img src="<?= base_url('assets/images/logo.png') ?>" alt="School Logo" class="navbar-logo">
|
||
</a>
|
||
|
||
<button class="navbar-toggler order-0 me-2 mobile-adjust" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse"
|
||
aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
|
||
<span class="navbar-toggler-icon"></span>
|
||
</button>
|
||
|
||
<!-- collapse takes remaining width; ms-lg-3 adds a small gap from logo at lg+ -->
|
||
<div class="collapse navbar-collapse navbar-collapse-center ms-lg-auto" id="navbarCollapse">
|
||
<div class="navbar-nav d-flex nav-center">
|
||
<?php if ($role !== 'parent' && $role !== 'teacher' && $role !== 'teacher_assistant'): ?>
|
||
<a href="<?= $dashboard ?>" data-bs-toggle="tooltip" data-bs-placement="bottom" title="View a summary of key school statistics, recent activities and important updates." class="nav-item nav-link fs-5 bi bi-house-door"> Dashboard</a>
|
||
<?php endif; ?>
|
||
|
||
<?php if ($role === 'parent'): ?>
|
||
<?php
|
||
$parentLinks = [
|
||
[
|
||
'href' => $dashboard,
|
||
'icon' => 'bi-house-door',
|
||
'label' => 'Dashboard',
|
||
'title' => 'View a summary of key school statistics, recent activities and important updates.',
|
||
],
|
||
[
|
||
'href' => base_url('/parent/child_register'),
|
||
'icon' => 'bi-person-plus',
|
||
'label' => 'Register Students',
|
||
'title' => 'Add your child(ren) to the school’s database and update their basic info.',
|
||
],
|
||
[
|
||
'href' => base_url('/parent/enroll_classes'),
|
||
'icon' => 'bi-pencil-square',
|
||
'label' => 'Enroll in Classes',
|
||
'title' => 'Enroll registered students in their appropriate grade level or course.',
|
||
],
|
||
[
|
||
'href' => base_url('/parent/invoice_payment'),
|
||
'icon' => 'bi-credit-card',
|
||
'label' => 'Invoice',
|
||
'title' => 'View and pay your child(ren)\'s invoice securely (tuition & events).',
|
||
],
|
||
[
|
||
'href' => base_url('/parent/attendance'),
|
||
'icon' => 'bi-calendar-check',
|
||
'label' => 'Attendance',
|
||
'title' => 'Track attendance record of your child(ren) (absences & late arrivals).',
|
||
],
|
||
[
|
||
'href' => base_url('parent/report-attendance'),
|
||
'icon' => 'bi-megaphone',
|
||
'label' => 'Report Absence',
|
||
'title' => 'Let the school know about an absence, late arrival, or early dismissal.',
|
||
],
|
||
[
|
||
'href' => base_url('/parent/scores'),
|
||
'icon' => 'bi-clipboard-data',
|
||
'label' => 'Scores',
|
||
'title' => 'Review progressive academic score for the year (homeworks, projects and exams).',
|
||
],
|
||
[
|
||
'href' => base_url('/parent/report-cards'),
|
||
'icon' => 'bi-file-earmark-text',
|
||
'label' => 'Report Cards',
|
||
'title' => 'View and acknowledge student report cards.',
|
||
],
|
||
[
|
||
'href' => base_url('/parent/progress'),
|
||
'icon' => 'bi-journal-check',
|
||
'label' => 'Class Progress',
|
||
'title' => 'View weekly class progress shared by teachers.',
|
||
],
|
||
[
|
||
'href' => base_url('/parent/events'),
|
||
'icon' => 'bi-bell',
|
||
'label' => 'Events',
|
||
'title' => 'Manage participation in planned school activities such as field trips or competitions.',
|
||
'badge' => !empty($activeEventCount) ? $activeEventCount : null,
|
||
],
|
||
[
|
||
'href' => base_url('/parent/calendar'),
|
||
'icon' => 'bi-calendar-day',
|
||
'label' => 'Calendar',
|
||
'title' => 'View school-wide calendar of classes, events and holidays.',
|
||
],
|
||
];/*
|
||
if ($scoreCardEnabledRole) {
|
||
$parentLinks[] = [
|
||
'href' => base_url('student/score-card/list'),
|
||
'icon' => 'bi-card-list',
|
||
'label' => 'Score Card',
|
||
'title' => 'Open a student score card.',
|
||
];
|
||
}*/
|
||
usort($parentLinks, static function ($a, $b) {
|
||
$la = strtolower((string)($a['label'] ?? ''));
|
||
$lb = strtolower((string)($b['label'] ?? ''));
|
||
if ($la === 'dashboard' && $lb !== 'dashboard') return -1;
|
||
if ($lb === 'dashboard' && $la !== 'dashboard') return 1;
|
||
return strcasecmp($la, $lb);
|
||
});
|
||
?>
|
||
<div class="role-nav-grid">
|
||
<?php foreach ($parentLinks as $link): ?>
|
||
<?php $badge = $link['badge'] ?? null; ?>
|
||
<a href="<?= esc($link['href']) ?>"
|
||
class="nav-item nav-link role-nav-link"
|
||
data-bs-toggle="tooltip"
|
||
data-bs-placement="bottom"
|
||
title="<?= esc($link['title']) ?>"
|
||
<?= $link['attrs'] ?? '' ?>>
|
||
<span class="role-nav-icon">
|
||
<i class="bi <?= esc($link['icon']) ?>"></i>
|
||
</span>
|
||
<span class="role-nav-label"><?= esc($link['label']) ?></span>
|
||
<?php if (!empty($badge)): ?>
|
||
<span class="role-nav-badge"><?= esc($badge) ?></span>
|
||
<?php endif; ?>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
|
||
<?php elseif (($role === 'teacher') || ($role === 'teacher_assistant')): ?>
|
||
<?php
|
||
$teacherLinks = [
|
||
[
|
||
'href' => $dashboard,
|
||
'icon' => 'bi-house-door',
|
||
'label' => 'Dashboard',
|
||
'title' => 'View notices, summary stats and recent updates.',
|
||
],
|
||
[
|
||
'href' => base_url('/teacher/class_view'),
|
||
'icon' => 'bi-pencil-square',
|
||
'label' => 'Class',
|
||
'title' => 'Manage your assigned class list.',
|
||
],
|
||
[
|
||
'href' => base_url('/teacher/showupdate_attendance?class_section_id=' . ($class_section_id ?? '')),
|
||
'icon' => 'bi-calendar-check',
|
||
'label' => 'Attendance',
|
||
'title' => 'Update student attendance records.',
|
||
],
|
||
[
|
||
'href' => base_url('/teacher/absence'),
|
||
'icon' => 'bi-megaphone',
|
||
'label' => 'TimeOff',
|
||
'title' => 'Report your absence or vacation days.',
|
||
],
|
||
[
|
||
'href' => base_url('teacher/print-requests'),
|
||
'icon' => 'bi-printer',
|
||
'label' => 'Print',
|
||
'title' => 'Submit and track print/copy requests.',
|
||
],
|
||
[
|
||
'href' => base_url('teacher/progress/submit'),
|
||
'icon' => 'bi-clipboard-check',
|
||
'label' => 'Class Progress',
|
||
'title' => 'Submit weekly class progress.',
|
||
],
|
||
[
|
||
'href' => base_url('/teacher/scores'),
|
||
'icon' => 'bi-clipboard-data',
|
||
'label' => 'Scores',
|
||
'title' => 'Input, view and update student scores.',
|
||
],
|
||
[
|
||
'href' => base_url('/teacher/competition-scores'),
|
||
'icon' => 'bi-trophy',
|
||
'label' => 'Competitions',
|
||
'title' => 'Enter competition scores for your class.',
|
||
],
|
||
[
|
||
'href' => base_url('/teacher/exam-drafts'),
|
||
'icon' => 'bi-file-earmark-text',
|
||
'label' => 'Exam Drafts',
|
||
'title' => 'Submit or review draft exams that need administrator approval.',
|
||
],
|
||
[
|
||
'href' => base_url('inventory/books/distribute'),
|
||
'icon' => 'bi-book',
|
||
'label' => 'Books',
|
||
'title' => 'Review and distribute books.',
|
||
],
|
||
[
|
||
'href' => base_url('/teacher/calendar'),
|
||
'icon' => 'bi-calendar-day',
|
||
'label' => 'Calendar',
|
||
'title' => 'View school-wide calendar of classes, events, and holidays.',
|
||
],
|
||
];
|
||
if ($scoreCardEnabledRole) {
|
||
$teacherLinks[] = [
|
||
'href' => base_url('student/score-card/list'),
|
||
'icon' => 'bi-card-list',
|
||
'label' => 'Score Card',
|
||
'title' => 'Open a student score card.',
|
||
];
|
||
}
|
||
usort($teacherLinks, static function ($a, $b) {
|
||
$la = strtolower((string)($a['label'] ?? ''));
|
||
$lb = strtolower((string)($b['label'] ?? ''));
|
||
if ($la === 'dashboard' && $lb !== 'dashboard') return -1;
|
||
if ($lb === 'dashboard' && $la !== 'dashboard') return 1;
|
||
return strcasecmp($la, $lb);
|
||
});
|
||
?>
|
||
<div class="role-nav-grid">
|
||
<?php foreach ($teacherLinks as $link): ?>
|
||
<a href="<?= esc($link['href']) ?>"
|
||
class="nav-item nav-link role-nav-link"
|
||
data-bs-toggle="tooltip"
|
||
data-bs-placement="bottom"
|
||
title="<?= esc($link['title']) ?>"
|
||
<?= $link['attrs'] ?? '' ?>>
|
||
<span class="role-nav-icon">
|
||
<i class="bi <?= esc($link['icon']) ?>"></i>
|
||
</span>
|
||
<span class="role-nav-label"><?= esc($link['label']) ?></span>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php elseif ($role === 'student' || $role === 'guest'): ?>
|
||
<span class="nav-link text-warning">Please contact administration to assign a role to your account.</span>
|
||
<?php endif; ?>
|
||
</div>
|
||
|
||
<?php
|
||
// Role switcher + style combined under one "Quick Menu"
|
||
$allRoles = array_map(fn($r)=> strtolower(trim((string)$r)), (array) (session()->get('roles') ?? []));
|
||
$current = strtolower((string) (session()->get('role') ?? 'guest'));
|
||
$other = array_values(array_filter($allRoles, fn($r) => $r !== '' && $r !== $current));
|
||
|
||
$styleCfg = config('Style');
|
||
$sess = session();
|
||
$currentAccent = $sess->get('style_color') ?? ($styleCfg->defaultStyle ?? 'blue');
|
||
$currentMenu = $sess->get('menu_color') ?? ($styleCfg->defaultMenu ?? 'white');
|
||
?>
|
||
<div class="nav-item dropdown ms-lg-3">
|
||
|
||
<div class="dropdown-menu dropdown-menu-end quick-menu" aria-labelledby="quickMenu" style="max-height: 70vh; overflow-y: auto; overflow-x: hidden;">
|
||
<?php if (!empty($other)): ?>
|
||
<h6 class="dropdown-header">Switch Role</h6>
|
||
<?php foreach ($other as $r): ?>
|
||
<form method="post" action="<?= base_url('set-role') ?>" class="px-2">
|
||
<?= csrf_field() ?>
|
||
<input type="hidden" name="selected_role" value="<?= esc($r) ?>">
|
||
<button type="submit" class="dropdown-item">Switch to <?= esc(ucfirst(str_replace('_', ' ', $r))) ?></button>
|
||
</form>
|
||
<?php endforeach; ?>
|
||
<div class="dropdown-divider"></div>
|
||
<?php endif; ?>
|
||
|
||
<h6 class="dropdown-header">Style</h6>
|
||
<a class="dropdown-item d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#ddAccentQuick" role="button" aria-expanded="true" aria-controls="ddAccentQuick">
|
||
Accent <i class="bi bi-chevron-down ms-2"></i>
|
||
</a>
|
||
<div class="collapse show" id="ddAccentQuick">
|
||
<div class="px-2 pb-2">
|
||
<?php foreach (array_keys($styleCfg->stylePalettes ?? []) as $opt): ?>
|
||
<?php $isActive = ($opt === $currentAccent); ?>
|
||
<a class="dropdown-item <?= $isActive ? 'active' : '' ?>" href="<?= site_url('ui/style?accent=' . urlencode($opt) . '&back=' . urlencode(current_url())) ?>" <?= $isActive ? 'aria-current="true"' : '' ?>>
|
||
<?= ucfirst(esc($opt)) ?><?= $isActive ? ' <i class=\"bi bi-check-lg ms-2\"></i>' : '' ?>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
<div class="dropdown-divider"></div>
|
||
<div class="px-2 small text-muted">Menu</div>
|
||
<?php foreach (array_keys($styleCfg->menuPalettes ?? []) as $opt): ?>
|
||
<?php $isActive = ($opt === $currentMenu); ?>
|
||
<a class="dropdown-item <?= $isActive ? 'active' : '' ?>" href="<?= site_url('ui/style?menu=' . urlencode($opt) . '&back=' . urlencode(current_url())) ?>" <?= $isActive ? 'aria-current="true"' : '' ?>>
|
||
<?= ucfirst(esc($opt)) ?><?= $isActive ? ' <i class=\"bi bi-check-lg ms-2\"></i>' : '' ?>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Avatar dropdown outside collapse to avoid clipping and keep right spacing -->
|
||
<?php
|
||
// Role switcher + style selections (ensure vars exist out here)
|
||
if (!isset($other) || !isset($styleCfg) || !isset($currentAccent) || !isset($currentMenu)) {
|
||
$allRoles = array_map(fn($r)=> strtolower(trim((string)$r)), (array) (session()->get('roles') ?? []));
|
||
$current = strtolower((string) (session()->get('role') ?? 'guest'));
|
||
$other = array_values(array_filter($allRoles, fn($r) => $r !== '' && $r !== $current));
|
||
$styleCfg = config('Style');
|
||
$sess = session();
|
||
$currentAccent = $sess->get('style_color') ?? ($styleCfg->defaultStyle ?? 'blue');
|
||
$currentMenu = $sess->get('menu_color') ?? ($styleCfg->defaultMenu ?? 'white');
|
||
}
|
||
?>
|
||
<ul class="navbar-nav ms-auto me-4">
|
||
<li class="nav-item dropdown">
|
||
<a class="nav-link p-0" href="#" id="quickMenu" role="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false" aria-label="Open user menu">
|
||
<div class="rounded-circle text-white fw-semibold d-flex align-items-center justify-content-center" style="width: 40px; height: 40px; background-color: var(--app-primary);">
|
||
<?= esc($initials) ?>
|
||
</div>
|
||
</a>
|
||
<div class="dropdown-menu dropdown-menu-end quick-menu" aria-labelledby="quickMenu" style="max-height: 70vh; overflow-y: auto; overflow-x: hidden; min-width: 260px; max-width: min(320px, calc(100vw - 16px)); right: 8px; left: auto;">
|
||
<div class="px-3 py-3 d-flex align-items-center">
|
||
<div class="rounded-circle text-white fw-semibold d-flex align-items-center justify-content-center me-3" style="width: 36px; height: 36px; background-color: var(--app-primary);">
|
||
<?= esc($initials) ?>
|
||
</div>
|
||
<div>
|
||
<div class="fw-semibold mb-0" style="line-height: 1.2;"><?= esc($userName !== '' ? $userName : 'User') ?></div>
|
||
<div class="text-muted small" style="line-height: 1.2;"><?= esc($role) ?><?= $userEmail ? ' · ' . esc($userEmail) : '' ?></div>
|
||
</div>
|
||
</div>
|
||
<div class="dropdown-divider"></div>
|
||
<?php if (!empty($other)): ?>
|
||
<a class="dropdown-item d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#ddRoleBodyLP" role="button" aria-expanded="false" aria-controls="ddRoleBodyLP">
|
||
Switch Role <i class="bi bi-chevron-down ms-2"></i>
|
||
</a>
|
||
<div class="collapse" id="ddRoleBodyLP">
|
||
<div class="px-2 pb-2">
|
||
<?php foreach ($other as $r): ?>
|
||
<form method="post" action="<?= base_url('set-role') ?>" class="mb-1">
|
||
<?= csrf_field() ?>
|
||
<input type="hidden" name="selected_role" value="<?= esc($r) ?>">
|
||
<button type="submit" class="dropdown-item">Switch to <?= esc(ucfirst(str_replace('_', ' ', $r))) ?></button>
|
||
</form>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
<div class="dropdown-divider"></div>
|
||
<?php endif; ?>
|
||
|
||
<a class="dropdown-item d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#ddStyleBodyLP" role="button" aria-expanded="false" aria-controls="ddStyleBodyLP">
|
||
Style <i class="bi bi-chevron-down ms-2"></i>
|
||
</a>
|
||
<div class="collapse" id="ddStyleBodyLP">
|
||
<div class="px-2 pb-2">
|
||
<a class="dropdown-item d-flex justify-content-between align-items-center" data-bs-toggle="collapse" href="#ddAccentAvatar" role="button" aria-expanded="true" aria-controls="ddAccentAvatar">
|
||
Accent <i class="bi bi-chevron-down ms-2"></i>
|
||
</a>
|
||
<div class="collapse show" id="ddAccentAvatar">
|
||
<div class="px-2 pb-2">
|
||
<?php foreach (array_keys($styleCfg->stylePalettes ?? []) as $opt): ?>
|
||
<?php $isActive = ($opt === $currentAccent); ?>
|
||
<a class="dropdown-item <?= $isActive ? 'active' : '' ?>" href="<?= site_url('ui/style?accent=' . urlencode($opt) . '&back=' . urlencode(current_url())) ?>" <?= $isActive ? 'aria-current=\"true\"' : '' ?>>
|
||
<?= ucfirst(esc($opt)) ?><?= $isActive ? ' <i class=\"bi bi-check-lg ms-2\"></i>' : '' ?>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
<div class="dropdown-divider"></div>
|
||
<div class="px-2 small text-muted">Menu</div>
|
||
<div class="px-2 pb-2">
|
||
<div class="table-responsive">
|
||
<table class="table table-borderless mb-2" style="min-width:auto;">
|
||
<tbody>
|
||
<?php
|
||
$palettes = $styleCfg->menuPalettes ?? [];
|
||
$keys = array_keys($palettes);
|
||
$cols = 3; $i = 0;
|
||
foreach ($keys as $k):
|
||
if ($i % $cols === 0) echo '<tr>';
|
||
$pal = $palettes[$k];
|
||
$bg = (string)($pal['bg'] ?? '#fff');
|
||
$tx = (string)($pal['text'] ?? '#000');
|
||
$active = ($k === $currentMenu) ? 'outline-success' : 'outline-secondary';
|
||
?>
|
||
<td class="p-1" style="width:33.33%;">
|
||
<a href="<?= site_url('ui/style?menu=' . urlencode($k) . '&back=' . urlencode(current_url())) ?>" class="btn btn-<?= $active ?> w-100" style="padding:6px;">
|
||
<div class="rounded" style="height:28px; background-color: <?= esc($bg) ?>; color: <?= esc($tx) ?>; display:flex; align-items:center; justify-content:center; font-size:.8rem;">
|
||
<?= ucfirst(esc($k)) ?>
|
||
</div>
|
||
</a>
|
||
</td>
|
||
<?php
|
||
$i++;
|
||
if ($i % $cols === 0) echo '</tr>';
|
||
endforeach;
|
||
if ($i % $cols !== 0) { while ($i % $cols !== 0) { echo '<td class="p-1"></td>'; $i++; } echo '</tr>'; }
|
||
?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<!-- Custom color picker -->
|
||
<form action="<?= site_url('ui/style') ?>" method="get" class="px-1">
|
||
<input type="hidden" name="menu" value="custom">
|
||
<input type="hidden" name="back" value="<?= esc(current_url()) ?>">
|
||
<div class="row g-2 align-items-center">
|
||
<div class="col-6">
|
||
<label class="form-label mb-1 small">Menu BG</label>
|
||
<input type="color" name="menu_bg" value="<?= esc($menuLP['bg'] ?? '#0f172a') ?>" class="form-control form-control-color w-100" title="Pick background color">
|
||
</div>
|
||
<div class="col-6">
|
||
<label class="form-label mb-1 small">Text</label>
|
||
<input type="color" name="menu_text" value="<?= esc($menuLP['text'] ?? '#ffffff') ?>" class="form-control form-control-color w-100" title="Pick text color">
|
||
</div>
|
||
<div class="col-12">
|
||
<label class="form-label mb-1 small">Mode</label>
|
||
<div>
|
||
<?php $modeLP = ($menuLP['mode'] ?? 'light'); ?>
|
||
<div class="form-check form-check-inline">
|
||
<input class="form-check-input" type="radio" name="menu_mode" id="mm_light" value="light" <?= $modeLP==='light'?'checked':'' ?>>
|
||
<label class="form-check-label" for="mm_light">Light</label>
|
||
</div>
|
||
<div class="form-check form-check-inline">
|
||
<input class="form-check-input" type="radio" name="menu_mode" id="mm_dark" value="dark" <?= $modeLP==='dark'?'checked':'' ?>>
|
||
<label class="form-check-label" for="mm_dark">Dark</label>
|
||
</div>
|
||
<div class="form-check form-check-inline">
|
||
<input class="form-check-input" type="radio" name="menu_mode" id="mm_auto" value="auto" <?= ($modeLP!=='light' && $modeLP!=='dark')?'checked':'' ?>>
|
||
<label class="form-check-label" for="mm_auto">Auto</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-12 mt-1">
|
||
<button type="submit" class="btn btn-sm btn-primary w-100">Apply Custom</button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item" href="<?= base_url('/logout') ?>">Log Out</a>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
</nav>
|