feat(demo): update prototype to showcase authentic Windows and Android app screens

This commit is contained in:
ssbg04 committed 2026-09-28 22:23:12 +08:00
1 parent 18abb9a6d8
commit fca3a1f9d7
3 files changed
+473 -1722

No files matched your search

+148 -389
View File
@@ -1,371 +1,149 @@
/**
* TIS-RMS Interactive Prototype Logic
* Powers navigation, device switching, mock data filtering, and simulated workflows.
* TIS-RMS Interactive Prototype Showcase
* Drives real screen switching between actual screenshots and interactive dialogs.
*/
// ── Mock Data ───────────────────────────────────────────────────
const MOCK_STUDENTS = [
{ id: 1, lrn: '109876543210', name: 'DELA CRUZ, Juan Santos', grade: 'Grade 10', section: 'Jacinto', sex: 'Male', status: 'Enrolled', age: 16, contact: '0917-123-4567', docs: 4 },
{ id: 2, lrn: '109876543211', name: 'SANTOS, Maria Clara Perez', grade: 'Grade 9', section: 'Silang', sex: 'Female', status: 'Enrolled', age: 15, contact: '0918-234-5678', docs: 5 },
{ id: 3, lrn: '109876543212', name: 'ALVAREZ, Gabriel Mendoza', grade: 'Grade 7', section: 'Rizal', sex: 'Male', status: 'Enrolled', age: 13, contact: '0919-345-6789', docs: 3 },
{ id: 4, lrn: '109876543213', name: 'BAUTISTA, Chloe Anne Flores', grade: 'Grade 8', section: 'Aguinaldo', sex: 'Female', status: 'Enrolled', age: 14, contact: '0920-456-7890', docs: 4 },
{ id: 5, lrn: '109876543214', name: 'RAMIREZ, Christian Paul Torres', grade: 'Grade 11', section: 'TVL-ICT', sex: 'Male', status: 'Enrolled', age: 17, contact: '0921-567-8901', docs: 5 },
{ id: 6, lrn: '109876543215', name: 'VILLANUEVA, Princess Diane Gomez', grade: 'Grade 12', section: 'STEM A', sex: 'Female', status: 'Enrolled', age: 18, contact: '0922-678-9012', docs: 5 },
{ id: 7, lrn: '109876543216', name: 'CASTILLO, Joshua Mark Reyes', grade: 'Grade 10', section: 'Tandang Sora', sex: 'Male', status: 'Enrolled', age: 16, contact: '0923-789-0123', docs: 4 },
{ id: 8, lrn: '109876543217', name: 'MERCADO, Angel Mae Lim', grade: 'Grade 7', section: 'Bonifacio', sex: 'Female', status: 'Enrolled', age: 13, contact: '0924-890-1234', docs: 3 },
const SCREENS = [
{ id: 'dashboard', name: 'Dashboard', icon: '📊' },
{ id: 'students', name: 'Students', icon: '👥' },
{ id: 'documents', name: 'Documents', icon: '📁' },
{ id: 'archives', name: 'Archives', icon: '📦' },
{ id: 'reports', name: 'Reports', icon: '📈' },
{ id: 'users', name: 'Users', icon: '👤' },
{ id: 'history', name: 'History', icon: '🕒' },
{ id: 'settings', name: 'Settings', icon: '⚙️' },
];
const MOCK_DOCS = [
{ name: 'PSA / NSO Birth Certificate', code: 'DOC-PSA', required: true, status: 'Verified', count: 1420 },
{ name: 'SF10 / Form 137 (Permanent Record)', code: 'DOC-SF10', required: true, status: 'Verified', count: 1388 },
{ name: 'SF9 / Form 138 (Report Card)', code: 'DOC-SF9', required: true, status: 'Verified', count: 1405 },
{ name: 'Certificate of Good Moral Character', code: 'DOC-GMC', required: false, status: 'Complete', count: 1290 },
{ name: '2x2 Recent ID Photo', code: 'DOC-PHOTO', required: true, status: 'Verified', count: 1482 },
];
const MOCK_CLASSES = [
{ grade: 'Grade 7', section: 'Rizal', adviser: 'Ms. Carmela Diaz', students: 46, max: 50 },
{ grade: 'Grade 7', section: 'Bonifacio', adviser: 'Mr. Eduardo Ramos', students: 48, max: 50 },
{ grade: 'Grade 8', section: 'Aguinaldo', adviser: 'Mrs. Leah Manalo', students: 45, max: 50 },
{ grade: 'Grade 8', section: 'Luna', adviser: 'Mr. Kenneth Ortiz', students: 47, max: 50 },
{ grade: 'Grade 9', section: 'Silang', adviser: 'Ms. Joanne Beltran', students: 44, max: 50 },
{ grade: 'Grade 10', section: 'Jacinto', adviser: 'Mr. Roderick Tan', students: 49, max: 50 },
{ grade: 'Grade 11', section: 'TVL-ICT', adviser: 'Engr. Mark Soriano', students: 42, max: 45 },
{ grade: 'Grade 12', section: 'STEM A', adviser: 'Dr. Evelyn Cruz', students: 40, max: 45 },
];
// ── Application State ──────────────────────────────────────────
let currentDevice = 'windows';
let currentDevice = 'windows'; // 'windows' | 'android'
let currentScreen = 'dashboard';
let currentTheme = 'light';
let studentFilter = 'all';
let searchQuery = '';
// ── Initialization ─────────────────────────────────────────────
document.addEventListener('DOMContentLoaded', () => {
setupDeviceSwitcher();
setupThemeToggle();
setupNavigation();
renderStudentsTable();
renderMobileStudentsList();
renderDocsList();
renderClassesList();
startClock();
setupScreenPills();
setupKeyboardNavigation();
updateView();
});
// ── Device Switcher ────────────────────────────────────────────
// ── Device Switcher ───────────────────────────────────────────
function setupDeviceSwitcher() {
const winBtn = document.getElementById('btn-view-windows');
const androidBtn = document.getElementById('btn-view-android');
const winFrame = document.getElementById('desktop-frame');
const phoneFrame = document.getElementById('phone-frame');
winBtn.addEventListener('click', () => {
currentDevice = 'windows';
winBtn.classList.add('active');
androidBtn.classList.remove('active');
winFrame.style.display = 'flex';
phoneFrame.style.display = 'none';
syncScreens();
document.getElementById('desktop-window').style.display = 'flex';
document.getElementById('phone-mockup').style.display = 'none';
updateView();
});
androidBtn.addEventListener('click', () => {
currentDevice = 'android';
androidBtn.classList.add('active');
winBtn.classList.remove('active');
winFrame.style.display = 'none';
phoneFrame.style.display = 'flex';
syncScreens();
document.getElementById('desktop-window').style.display = 'none';
document.getElementById('phone-mockup').style.display = 'flex';
updateView();
});
}
// ── Theme Toggle ───────────────────────────────────────────────
function setupThemeToggle() {
const toggleBtn = document.getElementById('theme-toggle-btn');
toggleBtn.addEventListener('click', () => {
currentTheme = currentTheme === 'light' ? 'dark' : 'light';
document.documentElement.setAttribute('data-theme', currentTheme);
toggleBtn.innerHTML = currentTheme === 'light'
? `<svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>`
: `<svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>`;
});
}
// ── Screen Selector Pills ─────────────────────────────────────
function setupScreenPills() {
const bar = document.getElementById('screen-selector-bar');
if (!bar) return;
// ── Navigation ─────────────────────────────────────────────────
function setupNavigation() {
// Desktop sidebar clicks
document.querySelectorAll('.win-nav-item').forEach(item => {
item.addEventListener('click', () => {
const target = item.getAttribute('data-screen');
if (target) navigateTo(target);
});
});
// Mobile bottom nav clicks
document.querySelectorAll('.bottom-nav-item').forEach(item => {
item.addEventListener('click', () => {
const target = item.getAttribute('data-screen');
if (target) navigateTo(target);
});
});
}
function navigateTo(screenId) {
currentScreen = screenId;
syncScreens();
}
function syncScreens() {
// Update desktop sidebar active class
document.querySelectorAll('.win-nav-item').forEach(el => {
el.classList.toggle('active', el.getAttribute('data-screen') === currentScreen);
});
// Update mobile bottom nav active class
document.querySelectorAll('.bottom-nav-item').forEach(el => {
el.classList.toggle('active', el.getAttribute('data-screen') === currentScreen);
});
// Update desktop content views
document.querySelectorAll('.win-screen-view').forEach(view => {
view.style.display = view.id === `win-${currentScreen}` ? 'block' : 'none';
});
// Update mobile content views
document.querySelectorAll('.phone-screen-view').forEach(view => {
view.style.display = view.id === `phone-${currentScreen}` ? 'block' : 'none';
});
// Update breadcrumb titles
const titles = {
dashboard: 'Dashboard Overview',
students: 'Students Directory',
documents: 'Document Requirements',
academic: 'Classes & Academic Structure',
settings: 'System Settings & About'
};
const winTitle = document.getElementById('win-breadcrumb-title');
if (winTitle) winTitle.textContent = titles[currentScreen] || 'Dashboard';
const phoneTitle = document.getElementById('phone-header-title');
if (phoneTitle) phoneTitle.textContent = titles[currentScreen] || 'TIS-RMS';
}
// ── Students Table & Card Rendering ────────────────────────────
function renderStudentsTable() {
const tbody = document.getElementById('students-table-body');
if (!tbody) return;
const filtered = filterStudentData();
tbody.innerHTML = '';
if (filtered.length === 0) {
tbody.innerHTML = `<tr><td colspan="7" style="text-align: center; padding: 32px; color: var(--win-text-muted);">No student records matched your search query.</td></tr>`;
return;
}
filtered.forEach(student => {
const tr = document.createElement('tr');
tr.className = 'student-row-click';
tr.innerHTML = `
<td style="font-weight: 600;">${student.name}</td>
<td style="font-family: monospace; color: var(--win-text-muted);">${student.lrn}</td>
<td>${student.grade}</td>
<td>${student.section}</td>
<td>${student.sex}</td>
<td><span class="status-badge badge-enrolled">${student.status}</span></td>
<td>
<button class="btn-secondary" style="height: 28px; padding: 0 10px; font-size: 11px;" onclick="openStudentModal(${student.id})">
View Details
</button>
</td>
`;
tr.addEventListener('click', (e) => {
if (e.target.tagName !== 'BUTTON') openStudentModal(student.id);
});
tbody.appendChild(tr);
});
}
function renderMobileStudentsList() {
const container = document.getElementById('mobile-students-container');
if (!container) return;
const filtered = filterStudentData();
container.innerHTML = '';
if (filtered.length === 0) {
container.innerHTML = `<div style="text-align:center; padding: 30px; color: var(--win-text-muted); font-size: 13px;">No student records found.</div>`;
return;
}
filtered.forEach(student => {
const card = document.createElement('div');
card.className = 'mobile-student-card';
card.innerHTML = `
<div class="m-student-header">
<span class="m-student-name">${student.name}</span>
<span class="status-badge badge-enrolled">${student.status}</span>
</div>
<div class="m-student-lrn">LRN: ${student.lrn}</div>
<div class="m-student-footer">
<span>${student.grade} - ${student.section}</span>
<span style="color: var(--primary-green); font-weight: 600;">Details &rsaquo;</span>
</div>
`;
card.addEventListener('click', () => openStudentModal(student.id));
container.appendChild(card);
});
}
function filterStudentData() {
return MOCK_STUDENTS.filter(s => {
const matchesSearch = s.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
s.lrn.includes(searchQuery) ||
s.section.toLowerCase().includes(searchQuery.toLowerCase());
if (studentFilter === 'all') return matchesSearch;
if (studentFilter === 'male') return matchesSearch && s.sex === 'Male';
if (studentFilter === 'female') return matchesSearch && s.sex === 'Female';
return matchesSearch && s.grade.toLowerCase().includes(studentFilter.toLowerCase());
});
}
function setStudentFilter(filterVal, element) {
studentFilter = filterVal;
document.querySelectorAll('.filter-chips .chip').forEach(c => c.classList.remove('active'));
if (element) element.classList.add('active');
renderStudentsTable();
renderMobileStudentsList();
}
function onSearchInput(query) {
searchQuery = query;
renderStudentsTable();
renderMobileStudentsList();
}
// ── Documents Screen ───────────────────────────────────────────
function renderDocsList() {
const winContainer = document.getElementById('docs-grid-windows');
const phoneContainer = document.getElementById('docs-list-phone');
if (winContainer) {
winContainer.innerHTML = MOCK_DOCS.map(doc => `
<div class="content-card" style="display: flex; justify-content: space-between; align-items: center;">
<div>
<div style="font-weight: 700; font-size: 14px; margin-bottom: 2px;">${doc.name}</div>
<div style="font-size: 12px; color: var(--win-text-muted);">${doc.code} &bull; ${doc.count} Verified Records</div>
</div>
<div style="display: flex; align-items: center; gap: 12px;">
<span class="status-badge badge-complete">${doc.status}</span>
<button class="btn-secondary" style="height: 32px; padding: 0 12px;" onclick="openDocPreviewModal('${doc.name}', '${doc.code}')">Preview Scan</button>
</div>
</div>
`).join('');
}
if (phoneContainer) {
phoneContainer.innerHTML = MOCK_DOCS.map(doc => `
<div class="mobile-student-card" onclick="openDocPreviewModal('${doc.name}', '${doc.code}')">
<div class="m-student-header">
<span class="m-student-name" style="font-size: 13px;">${doc.name}</span>
<span class="status-badge badge-complete">${doc.status}</span>
</div>
<div class="m-student-footer" style="margin-top: 6px;">
<span>${doc.count} submissions</span>
<span style="color: var(--primary-green); font-weight: 600;">View &rsaquo;</span>
</div>
</div>
`).join('');
}
}
// ── Academic Screen ────────────────────────────────────────────
function renderClassesList() {
const winContainer = document.getElementById('classes-grid-windows');
const phoneContainer = document.getElementById('classes-list-phone');
const html = MOCK_CLASSES.map(cls => `
<div class="content-card">
<div class="card-header" style="margin-bottom: 8px;">
<span style="font-size: 12px; font-weight: 700; color: var(--primary-green); text-transform: uppercase;">${cls.grade}</span>
<span style="font-size: 11px; font-weight: 600; color: var(--win-text-muted);">${cls.students}/${cls.max} Students</span>
</div>
<div style="font-size: 16px; font-weight: 700; color: var(--win-text); margin-bottom: 4px;">Section ${cls.section}</div>
<div style="font-size: 12px; color: var(--win-text-muted); margin-bottom: 12px;">Adviser: ${cls.adviser}</div>
<div class="bar-track" style="height: 6px;">
<div class="bar-fill" style="width: ${(cls.students / cls.max) * 100}%;"></div>
</div>
</div>
bar.innerHTML = SCREENS.map(s => `
<button class="screen-pill ${s.id === currentScreen ? 'active' : ''}" data-screen="${s.id}" onclick="setScreen('${s.id}')">
<span>${s.icon}</span>
<span>${s.name}</span>
</button>
`).join('');
if (winContainer) winContainer.innerHTML = html;
if (phoneContainer) phoneContainer.innerHTML = html;
}
// ── Student Detail Modal ───────────────────────────────────────
function openStudentModal(id) {
const student = MOCK_STUDENTS.find(s => s.id === id);
if (!student) return;
const modal = document.getElementById('student-modal');
const body = document.getElementById('student-modal-body');
body.innerHTML = `
<div style="display: flex; align-items: center; gap: 14px; padding-bottom: 12px; border-bottom: 1px solid var(--win-border);">
<div style="width: 52px; height: 52px; border-radius: 50%; background: var(--primary-green); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: 700;">
${student.name.charAt(0)}
</div>
<div>
<h4 style="font-size: 16px; font-weight: 700;">${student.name}</h4>
<span style="font-size: 12px; color: var(--win-text-muted);">LRN: ${student.lrn} &bull; ${student.grade} - ${student.section}</span>
</div>
</div>
<div class="info-row"><span class="info-label">Gender:</span><span class="info-val">${student.sex}</span></div>
<div class="info-row"><span class="info-label">Age:</span><span class="info-val">${student.age} years old</span></div>
<div class="info-row"><span class="info-label">Enrollment Status:</span><span class="info-val"><span class="status-badge badge-enrolled">${student.status}</span></span></div>
<div class="info-row"><span class="info-label">Parent / Guardian Contact:</span><span class="info-val">${student.contact}</span></div>
<div class="info-row"><span class="info-label">School:</span><span class="info-val">Talipan National High School</span></div>
<div style="margin-top: 10px;">
<h5 style="font-size: 13px; font-weight: 700; margin-bottom: 8px;">Submitted Document Requirements</h5>
<div style="display: flex; flex-direction: column; gap: 6px;">
<div style="display: flex; justify-content: space-between; font-size: 12px; padding: 6px 10px; background: var(--win-surface-subtle); border-radius: 6px;">
<span>PSA Birth Certificate</span>
<span style="color: var(--primary-green); font-weight: 600;">✓ Verified</span>
</div>
<div style="display: flex; justify-content: space-between; font-size: 12px; padding: 6px 10px; background: var(--win-surface-subtle); border-radius: 6px;">
<span>Form 137 / SF10</span>
<span style="color: var(--primary-green); font-weight: 600;">✓ Verified</span>
</div>
<div style="display: flex; justify-content: space-between; font-size: 12px; padding: 6px 10px; background: var(--win-surface-subtle); border-radius: 6px;">
<span>Form 138 / SF9</span>
<span style="color: var(--primary-green); font-weight: 600;">✓ Verified</span>
</div>
</div>
</div>
`;
modal.classList.add('active');
function setScreen(screenId) {
currentScreen = screenId;
updateView();
}
function openDocPreviewModal(name, code) {
const modal = document.getElementById('doc-preview-modal');
const title = document.getElementById('doc-preview-title');
const codeEl = document.getElementById('doc-preview-code');
function updateView() {
// Update screen pills
document.querySelectorAll('.screen-pill').forEach(pill => {
pill.classList.toggle('active', pill.getAttribute('data-screen') === currentScreen);
});
if (title) title.textContent = name;
if (codeEl) codeEl.textContent = code;
// Windows Desktop Image
const winImg = document.getElementById('win-screen-img');
if (winImg) {
winImg.style.opacity = '0';
setTimeout(() => {
winImg.src = `screenshots/windows/${currentScreen}.webp`;
winImg.style.opacity = '1';
}, 120);
}
modal.classList.add('active');
// Android Mobile Image
const phoneImg = document.getElementById('phone-screen-img');
if (phoneImg) {
phoneImg.style.opacity = '0';
setTimeout(() => {
phoneImg.src = `screenshots/android/${currentScreen}.webp`;
phoneImg.style.opacity = '1';
}, 120);
}
// Update Dynamic Hotspots
updateHotspots();
}
// ── Dynamic Hotspots ──────────────────────────────────────────
function updateHotspots() {
const addStudentHotspot = document.getElementById('hotspot-add-student');
const settingsUpdateHotspot = document.getElementById('hotspot-settings-update');
if (addStudentHotspot) {
addStudentHotspot.style.display = currentScreen === 'students' ? 'block' : 'none';
}
if (settingsUpdateHotspot) {
settingsUpdateHotspot.style.display = currentScreen === 'settings' ? 'block' : 'none';
}
}
// ── Keyboard Shortcuts (1-8 and Left/Right Arrows) ────────────
function setupKeyboardNavigation() {
document.addEventListener('keydown', (e) => {
// 1-8 keys
const num = parseInt(e.key);
if (!isNaN(num) && num >= 1 && num <= SCREENS.length) {
setScreen(SCREENS[num - 1].id);
return;
}
// Arrow keys
const currentIndex = SCREENS.findIndex(s => s.id === currentScreen);
if (e.key === 'ArrowRight') {
const nextIndex = (currentIndex + 1) % SCREENS.length;
setScreen(SCREENS[nextIndex].id);
} else if (e.key === 'ArrowLeft') {
const prevIndex = (currentIndex - 1 + SCREENS.length) % SCREENS.length;
setScreen(SCREENS[prevIndex].id);
}
});
}
// ── Interactive Modals ─────────────────────────────────────────
function openAddStudentModal() {
const modal = document.getElementById('add-student-modal');
modal.classList.add('active');
if (modal) modal.classList.add('active');
}
function openUpdateCheckModal() {
const modal = document.getElementById('update-modal');
if (modal) {
modal.classList.add('active');
simulateUpdateProcess();
}
}
function closeModal(id) {
@@ -373,76 +151,57 @@ function closeModal(id) {
if (modal) modal.classList.remove('active');
}
// ── Settings Collapsible Sections ──────────────────────────────
function toggleSettingsSection(id) {
const body = document.getElementById(`settings-body-${id}`);
const arrow = document.getElementById(`settings-arrow-${id}`);
if (!body) return;
const isVisible = body.style.display !== 'none';
body.style.display = isVisible ? 'none' : 'flex';
if (arrow) {
arrow.style.transform = isVisible ? 'rotate(0deg)' : 'rotate(180deg)';
}
}
// ── Check For Updates Simulation ───────────────────────────────
function simulateUpdateCheck() {
const btn = document.getElementById('btn-check-update');
const btnText = document.getElementById('btn-check-update-text');
const statusBanner = document.getElementById('update-status-banner');
// ── Simulated Update Check Workflow ────────────────────────────
function simulateUpdateProcess() {
const statusEl = document.getElementById('update-modal-status');
const actionBtn = document.getElementById('btn-download-action');
const toast = document.getElementById('browser-download-toast');
const toastText = document.getElementById('toast-filename');
const toastFile = document.getElementById('toast-filename');
if (!btn) return;
const isWin = currentDevice === 'windows';
const arch = isWin ? 'x64 (64-bit)' : 'ARM64 (64-bit)';
const file = isWin ? 'TIS_RMS_Setup_v1.0.24.exe' : 'TIS_RMS_64_v1.0.24.apk';
btn.disabled = true;
btnText.textContent = 'Checking GitHub releases...';
statusBanner.style.display = 'none';
statusEl.innerHTML = `
<div style="display: flex; align-items: center; gap: 10px; color: var(--accent-emerald);">
<div style="width: 16px; height: 16px; border: 2px solid var(--accent-emerald); border-top-color: transparent; border-radius: 50%; animation: spin 0.8s linear infinite;"></div>
<span>Querying GitHub releases for ${arch}...</span>
</div>
`;
actionBtn.style.display = 'none';
setTimeout(() => {
btn.disabled = false;
btnText.textContent = 'Check for Updates';
// Architecture-matched file simulation
const isWin = currentDevice === 'windows';
const filename = isWin ? 'TIS_RMS_Setup_v1.0.24.exe' : 'TIS_RMS_64_v1.0.24.apk';
const archLabel = isWin ? 'x64 (64-bit)' : 'ARM64 (64-bit)';
statusBanner.style.display = 'block';
statusBanner.innerHTML = `
<div style="display: flex; align-items: center; gap: 8px; font-weight: 600; color: var(--primary-green); margin-bottom: 4px;">
<svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>
New Version Detected: v1.0.24 for ${archLabel}
</div>
<div style="font-size: 12px; color: var(--win-text);">
Architecture matched: <strong>${filename}</strong>.<br/>
Simulating launching download in device's default browser...
statusEl.innerHTML = `
<div style="background: rgba(25, 135, 84, 0.15); border: 1px solid rgba(25, 135, 84, 0.35); padding: 12px; border-radius: 8px;">
<div style="font-weight: 700; color: var(--accent-emerald); margin-bottom: 4px;">
✓ Update Detected: v1.0.24
</div>
<div style="font-size: 12px; color: #cbd5e1; line-height: 1.5;">
Architecture: <strong>${arch}</strong><br/>
Matched Asset: <strong>${file}</strong><br/>
Opening direct link in default device browser...
</div>
</div>
`;
// Show simulated default browser toast
if (toast && toastText) {
toastText.textContent = filename;
toast.classList.add('active');
setTimeout(() => {
toast.classList.remove('active');
}, 5000);
}
}, 1200);
actionBtn.style.display = 'inline-flex';
actionBtn.onclick = () => {
closeModal('update-modal');
triggerDownloadToast(file);
};
triggerDownloadToast(file);
}, 1400);
}
// ── Clock for Android Status Bar ───────────────────────────────
function startClock() {
function updateTime() {
const el = document.getElementById('phone-time');
if (!el) return;
const now = new Date();
let hours = now.getHours();
let mins = now.getMinutes();
mins = mins < 10 ? '0' + mins : mins;
el.textContent = `${hours}:${mins}`;
function triggerDownloadToast(filename) {
const toast = document.getElementById('browser-download-toast');
const toastFile = document.getElementById('toast-filename');
if (toast && toastFile) {
toastFile.textContent = filename;
toast.classList.add('active');
setTimeout(() => {
toast.classList.remove('active');
}, 5000);
}
updateTime();
setInterval(updateTime, 30000);
}
+88 -547
View File
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" data-theme="light">
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -15,583 +15,95 @@
<header class="top-control-bar">
<div class="brand-badge">
<img src="assets/logo.png" alt="TIS Logo">
<span>TIS-RMS Demo</span>
<span>TIS-RMS Showcase</span>
</div>
<!-- Viewport Switcher -->
<!-- Device Switcher -->
<div class="device-switcher" role="tablist">
<button id="btn-view-windows" class="device-btn active" title="Switch to Windows Desktop layout">
<button id="btn-view-windows" class="device-btn active" title="Switch to Windows Desktop app view">
<svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor">
<path d="M0 3.449L9.75 2.1v9.451H0m10.949-9.602L24 0v11.4H10.949M0 12.6h9.75v9.451L0 20.699M10.949 12.6H24V24l-12.9-1.801"/>
</svg>
<span>Windows Desktop</span>
</button>
<button id="btn-view-android" class="device-btn" title="Switch to Android Mobile layout">
<button id="btn-view-android" class="device-btn" title="Switch to Android Mobile app view">
<svg width="15" height="15" viewBox="0 0 24 24" fill="currentColor">
<path d="M17.523 15.3414c-.5511 0-.9993-.4486-.9993-.9997s.4482-.9993.9993-.9993c.551 0 .9993.4482.9993.9993.0001.5511-.4483.9997-.9993.9997m-11.046 0c-.5511 0-.9993-.4486-.9993-.9997s.4482-.9993.9993-.9993c.5511 0 .9993.4482.9993.9993 0 .5511-.4482.9997-.9993.9997m11.4045-6.02l1.9973-3.4592a.416.416 0 00-.1521-.5676.416.416 0 00-.5676.1521l-2.0223 3.503C15.5902 8.411 13.8533 8.081 12 8.081s-3.5902.33-5.1367.8687L4.841 5.4467a.4161.4161 0 00-.5677-.1521.4157.4157 0 00-.1521.5676l1.9973 3.4592C2.6889 11.1867.3432 14.6589 0 18.761h24c-.3432-4.1021-2.6889-7.5743-6.1185-9.4396"/>
</svg>
<span>Android Mobile</span>
</button>
</div>
<!-- Theme Switcher -->
<button id="theme-toggle-btn" class="theme-toggle-btn" title="Toggle Light/Dark Theme">
<svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
</svg>
</button>
</header>
<!-- ── Main Viewport Area ────────────────────────────────────── -->
<!-- ── Screen Selector Pill Bar ───────────────────────────────── -->
<nav id="screen-selector-bar" class="screen-selector-bar">
<!-- Injected via app.js -->
</nav>
<!-- ── Viewport Area ─────────────────────────────────────────── -->
<main class="viewport-container">
<!-- ==============================================================
1. WINDOWS DESKTOP VIEW
============================================================== -->
<div id="desktop-frame" class="desktop-frame">
<!-- 1. WINDOWS DESKTOP WINDOW FRAME -->
<div id="desktop-window" class="desktop-window">
<!-- Titlebar -->
<div class="win-titlebar">
<div class="win-title">
<div class="win-titlebar-left">
<img src="assets/logo.png" alt="Logo">
<span>TIS Record Management System - Talipan National High School</span>
<span>TIS Record Management System</span>
</div>
<div class="win-controls">
<div class="win-window-controls">
<span>&#x2014;</span>
<span>&#x25A2;</span>
<span class="close">&#x2715;</span>
<span style="cursor: pointer;">&#x2715;</span>
</div>
</div>
<div class="win-body">
<!-- Sidebar Navigation -->
<aside class="win-sidebar">
<div class="win-app-brand">
<img src="assets/logo.png" alt="Logo">
<div class="win-brand-text">
<h3>TIS-RMS</h3>
<span>Tiaong, Quezon</span>
</div>
</div>
<!-- Stage with actual screenshot and clickable interactive hotspots -->
<div class="win-stage">
<img id="win-screen-img" class="win-screen-img" src="screenshots/windows/dashboard.webp" alt="Windows Screen">
<ul class="win-nav-list">
<li class="win-nav-item active" data-screen="dashboard">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7"></rect><rect x="14" y="3" width="7" height="7"></rect><rect x="14" y="14" width="7" height="7"></rect><rect x="3" y="14" width="7" height="7"></rect></svg>
<span>Dashboard</span>
</li>
<li class="win-nav-item" data-screen="students">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>
<span>Students</span>
<span class="badge">1,482</span>
</li>
<li class="win-nav-item" data-screen="documents">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg>
<span>Documents</span>
</li>
<li class="win-nav-item" data-screen="academic">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M22 10v6M2 10l10-5 10 5-10 5z"></path><path d="M6 12v5c0 2 2 3 6 3s6-1 6-3v-5"></path></svg>
<span>Academic</span>
</li>
<li class="win-nav-item" data-screen="settings">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
<span>Settings</span>
</li>
</ul>
<!-- Interactive Sidebar Hotspots (Clicking sidebar directly on screenshot navigates!) -->
<div class="win-sidebar-hotspots">
<div class="hotspot-sidebar-item hotspot-item-dashboard" title="Go to Dashboard" onclick="setScreen('dashboard')"></div>
<div class="hotspot-sidebar-item hotspot-item-students" title="Go to Students Directory" onclick="setScreen('students')"></div>
<div class="hotspot-sidebar-item hotspot-item-documents" title="Go to Documents" onclick="setScreen('documents')"></div>
<div class="hotspot-sidebar-item hotspot-item-archives" title="Go to Archives" onclick="setScreen('archives')"></div>
<div class="hotspot-sidebar-item hotspot-item-reports" title="Go to Reports" onclick="setScreen('reports')"></div>
<div class="hotspot-sidebar-item hotspot-item-users" title="Go to Users Management" onclick="setScreen('users')"></div>
<div class="hotspot-sidebar-item hotspot-item-history" title="Go to Audit History" onclick="setScreen('history')"></div>
<div class="hotspot-sidebar-item hotspot-item-settings" title="Go to Settings" onclick="setScreen('settings')"></div>
</div>
<div class="win-user-profile">
<div class="avatar">AD</div>
<div class="win-user-info">
<h4>Admin User</h4>
<span>System Registrar</span>
</div>
</div>
</aside>
<!-- Hotspot: Add Student on Students Screen -->
<div id="hotspot-add-student" class="hotspot-add-student" title="Click to simulate Add Student modal" onclick="openAddStudentModal()" style="display: none;"></div>
<!-- Main Content -->
<section class="win-content">
<!-- Top Bar -->
<div class="win-topbar">
<div class="win-breadcrumb">
<span id="win-breadcrumb-title">Dashboard Overview</span>
</div>
<div class="win-topbar-actions">
<div class="win-search-box">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
<input type="text" placeholder="Search records (Ctrl+F)..." oninput="onSearchInput(this.value)">
</div>
<button class="btn-primary" onclick="openAddStudentModal()">
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
<span>Add Student</span>
</button>
<!-- Note: Bulk Import button is cleanly hidden on Windows app as requested! -->
</div>
</div>
<!-- Scrollable Body Views -->
<div class="win-scroll-area">
<!-- 1. Dashboard View -->
<div id="win-dashboard" class="win-screen-view">
<div class="stats-grid">
<div class="stat-card">
<div class="stat-icon green">&#x1F465;</div>
<div class="stat-info">
<h5>Total Students</h5>
<h2>1,482</h2>
</div>
</div>
<div class="stat-card">
<div class="stat-icon blue">&#x2714;</div>
<div class="stat-info">
<h5>Enrolled</h5>
<h2>1,420</h2>
</div>
</div>
<div class="stat-card">
<div class="stat-icon amber">&#x21C4;</div>
<div class="stat-info">
<h5>Transferred</h5>
<h2>38</h2>
</div>
</div>
<div class="stat-card">
<div class="stat-icon rose">&#x2298;</div>
<div class="stat-info">
<h5>Dropped Out</h5>
<h2>24</h2>
</div>
</div>
</div>
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 20px; margin-top: 24px;">
<div class="content-card">
<div class="card-header">
<span class="card-title">Grade Level Distribution</span>
<span style="font-size: 12px; color: var(--win-text-muted);">S.Y. 2026-2027</span>
</div>
<div class="chart-container">
<div class="bar-row">
<span class="bar-label">Grade 7</span>
<div class="bar-track"><div class="bar-fill" style="width: 88%;"></div></div>
<span class="bar-val">280</span>
</div>
<div class="bar-row">
<span class="bar-label">Grade 8</span>
<div class="bar-track"><div class="bar-fill" style="width: 82%;"></div></div>
<span class="bar-val">260</span>
</div>
<div class="bar-row">
<span class="bar-label">Grade 9</span>
<div class="bar-track"><div class="bar-fill" style="width: 79%;"></div></div>
<span class="bar-val">250</span>
</div>
<div class="bar-row">
<span class="bar-label">Grade 10</span>
<div class="bar-track"><div class="bar-fill" style="width: 75%;"></div></div>
<span class="bar-val">240</span>
</div>
<div class="bar-row">
<span class="bar-label">Grade 11</span>
<div class="bar-track"><div class="bar-fill" style="width: 72%;"></div></div>
<span class="bar-val">230</span>
</div>
<div class="bar-row">
<span class="bar-label">Grade 12</span>
<div class="bar-track"><div class="bar-fill" style="width: 68%;"></div></div>
<span class="bar-val">222</span>
</div>
</div>
</div>
<div class="content-card">
<div class="card-header">
<span class="card-title">Recent Activity</span>
</div>
<div style="display: flex; flex-direction: column; gap: 14px; font-size: 13px;">
<div style="border-left: 3px solid var(--primary-green); padding-left: 10px;">
<div style="font-weight: 600;">Student Enrolled</div>
<div style="font-size: 11px; color: var(--win-text-muted);">Juan Dela Cruz &bull; Grade 10</div>
</div>
<div style="border-left: 3px solid var(--accent-cyan); padding-left: 10px;">
<div style="font-weight: 600;">SF10 Verified</div>
<div style="font-size: 11px; color: var(--win-text-muted);">Maria Clara Perez &bull; Grade 9</div>
</div>
<div style="border-left: 3px solid var(--accent-amber); padding-left: 10px;">
<div style="font-weight: 600;">Section Capacity Alert</div>
<div style="font-size: 11px; color: var(--win-text-muted);">Grade 10 - Jacinto at 49/50</div>
</div>
</div>
</div>
</div>
</div>
<!-- 2. Students View -->
<div id="win-students" class="win-screen-view" style="display: none;">
<div class="filter-chips">
<button class="chip active" onclick="setStudentFilter('all', this)">All Students (1,482)</button>
<button class="chip" onclick="setStudentFilter('Grade 7', this)">Grade 7</button>
<button class="chip" onclick="setStudentFilter('Grade 8', this)">Grade 8</button>
<button class="chip" onclick="setStudentFilter('Grade 9', this)">Grade 9</button>
<button class="chip" onclick="setStudentFilter('Grade 10', this)">Grade 10</button>
<button class="chip" onclick="setStudentFilter('Grade 11', this)">Grade 11</button>
<button class="chip" onclick="setStudentFilter('Grade 12', this)">Grade 12</button>
<button class="chip" onclick="setStudentFilter('male', this)">Male</button>
<button class="chip" onclick="setStudentFilter('female', this)">Female</button>
</div>
<div class="content-card" style="padding: 0; overflow: hidden;">
<div class="table-responsive">
<table class="tis-table">
<thead>
<tr>
<th>Student Name</th>
<th>LRN</th>
<th>Grade</th>
<th>Section</th>
<th>Sex</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="students-table-body">
<!-- Rendered via app.js -->
</tbody>
</table>
</div>
</div>
</div>
<!-- 3. Documents View -->
<div id="win-documents" class="win-screen-view" style="display: none;">
<div class="content-card" style="margin-bottom: 20px;">
<h3 style="font-size: 15px; margin-bottom: 6px;">Document Verification Health</h3>
<p style="font-size: 13px; color: var(--win-text-muted); margin-bottom: 14px;">Compliance progress for Learner Permanent Records (DepEd Form 137 / SF10).</p>
<div class="bar-track" style="height: 14px;">
<div class="bar-fill" style="width: 92%;"></div>
</div>
<div style="display: flex; justify-content: space-between; font-size: 12px; margin-top: 8px; color: var(--win-text-muted);">
<span>92% Verified (1,363 / 1,482 Students)</span>
<span>119 Pending Verification</span>
</div>
</div>
<div id="docs-grid-windows" style="display: flex; flex-direction: column; gap: 12px;">
<!-- Rendered via app.js -->
</div>
</div>
<!-- 4. Academic View -->
<div id="win-academic" class="win-screen-view" style="display: none;">
<div class="content-card" style="margin-bottom: 20px; background: linear-gradient(135deg, rgba(25, 135, 84, 0.12), rgba(6, 182, 212, 0.08)); border-color: rgba(25, 135, 84, 0.3);">
<div style="display: flex; justify-content: space-between; align-items: center;">
<div>
<h3 style="font-size: 18px; font-weight: 800; color: var(--primary-green);">Academic Year 2026-2027</h3>
<p style="font-size: 13px; color: var(--win-text-muted); margin-top: 2px;">Active Academic Period &bull; DepEd Region IV-A CALABARZON</p>
</div>
<span class="status-badge badge-enrolled" style="font-size: 12px; padding: 6px 12px;">Active Term</span>
</div>
</div>
<div id="classes-grid-windows" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px;">
<!-- Rendered via app.js -->
</div>
</div>
<!-- 5. Settings View -->
<div id="win-settings" class="win-screen-view" style="display: none;">
<!-- Collapsible Card: About & App Updates (Exact feature implemented) -->
<div class="settings-section">
<div class="settings-header" onclick="toggleSettingsSection('about')">
<div style="display: flex; align-items: center; gap: 12px;">
<span style="color: var(--primary-green);">&#x2139;</span>
<span>About &amp; App Updates</span>
</div>
<span id="settings-arrow-about" style="transition: transform 0.2s;">&#x25BC;</span>
</div>
<div id="settings-body-about" class="settings-body">
<div class="info-row"><span class="info-label">Application:</span><span class="info-val">Talipan Integrated School - RMS</span></div>
<div class="info-row"><span class="info-label">Current Version:</span><span class="info-val">v1.0.23 (Build 24)</span></div>
<div class="info-row"><span class="info-label">Platform:</span><span class="info-val">Windows x64 Desktop</span></div>
<div class="info-row"><span class="info-label">Architecture:</span><span class="info-val">x64 (64-bit)</span></div>
<div class="info-row"><span class="info-label">Institution:</span><span class="info-val">Talipan National High School</span></div>
<div class="info-row"><span class="info-label">Developed By:</span><span class="info-val">Dalubhasaan ng Lungsod ng San Pablo (DLSP)</span></div>
<hr style="border: none; border-top: 1px solid var(--win-border); margin: 6px 0;">
<!-- Software Updates Section -->
<div>
<h4 style="font-size: 14px; font-weight: 700; margin-bottom: 4px;">Software Updates</h4>
<p style="font-size: 12px; color: var(--win-text-muted); margin-bottom: 12px;">Checks latest GitHub release and matches machine architecture automatically.</p>
<div id="update-status-banner" style="display: none; padding: 12px; background: rgba(25, 135, 84, 0.1); border: 1px solid rgba(25, 135, 84, 0.3); border-radius: 8px; margin-bottom: 12px;"></div>
<button id="btn-check-update" class="btn-primary" onclick="simulateUpdateCheck()">
<svg width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M21.5 2v6h-6M21.34 15.57a10 10 0 1 1-.57-8.38l5.67-5.67"/></svg>
<span id="btn-check-update-text">Check for Updates</span>
</button>
</div>
</div>
</div>
<!-- Collapsible Card: Appearance -->
<div class="settings-section">
<div class="settings-header" onclick="toggleSettingsSection('appearance')">
<div style="display: flex; align-items: center; gap: 12px;">
<span style="color: var(--primary-green);">&#x1F3A8;</span>
<span>Appearance &amp; Sound</span>
</div>
<span id="settings-arrow-appearance" style="transition: transform 0.2s;">&#x25BC;</span>
</div>
<div id="settings-body-appearance" class="settings-body">
<div class="info-row"><span class="info-label">Interface Theme:</span><span class="info-val">Light / Dark Adaptive</span></div>
<div class="info-row"><span class="info-label">Audio Feedback:</span><span class="info-val">Enabled (Chime on success)</span></div>
<div class="info-row"><span class="info-label">Haptics:</span><span class="info-val">Enabled (Mobile vibrator)</span></div>
</div>
</div>
<!-- Collapsible Card: Security -->
<div class="settings-section">
<div class="settings-header" onclick="toggleSettingsSection('security')">
<div style="display: flex; align-items: center; gap: 12px;">
<span style="color: var(--primary-green);">&#x1F512;</span>
<span>Security &amp; Account</span>
</div>
<span id="settings-arrow-security" style="transition: transform 0.2s;">&#x25BC;</span>
</div>
<div id="settings-body-security" class="settings-body">
<div class="info-row"><span class="info-label">User Role:</span><span class="info-val">Admin / Registrar</span></div>
<div class="info-row"><span class="info-label">Active Session:</span><span class="info-val">Local Workstation (Active)</span></div>
</div>
</div>
</div>
</div>
</section>
<!-- Hotspot: Check Updates on Settings Screen -->
<div id="hotspot-settings-update" class="hotspot-settings-update" title="Click to test Check for Updates" onclick="openUpdateCheckModal()" style="display: none;"></div>
</div>
</div>
<!-- 2. ANDROID SMARTPHONE FRAME -->
<div id="phone-mockup" class="phone-mockup" style="display: none;">
<div class="phone-screen-container">
<img id="phone-screen-img" class="phone-screen-img" src="screenshots/android/dashboard.webp" alt="Android Screen">
<!-- ==============================================================
2. ANDROID MOBILE VIEW (Smartphone Frame Mockup)
============================================================== -->
<div id="phone-frame" class="phone-frame" style="display: none;">
<!-- Dynamic Island / Speaker Notch -->
<div class="phone-island"></div>
<!-- Android Status Bar -->
<div class="phone-status-bar">
<span id="phone-time">12:30</span>
<div style="display: flex; align-items: center; gap: 6px;">
<span>5G</span>
<span>&#x1F4F6;</span>
<span>&#x1F50B;</span>
<!-- Hotspots for quick testing -->
<div style="position: absolute; top: 12%; right: 5%; width: 50px; height: 50px; cursor: pointer;" title="Interactive Action" onclick="openAddStudentModal()"></div>
<div style="position: absolute; bottom: 2%; left: 0; right: 0; height: 60px; display: flex;">
<div style="flex: 1; cursor: pointer;" title="Dashboard" onclick="setScreen('dashboard')"></div>
<div style="flex: 1; cursor: pointer;" title="Students" onclick="setScreen('students')"></div>
<div style="flex: 1; cursor: pointer;" title="Documents" onclick="setScreen('documents')"></div>
<div style="flex: 1; cursor: pointer;" title="Settings" onclick="setScreen('settings')"></div>
</div>
</div>
<!-- Mobile Top App Header -->
<div class="phone-app-header">
<h3 id="phone-header-title">Dashboard Overview</h3>
<div style="display: flex; align-items: center; gap: 10px;">
<span style="font-size: 18px; cursor: pointer;" onclick="openAddStudentModal()">&#x2795;</span>
</div>
</div>
<!-- Phone Content Body -->
<div class="phone-content">
<!-- Mobile: Dashboard -->
<div id="phone-dashboard" class="phone-screen-view">
<div class="stats-grid">
<div class="stat-card">
<div class="stat-icon green">&#x1F465;</div>
<div class="stat-info">
<h5>Students</h5>
<h2>1,482</h2>
</div>
</div>
<div class="stat-card">
<div class="stat-icon blue">&#x2714;</div>
<div class="stat-info">
<h5>Enrolled</h5>
<h2>1,420</h2>
</div>
</div>
<div class="stat-card">
<div class="stat-icon amber">&#x21C4;</div>
<div class="stat-info">
<h5>Transferred</h5>
<h2>38</h2>
</div>
</div>
<div class="stat-card">
<div class="stat-icon rose">&#x2298;</div>
<div class="stat-info">
<h5>Dropped</h5>
<h2>24</h2>
</div>
</div>
</div>
<div class="content-card" style="margin-top: 14px;">
<div class="card-header">
<span class="card-title">Enrollment per Grade</span>
</div>
<div class="chart-container">
<div class="bar-row">
<span class="bar-label">G7</span>
<div class="bar-track"><div class="bar-fill" style="width: 88%;"></div></div>
<span class="bar-val">280</span>
</div>
<div class="bar-row">
<span class="bar-label">G8</span>
<div class="bar-track"><div class="bar-fill" style="width: 82%;"></div></div>
<span class="bar-val">260</span>
</div>
<div class="bar-row">
<span class="bar-label">G9</span>
<div class="bar-track"><div class="bar-fill" style="width: 79%;"></div></div>
<span class="bar-val">250</span>
</div>
<div class="bar-row">
<span class="bar-label">G10</span>
<div class="bar-track"><div class="bar-fill" style="width: 75%;"></div></div>
<span class="bar-val">240</span>
</div>
<div class="bar-row">
<span class="bar-label">SHS</span>
<div class="bar-track"><div class="bar-fill" style="width: 70%;"></div></div>
<span class="bar-val">452</span>
</div>
</div>
</div>
</div>
<!-- Mobile: Students -->
<div id="phone-students" class="phone-screen-view" style="display: none;">
<div style="position: relative; margin-bottom: 10px;">
<input type="text" placeholder="Search student name / LRN..." oninput="onSearchInput(this.value)" style="width: 100%; height: 38px; border-radius: 8px; border: 1px solid var(--win-border); background: var(--win-surface); color: var(--win-text); padding: 0 12px; font-size: 13px;">
</div>
<div class="filter-chips">
<button class="chip active" onclick="setStudentFilter('all', this)">All</button>
<button class="chip" onclick="setStudentFilter('Grade 7', this)">G7</button>
<button class="chip" onclick="setStudentFilter('Grade 8', this)">G8</button>
<button class="chip" onclick="setStudentFilter('Grade 9', this)">G9</button>
<button class="chip" onclick="setStudentFilter('Grade 10', this)">G10</button>
<button class="chip" onclick="setStudentFilter('Grade 11', this)">G11</button>
<button class="chip" onclick="setStudentFilter('Grade 12', this)">G12</button>
</div>
<div id="mobile-students-container" class="mobile-student-list">
<!-- Rendered via app.js -->
</div>
</div>
<!-- Mobile: Documents -->
<div id="phone-documents" class="phone-screen-view" style="display: none;">
<div id="docs-list-phone" style="display: flex; flex-direction: column; gap: 10px;">
<!-- Rendered via app.js -->
</div>
</div>
<!-- Mobile: Academic -->
<div id="phone-academic" class="phone-screen-view" style="display: none;">
<div id="classes-list-phone" style="display: flex; flex-direction: column; gap: 10px;">
<!-- Rendered via app.js -->
</div>
</div>
<!-- Mobile: Settings -->
<div id="phone-settings" class="phone-screen-view" style="display: none;">
<div class="settings-section">
<div class="settings-header">
<span>About &amp; App Updates</span>
</div>
<div class="settings-body" style="display: flex;">
<div class="info-row"><span class="info-label">App:</span><span class="info-val">TIS-RMS Mobile</span></div>
<div class="info-row"><span class="info-label">Version:</span><span class="info-val">v1.0.23 (Build 24)</span></div>
<div class="info-row"><span class="info-label">Platform:</span><span class="info-val">Android</span></div>
<div class="info-row"><span class="info-label">Architecture:</span><span class="info-val">ARM64 (64-bit)</span></div>
<div class="info-row"><span class="info-label">Institution:</span><span class="info-val">Talipan NHS</span></div>
<div class="info-row"><span class="info-label">Developed By:</span><span class="info-val">DLSP</span></div>
<button class="btn-primary" style="margin-top: 8px;" onclick="simulateUpdateCheck()">
<span>Check for Updates</span>
</button>
</div>
</div>
</div>
</div>
<!-- Android Bottom Nav Bar -->
<nav class="phone-bottom-nav">
<div class="bottom-nav-item active" data-screen="dashboard">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7"></rect><rect x="14" y="3" width="7" height="7"></rect><rect x="14" y="14" width="7" height="7"></rect><rect x="3" y="14" width="7" height="7"></rect></svg>
<span>Home</span>
</div>
<div class="bottom-nav-item" data-screen="students">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle></svg>
<span>Students</span>
</div>
<div class="bottom-nav-item" data-screen="documents">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline></svg>
<span>Docs</span>
</div>
<div class="bottom-nav-item" data-screen="academic">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M22 10v6M2 10l10-5 10 5-10 5z"></path></svg>
<span>Classes</span>
</div>
<div class="bottom-nav-item" data-screen="settings">
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
<span>Settings</span>
</div>
</nav>
</div>
</main>
<!-- ── Interactive Modals ────────────────────────────────────── -->
<!-- 1. Student Detail Modal -->
<div id="student-modal" class="modal-overlay" onclick="if(event.target===this)closeModal('student-modal')">
<div class="modal-dialog">
<div class="modal-header">
<h3>Student Information</h3>
<button class="modal-close" onclick="closeModal('student-modal')">&times;</button>
</div>
<div id="student-modal-body" class="modal-body">
<!-- Injected via app.js -->
</div>
<div style="padding: 14px 20px; border-top: 1px solid var(--win-border); display: flex; justify-content: flex-end; gap: 10px;">
<button class="btn-secondary" onclick="closeModal('student-modal')">Close</button>
<button class="btn-primary" onclick="closeModal('student-modal')">Print SF10</button>
</div>
</div>
</div>
<!-- 2. Document Preview Modal -->
<div id="doc-preview-modal" class="modal-overlay" onclick="if(event.target===this)closeModal('doc-preview-modal')">
<div class="modal-dialog">
<div class="modal-header">
<h3 id="doc-preview-title">Document Preview</h3>
<button class="modal-close" onclick="closeModal('doc-preview-modal')">&times;</button>
</div>
<div class="modal-body">
<div style="background: var(--win-surface-subtle); border: 2px dashed var(--win-border); border-radius: 12px; height: 260px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; color: var(--win-text-muted);">
<svg width="48" height="48" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line></svg>
<div style="font-weight: 600; color: var(--win-text);">Simulated Scanned Document</div>
<div id="doc-preview-code" style="font-size: 12px; font-family: monospace;">DOC-PSA</div>
<div style="font-size: 11px;">Resolution: 300 DPI &bull; OCR Confidence: 99.4%</div>
</div>
</div>
<div style="padding: 14px 20px; border-top: 1px solid var(--win-border); display: flex; justify-content: flex-end;">
<button class="btn-secondary" onclick="closeModal('doc-preview-modal')">Close Preview</button>
</div>
</div>
</div>
<!-- 3. Add Student Modal -->
<!-- 1. Add Student Modal -->
<div id="add-student-modal" class="modal-overlay" onclick="if(event.target===this)closeModal('add-student-modal')">
<div class="modal-dialog">
<div class="modal-header">
@@ -599,37 +111,66 @@
<button class="modal-close" onclick="closeModal('add-student-modal')">&times;</button>
</div>
<div class="modal-body">
<p style="font-size: 13px; color: var(--win-text-muted);">Select standard registration or quick entry form:</p>
<p style="font-size: 13px; color: var(--text-muted); line-height: 1.5;">
Select student registration method:
</p>
<div style="display: flex; flex-direction: column; gap: 10px;">
<div class="content-card" style="cursor: pointer;" onclick="alert('Demo Mode: In the real app, this launches the multi-step student registration form.'); closeModal('add-student-modal');">
<h4 style="font-size: 14px; font-weight: 700; margin-bottom: 2px;">Standard Form Entry</h4>
<p style="font-size: 12px; color: var(--win-text-muted);">Fill out complete student profile, guardian contacts, and DepEd SF1 fields.</p>
<div style="background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.1); border-radius: 10px; padding: 14px; cursor: pointer;" onclick="alert('Simulation: Launches the multi-step student enrollment form.'); closeModal('add-student-modal');">
<h4 style="font-size: 14px; font-weight: 700; color: #fff;">Standard Stepper Form</h4>
<p style="font-size: 12px; color: var(--text-muted); margin-top: 3px;">Full student biographical details, parent info, and LRN verification.</p>
</div>
<div class="content-card" style="cursor: pointer;" onclick="alert('Demo Mode: In the real app, this prompts OCR scanning of PSA / SF10 records.'); closeModal('add-student-modal');">
<h4 style="font-size: 14px; font-weight: 700; margin-bottom: 2px;">Document OCR Auto-Fill</h4>
<p style="font-size: 12px; color: var(--win-text-muted);">Scan student certificate and automatically parse LRN, names, and birthday.</p>
<div style="background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.1); border-radius: 10px; padding: 14px; cursor: pointer;" onclick="alert('Simulation: Launches OCR document scanning for automatic field extraction.'); closeModal('add-student-modal');">
<h4 style="font-size: 14px; font-weight: 700; color: #fff;">Scan Document OCR</h4>
<p style="font-size: 12px; color: var(--text-muted); margin-top: 3px;">Auto-extract student information directly from Birth Certificate or Form 137.</p>
</div>
</div>
</div>
<div style="padding: 14px 20px; border-top: 1px solid var(--win-border); display: flex; justify-content: flex-end;">
<div style="padding: 14px 20px; border-top: 1px solid rgba(255, 255, 255, 0.1); display: flex; justify-content: flex-end;">
<button class="btn-secondary" onclick="closeModal('add-student-modal')">Cancel</button>
</div>
</div>
</div>
<!-- 4. Simulated Browser Download Toast -->
<!-- 2. Software Update Check Modal -->
<div id="update-modal" class="modal-overlay" onclick="if(event.target===this)closeModal('update-modal')">
<div class="modal-dialog">
<div class="modal-header">
<h3>About &amp; App Updates</h3>
<button class="modal-close" onclick="closeModal('update-modal')">&times;</button>
</div>
<div class="modal-body">
<div id="update-modal-status">
<!-- Dynamically filled via app.js -->
</div>
</div>
<div style="padding: 14px 20px; border-top: 1px solid rgba(255, 255, 255, 0.1); display: flex; justify-content: flex-end; gap: 10px;">
<button class="btn-secondary" onclick="closeModal('update-modal')">Close</button>
<button id="btn-download-action" class="btn-primary" style="display: none;">
<span>Download in Browser</span>
</button>
</div>
</div>
</div>
<!-- 3. Simulated Browser Download Toast -->
<div id="browser-download-toast" class="browser-download-toast">
<div class="toast-icon">
<svg width="20" height="20" fill="none" stroke="#fff" stroke-width="2.5" viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>
</div>
<div>
<div style="font-size: 13px; font-weight: 700;">Browser Download Launched</div>
<div id="toast-filename" style="font-size: 11px; opacity: 0.85; font-family: monospace;">TIS_RMS_64_v1.0.24.apk</div>
<div style="font-size: 13px; font-weight: 700;">Opening in Default Browser</div>
<div id="toast-filename" style="font-size: 11px; opacity: 0.85; font-family: monospace;">TIS_RMS_Setup_v1.0.24.exe</div>
</div>
</div>
<style>
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
<script src="app.js"></script>
</body>
</html>
+237 -786
View File
File diff suppressed because it is too large. Load diff