Refactor: remove unused APIs, controllers, models and data files. Update: icon picker all system, Dashboard, Main UI more respone, Change: Logo, favicon.

This commit is contained in:
2026-04-23 18:44:37 +07:00
parent 8ce6cf3c7e
commit 4ba3eb4a82
48 changed files with 438 additions and 14850 deletions
+37 -11
View File
@@ -1,16 +1,23 @@
<div class="container">
<div class="d-flex justify-content-between align-items-center mt-4 mb-4">
<div class="d-flex justify-content-between align-items-center mt-4 mb-4 flex-wrap gap-2">
<div>
<h1 class="h3 mb-0" style="color: var(--primary-dark);">
<%= title %>
</h1>
<p class="text-muted mb-0">Edit content displayed on the About page</p>
</div>
<div class="d-flex gap-2">
<% if (frontendUrl) { %>
<a href="<%= frontendUrl %>/about" class="btn btn-outline-primary" target="_blank" rel="noopener">
<i class="fas fa-external-link-alt me-2"></i>View About Page
</a>
<% } %>
</div>
</div>
<div class="row">
<div class="col-12">
<form method="POST" id="aboutForm" action="/admin/about-us/update">
<form method="POST" id="aboutForm" action="/admin/about/update">
<!-- Hidden JSON inputs -->
<input type="hidden" name="hero" id="heroJson">
<input type="hidden" name="leadership" id="leadershipJson">
@@ -366,7 +373,7 @@
let originalFormData = null;
document.addEventListener('DOMContentLoaded', function () {
originalFormData = <%- JSON.stringify(data) %>;
originalFormData = <% - JSON.stringify(data) %>;
populateAll(originalFormData);
document.getElementById('aboutForm').addEventListener('submit', function (e) {
@@ -595,22 +602,31 @@
c.insertAdjacentHTML('beforeend', `
<div class="card mb-2 lf-feature-item" data-mode="${mode}">
<div class="card-body p-2">
<div class="row g-2">
<div class="row g-2 align-items-center">
<div class="col-md-3">
<input type="text" class="form-control form-control-sm" data-field="icon" value="${esc(item.icon)}" placeholder="fa-play">
<div class="input-group input-group-sm">
<span class="input-group-text icon-preview-cell" style="min-width:32px">
${item.icon ? `<i class="${esc(item.icon)}"></i>` : ''}
</span>
<input type="text" class="form-control form-control-sm" data-field="icon"
value="${esc(item.icon)}" placeholder="Click to pick..." readonly
style="cursor:pointer;background:#fff"
onclick="IconPicker.open(this)">
</div>
</div>
<div class="col-md-4">
<input type="text" class="form-control form-control-sm" data-field="title" value="${esc(item.title)}" placeholder="Title">
</div>
<div class="col-md-5">
<div class="col-md-4">
<input type="text" class="form-control form-control-sm" data-field="desc" value="${esc(item.desc)}" placeholder="Description">
</div>
<div class="col-md-1 d-flex justify-content-center">
<button type="button" class="btn btn-link text-danger btn-sm p-0" onclick="this.closest('.lf-feature-item').remove()"><i class="fas fa-trash"></i></button>
</div>
</div>
<button type="button" class="btn btn-link text-danger btn-sm p-0 mt-1" onclick="this.closest('.lf-feature-item').remove()"><i class="fas fa-trash me-1"></i>Remove</button>
</div>
</div>`);
}
function populateLearningFeatures(mode, features) {
document.getElementById(mode + 'FeaturesContainer').innerHTML = '';
features.forEach(f => addLearningFeature(mode, f));
@@ -632,16 +648,26 @@
<div class="card-body p-2">
<div class="row g-2">
<div class="col-md-3">
<input type="text" class="form-control form-control-sm" data-field="icon" value="${esc(item.icon)}" placeholder="fa-award">
<div class="input-group input-group-sm">
<span class="input-group-text icon-preview-cell" style="min-width:32px">
${item.icon ? `<i class="${esc(item.icon)}"></i>` : ''}
</span>
<input type="text" class="form-control form-control-sm" data-field="icon"
value="${esc(item.icon)}" placeholder="Click to pick..." readonly
style="cursor:pointer;background:#fff"
onclick="IconPicker.open(this)">
</div>
</div>
<div class="col-md-4">
<input type="text" class="form-control form-control-sm" data-field="title" value="${esc(item.title)}" placeholder="Title">
</div>
<div class="col-md-5">
<div class="col-md-4">
<input type="text" class="form-control form-control-sm" data-field="desc" value="${esc(item.desc)}" placeholder="Description">
</div>
<div class="col-md-1 d-flex justify-content-center">
<button type="button" class="btn btn-link text-danger btn-sm p-0 mt-1" onclick="this.closest('.acc-badge-item').remove()"><i class="fas fa-trash me-1"></i></button>
</div>
</div>
<button type="button" class="btn btn-link text-danger btn-sm p-0 mt-1" onclick="this.closest('.acc-badge-item').remove()"><i class="fas fa-trash me-1"></i>Remove</button>
</div>
</div>`);
}
+19 -16
View File
@@ -114,11 +114,14 @@
<div class="row g-2 align-items-end">
<div class="col-md-3">
<label class="form-label small">Icon</label>
<select class="form-select ch-icon">
<% iconOptions.forEach(function(opt) { %>
<option value="<%= opt.value %>" <%= (ch.icon === opt.value) ? 'selected' : '' %>><%= opt.label %></option>
<% }); %>
</select>
<div class="input-group">
<span class="input-group-text icon-preview-cell" style="min-width:38px">
<% if (ch.icon) { %><i class="<%= ch.icon %>"></i><% } %>
</span>
<input type="text" class="form-control ch-icon"
value="<%= ch.icon || '' %>" placeholder="Click to pick..." readonly
style="cursor:pointer;background:#fff" onclick="IconPicker.open(this)">
</div>
</div>
<div class="col-md-3">
<label class="form-label small">Title</label>
@@ -367,7 +370,7 @@
<script>
let statusModal = null;
window.CONTACT_ICON_OPTIONS = <%- JSON.stringify(iconOptions) %>;
// window.CONTACT_ICON_OPTIONS = <%- JSON.stringify(iconOptions) %>;
function resetContactForm() {
if (confirm('Reset all unsaved changes?')) location.reload();
@@ -405,20 +408,20 @@
// ── Dynamic rows ──────────────────────────────
function iconSelectHtml(selected) {
var opts = window.CONTACT_ICON_OPTIONS || [];
var html = '';
for (var i = 0; i < opts.length; i++) {
var o = opts[i];
html += '<option value="' + escHtml(o.value) + '"' + (o.value === selected ? ' selected' : '') + '>' + escHtml(o.label) + '</option>';
}
return html;
}
// function iconSelectHtml(selected) {
// var opts = window.CONTACT_ICON_OPTIONS || [];
// var html = '';
// for (var i = 0; i < opts.length; i++) {
// var o = opts[i];
// html += '<option value="' + escHtml(o.value) + '"' + (o.value === selected ? ' selected' : '') + '>' + escHtml(o.label) + '</option>';
// }
// return html;
// }
function buildChannelRow(ch) {
ch = ch || {};
return '<div class="card channel-row border"><div class="card-body"><div class="row g-2 align-items-end">' +
'<div class="col-md-3"><label class="form-label small">Icon</label><select class="form-select ch-icon">' + iconSelectHtml(ch.icon) + '</select></div>' +
'<div class="col-md-3"><label class="form-label small">Icon</label>' + iconPickerInput('ch-icon', ch.icon) + '</div>' +
'<div class="col-md-3"><label class="form-label small">Title</label><input type="text" class="form-control ch-title" value="' + escHtml(ch.title) + '"></div>' +
'<div class="col-md-4"><label class="form-label small">Detail</label><input type="text" class="form-control ch-detail" value="' + escHtml(ch.detail) + '"></div>' +
'<div class="col-md-2 d-flex align-items-end"><button type="button" class="btn btn-outline-danger btn-sm w-100 remove-channel"><i class="fas fa-trash"></i></button></div>' +
+142 -5
View File
@@ -87,10 +87,9 @@
<div class="row g-3">
<% const aboutPages=[ { label: 'About Us' , href: '/admin/about' , icon: 'fa-users' }, {
label: 'Partnerships' , href: '/admin/partnerships' , icon: 'fa-handshake' }, { label: 'History' ,
href: '/admin/history' , icon: 'fa-history' }, { label: 'Accreditation' ,
href: '/admin/accreditation' , icon: 'fa-certificate' }, { label: 'Admissions' ,
href: '/admin/admissions' , icon: 'fa-door-open' }, { label: 'Policies' ,
href: '/admin/policies' , icon: 'fa-file-contract' }, ]; %>
href: '/admin/history' , icon: 'fa-history' }, { label: 'Accreditation' , href: '/admin/accreditation' ,
icon: 'fa-certificate' }, { label: 'Admissions' , href: '/admin/admissions' , icon: 'fa-door-open' }, {
label: 'Policies' , href: '/admin/policies' , icon: 'fa-file-contract' }, ]; %>
<% aboutPages.forEach(page=> { %>
<div class="col-md-4">
<div class="border rounded p-3" style="background-color: var(--bs-light);">
@@ -215,7 +214,7 @@
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">API Endpoints</h5>
<span class="badge bg-primary">9 APIs</span>
<span class="badge bg-primary">15 APIs</span>
</div>
<div class="card-body p-0">
<div class="table-responsive">
@@ -436,6 +435,144 @@
</a>
</td>
</tr>
<!--Partnerships API-->
<tr>
<td>
<div class="d-flex align-items-center">
<div class="rounded-circle d-flex align-items-center justify-content-center me-2"
style="width: 32px; height: 32px; background-color: rgba(184, 183, 106, 0.1);">
<i class="fas fa-handshake" style="color: var(--primary-color);"></i>
</div>
<span>Partnerships API</span>
</div>
</td>
<td><code>/api/partnerships</code></td>
<td>
<span class="badge" style="background-color: var(--primary-color)">GET</span>
</td>
<td>API to get partnerships page data</td>
<td>
<a href="/api/partnerships" class="btn btn-sm btn-outline-primary" target="_blank">
<i class="fas fa-external-link-alt me-1"></i>View
</a>
</td>
</tr>
<!--History API-->
<tr>
<td>
<div class="d-flex align-items-center">
<div class="rounded-circle d-flex align-items-center justify-content-center me-2"
style="width: 32px; height: 32px; background-color: rgba(184, 183, 106, 0.1);">
<i class="fas fa-history" style="color: var(--primary-color);"></i>
</div>
<span>History API</span>
</div>
</td>
<td><code>/api/history</code></td>
<td>
<span class="badge" style="background-color: var(--primary-color)">GET</span>
</td>
<td>API to get history page data</td>
<td>
<a href="/api/history" class="btn btn-sm btn-outline-primary" target="_blank">
<i class="fas fa-external-link-alt me-1"></i>View
</a>
</td>
</tr>
<!--Accreditation API-->
<tr>
<td>
<div class="d-flex align-items-center">
<div class="rounded-circle d-flex align-items-center justify-content-center me-2"
style="width: 32px; height: 32px; background-color: rgba(184, 183, 106, 0.1);">
<i class="fas fa-certificate" style="color: var(--primary-color);"></i>
</div>
<span>Accreditation API</span>
</div>
</td>
<td><code>/api/accreditation</code></td>
<td>
<span class="badge" style="background-color: var(--primary-color)">GET</span>
</td>
<td>API to get accreditation page data</td>
<td>
<a href="/api/accreditation" class="btn btn-sm btn-outline-primary" target="_blank">
<i class="fas fa-external-link-alt me-1"></i>View
</a>
</td>
</tr>
<!--Admissions API-->
<tr>
<td>
<div class="d-flex align-items-center">
<div class="rounded-circle d-flex align-items-center justify-content-center me-2"
style="width: 32px; height: 32px; background-color: rgba(184, 183, 106, 0.1);">
<i class="fas fa-door-open" style="color: var(--primary-color);"></i>
</div>
<span>Admissions API</span>
</div>
</td>
<td><code>/api/admissions</code></td>
<td>
<span class="badge" style="background-color: var(--primary-color)">GET</span>
</td>
<td>API to get admissions page data</td>
<td>
<a href="/api/admissions" class="btn btn-sm btn-outline-primary" target="_blank">
<i class="fas fa-external-link-alt me-1"></i>View
</a>
</td>
</tr>
<!--Policies API-->
<tr>
<td>
<div class="d-flex align-items-center">
<div class="rounded-circle d-flex align-items-center justify-content-center me-2"
style="width: 32px; height: 32px; background-color: rgba(184, 183, 106, 0.1);">
<i class="fas fa-file-contract" style="color: var(--primary-color);"></i>
</div>
<span>Policies API</span>
</div>
</td>
<td><code>/api/policies</code></td>
<td>
<span class="badge" style="background-color: var(--primary-color)">GET</span>
</td>
<td>API to get policies page data</td>
<td>
<a href="/api/policies" class="btn btn-sm btn-outline-primary" target="_blank">
<i class="fas fa-external-link-alt me-1"></i>View
</a>
</td>
</tr>
<!--Header API-->
<tr>
<td>
<div class="d-flex align-items-center">
<div class="rounded-circle d-flex align-items-center justify-content-center me-2"
style="width: 32px; height: 32px; background-color: rgba(184, 183, 106, 0.1);">
<i class="fas fa-heading" style="color: var(--primary-color);"></i>
</div>
<span>Header API</span>
</div>
</td>
<td><code>/api/header</code></td>
<td>
<span class="badge" style="background-color: var(--primary-color)">GET</span>
</td>
<td>API to get header data</td>
<td>
<a href="/api/header" class="btn btn-sm btn-outline-primary" target="_blank">
<i class="fas fa-external-link-alt me-1"></i>View
</a>
</td>
</tr>
</tbody>
</table>
</div>
+1 -1
View File
@@ -350,7 +350,7 @@
<div class="card-body p-3">
<div class="row g-2 align-items-center">
<div class="col-md-4">
<label class="form-label small">Icon (FA class)</label>
<label class="form-label small">Icon</label>
<div class="input-group">
<span class="input-group-text icon-preview-cell" style="min-width:38px">
${item.icon ? `<i class="${esc(item.icon)}"></i>` : ''}
+45 -71
View File
@@ -1,11 +1,18 @@
<div class="container">
<div class="d-flex justify-content-between align-items-center mt-4 mb-4">
<div class="d-flex justify-content-between align-items-center mt-4 mb-4 flex-wrap gap-2">
<div>
<h1 class="h3 mb-0" style="color: var(--primary-dark);">
<%= title %>
</h1>
<p class="text-muted mb-0">Edit content displayed on the Home page</p>
</div>
<div class="d-flex gap-2">
<% if (frontendUrl) { %>
<a href="<%= frontendUrl %>" class="btn btn-outline-primary" target="_blank" rel="noopener">
<i class="fas fa-external-link-alt me-2"></i>View Home Page
</a>
<% } %>
</div>
</div>
<div class="row">
@@ -103,8 +110,16 @@
<div class="row g-3">
<div class="col-md-4">
<label class="form-label">Icon (FA class)</label>
<input type="text" class="form-control" id="floatingBadgeIcon"
value="<%= data.hero?.floatingBadge?.icon || '' %>" placeholder="e.g. fa-users">
<div class="input-group">
<span class="input-group-text icon-preview-cell" style="min-width:38px">
<% if (data.hero?.floatingBadge?.icon) { %><i
class="<%= data.hero.floatingBadge.icon %>"></i>
<% } %>
</span>
<input type="text" class="form-control" id="floatingBadgeIcon"
value="<%= data.hero?.floatingBadge?.icon || '' %>" placeholder="Click to pick..." readonly
style="cursor:pointer;background:#fff" onclick="IconPicker.open(this)">
</div>
</div>
<div class="col-md-4">
<label class="form-label">Value</label>
@@ -200,13 +215,12 @@
rows="2"><%= data.programs?.description || '' %></textarea>
</div>
</div>
<div class="mt-4">
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="mb-0">Program Items</h6>
<button type="button" class="btn btn-outline-primary btn-sm" onclick="addProgramItem()"><i
class="fas fa-plus me-1"></i>Add Program</button>
</div>
<div id="programItemsContainer"></div>
<div class="alert alert-info mt-4 mb-0">
<i class="fas fa-info-circle me-2"></i>
Programs items will automatically display from the Programs table.
<a href="/admin/programme" target="_blank" class="fw-bold ms-1">
<i class="fas fa-external-link-alt me-1"></i>Manage programs
</a>
</div>
</div>
</div>
@@ -272,7 +286,7 @@
let originalFormData = null;
document.addEventListener('DOMContentLoaded', function () {
originalFormData = <%- JSON.stringify(data) %>;
originalFormData = <% - JSON.stringify(data) %>;
populateAll(originalFormData);
document.getElementById('homeForm').addEventListener('submit', function (e) {
@@ -320,7 +334,6 @@
const pr = data.programs || {};
setVal('programsHeading', pr.heading);
setVal('programsDescription', pr.description);
populateProgramItems(pr.items || []);
// Request Info
const ri = data.requestInfo || {};
@@ -423,8 +436,16 @@
<div class="card-body p-3">
<div class="row g-2">
<div class="col-md-2">
<label class="form-label small">Icon (FA class)</label>
<input type="text" class="form-control form-control-sm" data-field="icon" value="${esc(item.icon)}" placeholder="fa-trophy">
<label class="form-label small">Icon</label>
<div class="input-group">
<span class="input-group-text icon-preview-cell" style="min-width:38px">
${item.icon ? `<i class="${esc(item.icon)}"></i>` : ''}
</span>
<input type="text" class="form-control form-control-sm" data-field="icon"
value="${esc(item.icon)}" placeholder="Click to pick..." readonly
style="cursor:pointer;background:#fff"
onclick="IconPicker.open(this)">
</div>
</div>
<div class="col-md-2">
<label class="form-label small">Title</label>
@@ -462,8 +483,16 @@
<div class="card-body p-3">
<div class="row g-2">
<div class="col-md-3">
<label class="form-label small">Icon (FA class)</label>
<input type="text" class="form-control form-control-sm" data-field="icon" value="${esc(item.icon)}" placeholder="fa-laptop-code">
<label class="form-label small">Icon</label>
<div class="input-group">
<span class="input-group-text icon-preview-cell" style="min-width:38px">
${item.icon ? `<i class="${esc(item.icon)}"></i>` : ''}
</span>
<input type="text" class="form-control form-control-sm" data-field="icon"
value="${esc(item.icon)}" placeholder="Click to pick..." readonly
style="cursor:pointer;background:#fff"
onclick="IconPicker.open(this)">
</div>
</div>
<div class="col-md-3">
<label class="form-label small">Title</label>
@@ -524,61 +553,6 @@
items.forEach(item => addValuePropStat(item));
}
// ── Program Items ────────────────────────────────────────────────────────
function addProgramItem(item = {}) {
const idx = Date.now();
const c = document.getElementById('programItemsContainer');
const html = `
<div class="card mb-3 program-item">
<div class="card-body p-3">
<div class="row g-2">
<div class="col-md-3">
<label class="form-label small">Title</label>
<input type="text" class="form-control form-control-sm" data-field="title" value="${esc(item.title)}">
</div>
<div class="col-md-2">
<label class="form-label small">Category</label>
<input type="text" class="form-control form-control-sm" data-field="category" value="${esc(item.category)}">
</div>
<div class="col-md-2">
<label class="form-label small">Duration</label>
<input type="text" class="form-control form-control-sm" data-field="duration" value="${esc(item.duration)}">
</div>
<div class="col-md-1">
<label class="form-label small">Rating</label>
<input type="text" class="form-control form-control-sm" data-field="rating" value="${esc(item.rating)}">
</div>
<div class="col-md-2">
<label class="form-label small">Student Count</label>
<input type="text" class="form-control form-control-sm" data-field="studentCount" value="${esc(item.studentCount)}">
</div>
<div class="col-md-2">
<label class="form-label small">Href</label>
<input type="text" class="form-control form-control-sm" data-field="href" value="${esc(item.href)}">
</div>
<div class="col-md-8">
<label class="form-label small">Description</label>
<input type="text" class="form-control form-control-sm" data-field="description" value="${esc(item.description)}">
</div>
<div class="col-md-4">
<label class="form-label small">Image URL</label>
<div class="input-group input-group-sm">
<input type="text" class="form-control" data-field="image" id="progImg_${idx}" value="${esc(item.image)}">
<button class="btn btn-outline-primary btn-upload-image" type="button" data-target-input="progImg_${idx}" data-image-type="home"><i class="fas fa-upload"></i></button>
</div>
</div>
</div>
<button type="button" class="btn btn-link text-danger btn-sm p-0 mt-2" onclick="this.closest('.program-item').remove()"><i class="fas fa-trash me-1"></i>Remove</button>
</div>
</div>`;
c.insertAdjacentHTML('beforeend', html);
}
function populateProgramItems(items) {
document.getElementById('programItemsContainer').innerHTML = '';
items.forEach(item => addProgramItem(item));
}
// ── Request Info Programs ────────────────────────────────────────────────
function addRequestInfoProgram(val = '') {
const c = document.getElementById('requestInfoProgramsContainer');
+43 -25
View File
@@ -201,12 +201,15 @@
</div>
<div class="col-md-4">
<label class="form-label small">Icon</label>
<select class="form-select course-icon-select">
<option value="">— No icon —</option>
<% iconOptions.forEach(function(opt) { %>
<option value="<%= opt.value %>" <%= (course.icon === opt.value) ? 'selected' : '' %>><%= opt.label %></option>
<% }); %>
</select>
<div class="input-group">
<span class="input-group-text icon-preview-cell" style="min-width:38px">
<% if (course.icon) { %><i class="<%= course.icon %>"></i><% } %>
</span>
<input type="text" class="form-control course-icon-select"
value="<%= course.icon || '' %>" placeholder="Click to pick..." readonly
style="cursor:pointer;background:#fff"
onclick="IconPicker.open(this)">
</div>
</div>
<div class="col-md-2 d-flex align-items-end justify-content-end">
<button type="button" class="btn btn-outline-danger btn-sm remove-course">
@@ -269,12 +272,15 @@
</div>
<div class="col-md-5">
<label class="form-label small">Icon</label>
<select class="form-select outcome-icon-select">
<option value="">— No icon —</option>
<% iconOptions.forEach(function(opt) { %>
<option value="<%= opt.value %>" <%= (outcome.icon === opt.value) ? 'selected' : '' %>><%= opt.label %></option>
<% }); %>
</select>
<div class="input-group">
<span class="input-group-text icon-preview-cell" style="min-width:38px">
<% if (outcome.icon) { %><i class="<%= outcome.icon %>"></i><% } %>
</span>
<input type="text" class="form-control outcome-icon-select"
value="<%= outcome.icon || '' %>" placeholder="Click to pick..." readonly
style="cursor:pointer;background:#fff"
onclick="IconPicker.open(this)">
</div>
</div>
<div class="col-md-1 d-flex align-items-end justify-content-end">
<button type="button" class="btn btn-outline-danger btn-sm remove-outcome"><i class="fas fa-trash"></i></button>
@@ -358,23 +364,23 @@
</div>
<script>
window.PROGRAMME_ICON_OPTIONS = <%- JSON.stringify(iconOptions || []) %>;
// window.PROGRAMME_ICON_OPTIONS = <%- JSON.stringify(iconOptions || []) %>;
function escHtml(s) {
return String(s || '')
.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
function iconOptionsHtml(selected) {
var opts = window.PROGRAMME_ICON_OPTIONS;
var html = '<option value="">— No icon —</option>';
for (var i = 0; i < opts.length; i++) {
var o = opts[i];
var sel = (o.value === selected) ? ' selected' : '';
html += '<option value="' + escHtml(o.value) + '"' + sel + '>' + escHtml(o.label) + '</option>';
}
return html;
}
// function iconOptionsHtml(selected) {
// var opts = window.PROGRAMME_ICON_OPTIONS;
// var html = '<option value="">— No icon —</option>';
// for (var i = 0; i < opts.length; i++) {
// var o = opts[i];
// var sel = (o.value === selected) ? ' selected' : '';
// html += '<option value="' + escHtml(o.value) + '"' + sel + '>' + escHtml(o.label) + '</option>';
// }
// return html;
// }
function buildCourseRow(c) {
c = c || {};
@@ -387,7 +393,13 @@
'<div class="col-md-4"><label class="form-label small">Title</label>' +
'<input type="text" class="form-control course-title" value="' + escHtml(c.title) + '"></div>' +
'<div class="col-md-4"><label class="form-label small">Icon</label>' +
'<select class="form-select course-icon-select"><' + 'option value="">— No icon —</' + 'option>' + iconOptionsHtml(c.icon) + '</select></div>' +
'<div class="input-group">' +
'<span class="input-group-text icon-preview-cell" style="min-width:38px">' +
(c.icon ? '<i class="' + escHtml(c.icon) + '"></i>' : '') +
'</span>' +
'<input type="text" class="form-control course-icon-select" value="' + escHtml(c.icon) + '" placeholder="Click to pick..." readonly ' +
'style="cursor:pointer;background:#fff" onclick="IconPicker.open(this)">' +
'</div></div>' +
'<div class="col-md-2 d-flex align-items-end justify-content-end">' +
'<button type="button" class="btn btn-outline-danger btn-sm remove-course"><i class="fas fa-trash"></i></button></div>' +
'<div class="col-md-12"><label class="form-label small">Description</label>' +
@@ -407,7 +419,13 @@
'<div class="col-md-6"><label class="form-label small">Title</label>' +
'<input type="text" class="form-control outcome-title" value="' + escHtml(o.title) + '"></div>' +
'<div class="col-md-5"><label class="form-label small">Icon</label>' +
'<select class="form-select outcome-icon-select"><option value="">— No icon —</option>' + iconOptionsHtml(o.icon) + '</select></div>' +
'<div class="input-group">' +
'<span class="input-group-text icon-preview-cell" style="min-width:38px">' +
(o.icon ? '<i class="' + escHtml(o.icon) + '"></i>' : '') +
'</span>' +
'<input type="text" class="form-control outcome-icon-select" value="' + escHtml(o.icon) + '" placeholder="Click to pick..." readonly ' +
'style="cursor:pointer;background:#fff" onclick="IconPicker.open(this)">' +
'</div></div>' +
'<div class="col-md-1 d-flex align-items-end justify-content-end">' +
'<button type="button" class="btn btn-outline-danger btn-sm remove-outcome"><i class="fas fa-trash"></i></button></div>' +
'<div class="col-md-12"><label class="form-label small">Description</label>' +
+20 -18
View File
@@ -101,11 +101,14 @@
<div class="row g-2 align-items-end">
<div class="col-md-4">
<label class="form-label small">Icon</label>
<select class="form-select vp-icon-select">
<% iconOptions.forEach(function(opt) { %>
<option value="<%= opt.value %>" <%= (vp.icon === opt.value) ? 'selected' : '' %>><%= opt.label %></option>
<% }); %>
</select>
<div class="input-group">
<span class="input-group-text icon-preview-cell" style="min-width:38px">
<% if (vp.icon) { %><i class="<%= vp.icon %>"></i><% } %>
</span>
<input type="text" class="form-control vp-icon-select"
value="<%= vp.icon || '' %>" placeholder="Click to pick..." readonly
style="cursor:pointer;background:#fff" onclick="IconPicker.open(this)">
</div>
</div>
<div class="col-md-7">
<label class="form-label small">Title</label>
@@ -273,7 +276,7 @@
}
}
window.REQUEST_INFO_ICON_OPTIONS = <%- JSON.stringify(iconOptions) %>;
// window.REQUEST_INFO_ICON_OPTIONS = <%- JSON.stringify(iconOptions) %>;
function escapeHtml(s) {
return String(s || '')
@@ -283,24 +286,23 @@
.replace(/"/g, '&quot;');
}
function iconOptionsHtml(selected) {
var opts = window.REQUEST_INFO_ICON_OPTIONS || [];
var html = '';
for (var i = 0; i < opts.length; i++) {
var o = opts[i];
var sel = (o.value === selected) ? ' selected' : '';
html += '<option value="' + escapeHtml(o.value) + '"' + sel + '>' + escapeHtml(o.label) + '</option>';
}
return html;
}
// function iconOptionsHtml(selected) {
// var opts = window.REQUEST_INFO_ICON_OPTIONS || [];
// var html = '';
// for (var i = 0; i < opts.length; i++) {
// var o = opts[i];
// var sel = (o.value === selected) ? ' selected' : '';
// html += '<option value="' + escapeHtml(o.value) + '"' + sel + '>' + escapeHtml(o.label) + '</option>';
// }
// return html;
// }
function buildValuePropRow(vp) {
vp = vp || {};
var iconSel = '<select class="form-select vp-icon-select">' + iconOptionsHtml(vp.icon) + '</select>';
return (
'<div class="card vp-row border"><div class="card-body">' +
'<div class="row g-2 align-items-end">' +
'<div class="col-md-4"><label class="form-label small">Icon</label>' + iconSel + '</div>' +
'<div class="col-md-4"><label class="form-label small">Icon</label>' + iconPickerInput('vp-icon-select', vp.icon) + '</div>' +
'<div class="col-md-7"><label class="form-label small">Title</label>' +
'<input type="text" class="form-control vp-title" value="' + escapeHtml(vp.title) + '"></div>' +
'<div class="col-md-1 d-flex align-items-end justify-content-end">' +
+38 -30
View File
@@ -137,19 +137,25 @@
<div class="row g-2">
<div class="col-md-4">
<label class="form-label small">Icon</label>
<select class="form-select svc-icon-select">
<% iconOptions.forEach(function(opt) { %>
<option value="<%= opt.value %>" <%= (svc.icon === opt.value) ? 'selected' : '' %>><%= opt.label %></option>
<% }); %>
</select>
<div class="input-group">
<span class="input-group-text icon-preview-cell" style="min-width:38px">
<% if (svc.icon) { %><i class="<%= svc.icon %>"></i><% } %>
</span>
<input type="text" class="form-control ch-icon"
value="<%= svc.icon || '' %>" placeholder="Click to pick..." readonly
style="cursor:pointer;background:#fff" onclick="IconPicker.open(this)">
</div>
</div>
<div class="col-md-4">
<label class="form-label small">Hours icon</label>
<select class="form-select svc-hours-icon-select">
<% iconOptions.forEach(function(opt) { %>
<option value="<%= opt.value %>" <%= (svc.hoursIcon === opt.value) ? 'selected' : '' %>><%= opt.label %></option>
<% }); %>
</select>
<div class="input-group">
<span class="input-group-text icon-preview-cell" style="min-width:38px">
<% if (svc.hoursIcon) { %><i class="<%= svc.hoursIcon %>"></i><% } %>
</span>
<input type="text" class="form-control ch-icon"
value="<%= svc.hoursIcon || '' %>" placeholder="Click to pick..." readonly
style="cursor:pointer;background:#fff" onclick="IconPicker.open(this)">
</div>
</div>
<div class="col-md-4 d-flex align-items-end justify-content-end">
<button type="button" class="btn btn-outline-danger btn-sm remove-service"><i class="fas fa-trash"></i></button>
@@ -205,11 +211,14 @@
<div class="row g-2 align-items-end">
<div class="col-md-3">
<label class="form-label small">Icon</label>
<select class="form-select ch-icon-select">
<% iconOptions.forEach(function(opt) { %>
<option value="<%= opt.value %>" <%= (ch.icon === opt.value) ? 'selected' : '' %>><%= opt.label %></option>
<% }); %>
</select>
<div class="input-group">
<span class="input-group-text icon-preview-cell" style="min-width:38px">
<% if (ch.icon) { %><i class="<%= ch.icon %>"></i><% } %>
</span>
<input type="text" class="form-control ch-icon"
value="<%= ch.icon || '' %>" placeholder="Click to pick..." readonly
style="cursor:pointer;background:#fff" onclick="IconPicker.open(this)">
</div>
</div>
<div class="col-md-3">
<label class="form-label small">Title</label>
@@ -314,7 +323,7 @@
}
}
window.STUDENT_SUPPORT_ICON_OPTIONS = <%- JSON.stringify(iconOptions) %>;
// window.STUDENT_SUPPORT_ICON_OPTIONS = <%- JSON.stringify(iconOptions) %>;
function escapeHtml(s) {
return String(s || '')
@@ -324,16 +333,16 @@
.replace(/"/g, '&quot;');
}
function iconOptionsHtml(selected) {
var opts = window.STUDENT_SUPPORT_ICON_OPTIONS || [];
var html = '';
for (var i = 0; i < opts.length; i++) {
var o = opts[i];
var sel = (o.value === selected) ? ' selected' : '';
html += '<option value="' + escapeHtml(o.value) + '"' + sel + '>' + escapeHtml(o.label) + '</option>';
}
return html;
}
// function iconOptionsHtml(selected) {
// var opts = window.STUDENT_SUPPORT_ICON_OPTIONS || [];
// var html = '';
// for (var i = 0; i < opts.length; i++) {
// var o = opts[i];
// var sel = (o.value === selected) ? ' selected' : '';
// html += '<option value="' + escapeHtml(o.value) + '"' + sel + '>' + escapeHtml(o.label) + '</option>';
// }
// return html;
// }
function buildServiceRow(svc) {
svc = svc || {};
@@ -343,8 +352,8 @@
'<div class="card service-row border">' +
'<div class="card-body">' +
'<div class="row g-2">' +
'<div class="col-md-4"><label class="form-label small">Icon</label>' + iconSel + '</div>' +
'<div class="col-md-4"><label class="form-label small">Hours icon</label>' + hoursIconSel + '</div>' +
'<div class="col-md-4"><label class="form-label small">Icon</label>' + iconPickerInput('svc-icon-select', svc.icon) + '</div>' +
'<div class="col-md-4"><label class="form-label small">Hours icon</label>' + iconPickerInput('svc-hours-icon-select', svc.hoursIcon) + '</div>' +
'<div class="col-md-4 d-flex align-items-end justify-content-end">' +
'<button type="button" class="btn btn-outline-danger btn-sm remove-service"><i class="fas fa-trash"></i></button>' +
'</div>' +
@@ -364,11 +373,10 @@
function buildChannelRow(ch) {
ch = ch || {};
var iconSel = '<select class="form-select ch-icon-select">' + iconOptionsHtml(ch.icon) + '</select>';
return (
'<div class="card channel-row border"><div class="card-body py-2">' +
'<div class="row g-2 align-items-end">' +
'<div class="col-md-3"><label class="form-label small">Icon</label>' + iconSel + '</div>' +
'<div class="col-md-3"><label class="form-label small">Icon</label>' + iconPickerInput('ch-icon-select', ch.icon) + '</div>' +
'<div class="col-md-3"><label class="form-label small">Title</label>' +
'<input type="text" class="form-control ch-title" value="' + escapeHtml(ch.title) + '"></div>' +
'<div class="col-md-5"><label class="form-label small">Detail</label>' +
+2 -2
View File
@@ -5,7 +5,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>
<%= title %> | CMS-SIMS
<%= title %> | CMS-LAMS
</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
@@ -157,7 +157,7 @@
</div>
<div style="text-align: center; margin-bottom: 20px;">
<h4 style="color: var(--primary-color); font-weight: 600; margin-bottom: 5px;">CMS Management System</h4>
<h4 style="color: var(--primary-color); font-weight: 600; margin-bottom: 5px;">Content Management System</h4>
<p style="color: var(--text-color); font-size: 13px;">Welcome to Content Management System</p>
</div>
+17
View File
@@ -1,4 +1,21 @@
<!-- Hero Section -->
<style>
.hero {
padding: 3rem 2rem;
}
@media (min-width: 768px) {
.hero {
padding: 4rem 6rem;
}
}
@media (min-width: 992px) {
.hero {
padding: 5rem 10rem;
}
}
</style>
<section class="container">
<div class="hero"
style="background: linear-gradient(135deg, var(--primary-color), var(--primary-dark)); color: white; border-radius: 20px; box-shadow: 0 15px 30px rgba(0,0,0,0.1); margin-top: 2rem; overflow: hidden; position: relative;">
+39 -22
View File
@@ -6,7 +6,7 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>
<%= typeof title !=='undefined' ? title + ' | ' : '' %>CMS.HAILearning
<%= typeof title !=='undefined' ? title + ' | ' : '' %>CMS.LAMS
</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" />
@@ -1024,13 +1024,16 @@
<nav class="navbar navbar-expand-lg navbar-light sticky-top">
<div class="container">
<a class="navbar-brand d-flex align-items-center" href="/">
<img src="/img/logo/logo-hai-learning.png" alt="Logo" style="
width: 45px;
height: 45px;
border-radius: 50%;
margin-right: 10px;
" />
CMS.HAILearning
<img src="/img/logo/logo.jpg" alt="Logo" style="
width: 45px;
height: 45px;
border-radius: 50%;
margin-right: 10px;
" />
<div class="d-flex flex-column" style="line-height: 1.1;">
<span style="font-weight: 700; font-size: 1rem; color: var(--primary-color);">LAMS</span>
<span style="font-size: 0.65rem; color: #6c757d; letter-spacing: 0.08em;">CONTENT MANAGEMENT</span>
</div>
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
@@ -1069,14 +1072,33 @@
About
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item <%= currentPath === '/admin/about' ? 'active' : '' %>" href="/admin/about">About Us</a></li>
<li><a class="dropdown-item <%= currentPath === '/admin/partnerships' ? 'active' : '' %>" href="/admin/partnerships">Partnerships</a></li>
<li><a class="dropdown-item <%= currentPath === '/admin/history' ? 'active' : '' %>" href="/admin/history">History</a></li>
<li><a class="dropdown-item <%= currentPath === '/admin/accreditation' ? 'active' : '' %>" href="/admin/accreditation">Accreditation</a></li>
<li><a class="dropdown-item <%= currentPath === '/admin/admissions' ? 'active' : '' %>" href="/admin/admissions">Admissions</a></li>
<li><a class="dropdown-item <%= currentPath === '/admin/policies' ? 'active' : '' %>" href="/admin/policies">Policies</a></li>
<li><a class="dropdown-item <%= currentPath === '/admin/about' ? 'active' : '' %>"
href="/admin/about">About Us</a></li>
<li><a class="dropdown-item <%= currentPath === '/admin/partnerships' ? 'active' : '' %>"
href="/admin/partnerships">Partnerships</a></li>
<li><a class="dropdown-item <%= currentPath === '/admin/history' ? 'active' : '' %>"
href="/admin/history">History</a></li>
<li><a class="dropdown-item <%= currentPath === '/admin/accreditation' ? 'active' : '' %>"
href="/admin/accreditation">Accreditation</a></li>
<li><a class="dropdown-item <%= currentPath === '/admin/policies' ? 'active' : '' %>"
href="/admin/policies">Policies</a></li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link" href="/admin/programme">Programmes</a>
</li>
<li class="nav-item">
<a class="nav-link <%= currentPath === '/admin/student-support' ? 'active' : '' %>"
href="/admin/student-support">Student Support</a>
</li>
<li class="nav-item">
<a class="nav-link <%= currentPath === '/admin/admissions' ? 'active' : '' %>"
href="/admin/admissions">Admissions</a>
</li>
<li class="nav-item">
<a class="nav-link <%= currentPath === '/admin/blog' ? 'active' : '' %>" href="/admin/blog">Blog</a>
</li>
@@ -1084,13 +1106,8 @@
<a class="nav-link <%= currentPath === '/admin/contact' ? 'active' : '' %>" href="/admin/contact">Contact
Us</a>
</li>
<li class="nav-item">
<a class="nav-link <%= currentPath === '/admin/student-support' ? 'active' : '' %>"
href="/admin/student-support">Student Support</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/admin/programme">Programmes</a>
</li>
<li class="nav-item">
<a class="nav-link <%= currentPath === '/admin/audit-logs' ? 'active' : '' %>"
href="/admin/audit-logs">Audit Log
@@ -1502,4 +1519,4 @@
<%- script %>
</body>
</html>
</html>