rework the entire docs
This commit is contained in:
1 parent
a8473c23b7
commit
d126ecaef1
18 files changed
+6132
-1234
No files matched your search
+230
-103
@@ -1,43 +1,141 @@
|
||||
/**
|
||||
* TIS-RMS DOCUMENTATION INTERACTIVE CONTROLLER
|
||||
* Handles:
|
||||
* 1. Interactive Walkthrough Reel / Video Player
|
||||
* 2. Mockup Platform Tab Switching & Header Platform Filtering
|
||||
* 3. Live Client-Side Search with Highlighting
|
||||
* 4. Image Lightbox Zoom Modal
|
||||
* 5. Theme Toggle (Dark/Light) with LocalStorage
|
||||
* 6. Sidebar Scrollspy Navigation
|
||||
* 7. Print Handler & Global Keyboard Shortcuts
|
||||
* 1. Eye-Friendly Dark/Light Theme Switching with LocalStorage
|
||||
* 2. Dedicated Print Action
|
||||
* 3. Windows / Android Platform Filter with Persistent State
|
||||
* 4. Multi-Page Live Search with Keyboard Navigation (Arrows + Enter)
|
||||
* 5. Mockup Platform Tab Switching
|
||||
* 6. Responsive Mobile & Landscape Sidebar Navigation
|
||||
* 7. Image Lightbox Zoom Modal
|
||||
* 8. FAQ Accordion Interaction
|
||||
*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
// ==========================================
|
||||
// 1. THEME TOGGLE
|
||||
// 1. THEME TOGGLE (EYE-FRIENDLY SLATE DARK / CLEAN LIGHT)
|
||||
// ==========================================
|
||||
const themeToggleBtn = document.getElementById('themeToggleBtn');
|
||||
const savedTheme = localStorage.getItem('tis_doc_theme') || 'light';
|
||||
const savedTheme = localStorage.getItem('tis_doc_theme') ||
|
||||
(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
||||
|
||||
document.documentElement.setAttribute('data-theme', savedTheme);
|
||||
updateThemeButton(savedTheme);
|
||||
|
||||
themeToggleBtn.addEventListener('click', () => {
|
||||
const currentTheme = document.documentElement.getAttribute('data-theme');
|
||||
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
|
||||
document.documentElement.setAttribute('data-theme', newTheme);
|
||||
localStorage.setItem('tis_doc_theme', newTheme);
|
||||
});
|
||||
function updateThemeButton(theme) {
|
||||
if (!themeToggleBtn) return;
|
||||
const isDark = theme === 'dark';
|
||||
themeToggleBtn.setAttribute('title', isDark ? 'Switch to light theme' : 'Switch to eye-friendly dark theme');
|
||||
themeToggleBtn.setAttribute('aria-label', isDark ? 'Switch to light theme' : 'Switch to eye-friendly dark theme');
|
||||
}
|
||||
|
||||
if (themeToggleBtn) {
|
||||
themeToggleBtn.addEventListener('click', () => {
|
||||
const currentTheme = document.documentElement.getAttribute('data-theme');
|
||||
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
|
||||
document.documentElement.setAttribute('data-theme', newTheme);
|
||||
localStorage.setItem('tis_doc_theme', newTheme);
|
||||
updateThemeButton(newTheme);
|
||||
});
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 2. PRINT HANDLER
|
||||
// ==========================================
|
||||
const printBtn = document.getElementById('printBtn');
|
||||
if (printBtn) {
|
||||
printBtn.addEventListener('click', () => {
|
||||
printBtn.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
window.print();
|
||||
});
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 2B. MOBILE NAVIGATION & SEARCH
|
||||
// 3. GLOBAL PLATFORM FILTER (ALL / WINDOWS / ANDROID)
|
||||
// ==========================================
|
||||
const platformFilterBtns = document.querySelectorAll('.platform-pill-toggle .platform-btn');
|
||||
const savedPlatform = localStorage.getItem('tis_doc_platform') || 'all';
|
||||
|
||||
function applyPlatformFilter(filter) {
|
||||
// 1. Update button states in header
|
||||
platformFilterBtns.forEach(btn => {
|
||||
const bFilter = btn.getAttribute('data-platform-filter');
|
||||
btn.classList.toggle('active', bFilter === filter);
|
||||
});
|
||||
|
||||
// 2. Set root attribute for CSS styling
|
||||
document.documentElement.setAttribute('data-doc-platform', filter);
|
||||
|
||||
// 3. Save to localStorage
|
||||
localStorage.setItem('tis_doc_platform', filter);
|
||||
|
||||
// 4. Update mockup container tabs on the current page
|
||||
document.querySelectorAll('.mockup-container').forEach(container => {
|
||||
const winTabBtn = container.querySelector('[data-tab-target^="win-"]');
|
||||
const andTabBtn = container.querySelector('[data-tab-target^="and-"]');
|
||||
|
||||
if (filter === 'windows' && winTabBtn) {
|
||||
winTabBtn.click();
|
||||
} else if (filter === 'android' && andTabBtn) {
|
||||
andTabBtn.click();
|
||||
} else if (filter === 'all' && winTabBtn) {
|
||||
winTabBtn.click();
|
||||
}
|
||||
});
|
||||
|
||||
// 5. In shortcut tables or platform badges, adjust visual state
|
||||
document.querySelectorAll('.shortcut-group-windows, .shortcut-group-android').forEach(el => {
|
||||
if (filter === 'all') {
|
||||
el.style.opacity = '';
|
||||
} else if (filter === 'windows') {
|
||||
el.style.opacity = el.classList.contains('shortcut-group-windows') ? '1' : '0.35';
|
||||
} else if (filter === 'android') {
|
||||
el.style.opacity = el.classList.contains('shortcut-group-android') ? '1' : '0.35';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize platform filter from storage
|
||||
applyPlatformFilter(savedPlatform);
|
||||
|
||||
// Attach click listener to platform pill buttons
|
||||
platformFilterBtns.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
const filter = btn.getAttribute('data-platform-filter');
|
||||
applyPlatformFilter(filter);
|
||||
});
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// 4. MOCKUP TAB SWITCHING (IN-PAGE WINDOWS / ANDROID)
|
||||
// ==========================================
|
||||
document.querySelectorAll('.mockup-container').forEach(container => {
|
||||
const tabBtns = container.querySelectorAll('.mockup-tab-btn');
|
||||
const panes = container.querySelectorAll('.mockup-pane');
|
||||
|
||||
tabBtns.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
const targetId = btn.getAttribute('data-tab-target');
|
||||
|
||||
tabBtns.forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
|
||||
panes.forEach(pane => {
|
||||
if (pane.id === targetId) {
|
||||
pane.style.display = 'block';
|
||||
pane.classList.add('active');
|
||||
} else {
|
||||
pane.style.display = 'none';
|
||||
pane.classList.remove('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// 5. MOBILE NAVIGATION & SEARCH
|
||||
// ==========================================
|
||||
const mobileMenuBtn = document.getElementById('mobileMenuBtn');
|
||||
const docSidebar = document.getElementById('docSidebar');
|
||||
@@ -94,7 +192,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// Mobile search toggle
|
||||
// Mobile search toggle button in header
|
||||
if (mobileSearchBtn && headerSearchBox) {
|
||||
mobileSearchBtn.addEventListener('click', () => {
|
||||
const isOpen = headerSearchBox.classList.toggle('mobile-open');
|
||||
@@ -105,7 +203,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 3. FAQ ACCORDION HANDLER
|
||||
// 6. FAQ ACCORDION HANDLER
|
||||
// ==========================================
|
||||
document.querySelectorAll('.faq-item').forEach(item => {
|
||||
const questionBtn = item.querySelector('.faq-question');
|
||||
@@ -118,60 +216,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// 4. MOCKUP TAB SWITCHING (WINDOWS / ANDROID)
|
||||
// ==========================================
|
||||
document.querySelectorAll('.mockup-container').forEach(container => {
|
||||
const tabBtns = container.querySelectorAll('.mockup-tab-btn');
|
||||
const panes = container.querySelectorAll('.mockup-pane');
|
||||
|
||||
tabBtns.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
const targetId = btn.getAttribute('data-tab-target');
|
||||
|
||||
tabBtns.forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
|
||||
panes.forEach(pane => {
|
||||
if (pane.id === targetId) {
|
||||
pane.style.display = 'block';
|
||||
pane.classList.add('active');
|
||||
} else {
|
||||
pane.style.display = 'none';
|
||||
pane.classList.remove('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// 5. GLOBAL PLATFORM FILTER IN HEADER
|
||||
// ==========================================
|
||||
const platformFilterBtns = document.querySelectorAll('.platform-pill-toggle .platform-btn');
|
||||
platformFilterBtns.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
platformFilterBtns.forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
|
||||
const filter = btn.getAttribute('data-platform-filter');
|
||||
|
||||
document.querySelectorAll('.mockup-container').forEach(container => {
|
||||
const winTabBtn = container.querySelector('[data-tab-target^="win-"]');
|
||||
const andTabBtn = container.querySelector('[data-tab-target^="and-"]');
|
||||
|
||||
if (filter === 'windows' && winTabBtn) {
|
||||
winTabBtn.click();
|
||||
} else if (filter === 'android' && andTabBtn) {
|
||||
andTabBtn.click();
|
||||
} else if (filter === 'all' && winTabBtn) {
|
||||
winTabBtn.click();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// 6. LIGHTBOX ZOOM MODAL
|
||||
// 7. LIGHTBOX ZOOM MODAL
|
||||
// ==========================================
|
||||
const lightboxModal = document.getElementById('lightboxModal');
|
||||
const lightboxImg = document.getElementById('lightboxImg');
|
||||
@@ -215,19 +260,62 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 7. LIVE SEARCH WITH HIGHLIGHTING & SHORTCUT
|
||||
// 8. MULTI-PAGE LIVE SEARCH & QUICK NAVIGATION
|
||||
// ==========================================
|
||||
const searchInput = document.getElementById('docSearchInput');
|
||||
const searchableSections = document.querySelectorAll('.doc-section, .hero-banner');
|
||||
|
||||
const DOC_PAGES = [
|
||||
{ title: 'System Overview', url: 'index.html', desc: 'System overview, school background, key capabilities, and handbook introduction' },
|
||||
{ title: 'Staff Roles & Access', url: 'roles.html', desc: 'Administrator vs. Teacher permissions, advisory scoping, and registration permissions' },
|
||||
{ title: 'Sign In & Getting Started', url: 'login.html', desc: 'Login credentials, Android & Windows app access, remote tunnel, and OTP recovery' },
|
||||
{ title: 'Module 1: Dashboard', url: 'dashboard.html', desc: 'Real-time metrics, role toolbars, visual charts, top students, and attention lists' },
|
||||
{ title: 'Module 2: Students', url: 'students.html', desc: 'Learner profiles, dynamic filters, SF9/SF10 OCR autofill, bulk CSV import, multi-select' },
|
||||
{ title: 'Module 3: Documents', url: 'documents.html', desc: 'Virtual student folders, Android camera scanner, collapsible checklist, file previews' },
|
||||
{ title: 'Module 4: Archives', url: 'archives.html', desc: 'Historical learner archives, file restoration, and automatic inactive archiving' },
|
||||
{ title: 'Module 5: Batch Print', url: 'batchprint.html', desc: 'Multi-document print queue, Excel-to-PDF conversion, and email pickup notifications' },
|
||||
{ title: 'Module 6: Reports & Analytics', url: 'reports.html', desc: 'DepEd transparency board, compliance breakdown, storage analytics, Excel export' },
|
||||
{ title: 'Module 7: User Accounts', url: 'users.html', desc: 'Staff account management, teacher assignments, activation, and password resets' },
|
||||
{ title: 'Module 8: Activity History', url: 'history.html', desc: 'System activity logs, user lifecycle history, active sessions, and IP address audits' },
|
||||
{ title: 'Module 9: School Settings', url: 'settings.html', desc: 'Academic setup, dynamic document checklists, automated reminders, and graduation' },
|
||||
{ title: 'Keyboard Shortcuts', url: 'shortcuts.html', desc: 'Hotkeys and touch gestures for Windows desktop and Android tablets' },
|
||||
{ title: 'Frequently Asked Questions', url: 'faq.html', desc: 'Common questions regarding offline mode, remote access, OCR, and backups' },
|
||||
{ title: 'Help & Troubleshooting', url: 'troubleshooting.html', desc: 'Diagnostic steps for LAN connections, scanner troubleshooting, and sync' }
|
||||
];
|
||||
|
||||
let searchDropdown = document.getElementById('searchDropdown');
|
||||
if (!searchDropdown && headerSearchBox) {
|
||||
searchDropdown = document.createElement('div');
|
||||
searchDropdown.id = 'searchDropdown';
|
||||
searchDropdown.className = 'search-dropdown';
|
||||
headerSearchBox.appendChild(searchDropdown);
|
||||
}
|
||||
|
||||
let selectedResultIndex = -1;
|
||||
|
||||
function updateSelectedResult(items) {
|
||||
items.forEach((item, index) => {
|
||||
item.classList.toggle('selected', index === selectedResultIndex);
|
||||
if (index === selectedResultIndex) {
|
||||
item.scrollIntoView({ block: 'nearest' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (searchInput) {
|
||||
searchInput.addEventListener('input', (e) => {
|
||||
const query = e.target.value.trim().toLowerCase();
|
||||
selectedResultIndex = -1;
|
||||
|
||||
// Current page element filtering
|
||||
if (!query) {
|
||||
if (searchDropdown) {
|
||||
searchDropdown.classList.remove('active');
|
||||
searchDropdown.innerHTML = '';
|
||||
}
|
||||
searchableSections.forEach(sec => {
|
||||
sec.style.display = '';
|
||||
sec.querySelectorAll('.feature-card, .step-card, tr').forEach(item => {
|
||||
sec.querySelectorAll('.feature-card, .step-card, tr, .component-screenshot, .mockup-container').forEach(item => {
|
||||
item.style.display = '';
|
||||
});
|
||||
});
|
||||
@@ -238,25 +326,76 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const text = sec.textContent.toLowerCase();
|
||||
if (text.includes(query)) {
|
||||
sec.style.display = '';
|
||||
|
||||
// Filter internal child cards
|
||||
sec.querySelectorAll('.feature-card, .step-card').forEach(card => {
|
||||
const cardText = card.textContent.toLowerCase();
|
||||
card.style.display = cardText.includes(query) ? '' : 'none';
|
||||
});
|
||||
} else {
|
||||
sec.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Multi-page suggestion dropdown
|
||||
if (searchDropdown) {
|
||||
const matches = DOC_PAGES.filter(p =>
|
||||
p.title.toLowerCase().includes(query) ||
|
||||
p.desc.toLowerCase().includes(query)
|
||||
);
|
||||
|
||||
if (matches.length > 0) {
|
||||
searchDropdown.innerHTML = matches.map((m, idx) => `
|
||||
<a href="${m.url}" class="search-result-item" data-index="${idx}">
|
||||
<span class="search-result-title">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><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>
|
||||
${m.title}
|
||||
</span>
|
||||
<span class="search-result-desc">${m.desc}</span>
|
||||
</a>
|
||||
`).join('');
|
||||
searchDropdown.classList.add('active');
|
||||
} else {
|
||||
searchDropdown.classList.remove('active');
|
||||
searchDropdown.innerHTML = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Global keyboard shortcut: Ctrl+K or / focuses search
|
||||
// Keyboard navigation in search input: ArrowDown, ArrowUp, Enter, Escape
|
||||
searchInput.addEventListener('keydown', (e) => {
|
||||
if (!searchDropdown || !searchDropdown.classList.contains('active')) return;
|
||||
const items = searchDropdown.querySelectorAll('.search-result-item');
|
||||
if (items.length === 0) return;
|
||||
|
||||
if (e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
selectedResultIndex = (selectedResultIndex + 1) % items.length;
|
||||
updateSelectedResult(items);
|
||||
} else if (e.key === 'ArrowUp') {
|
||||
e.preventDefault();
|
||||
selectedResultIndex = (selectedResultIndex - 1 + items.length) % items.length;
|
||||
updateSelectedResult(items);
|
||||
} else if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
if (selectedResultIndex >= 0 && selectedResultIndex < items.length) {
|
||||
items[selectedResultIndex].click();
|
||||
} else if (items.length > 0) {
|
||||
items[0].click();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('click', (e) => {
|
||||
if (searchDropdown && !headerSearchBox.contains(e.target)) {
|
||||
searchDropdown.classList.remove('active');
|
||||
}
|
||||
});
|
||||
|
||||
// Global keyboard shortcut: Ctrl+F, Ctrl+K, or / focuses search
|
||||
window.addEventListener('keydown', (e) => {
|
||||
if ((e.ctrlKey && e.key === 'k') || (e.key === '/' && document.activeElement !== searchInput)) {
|
||||
if ((e.ctrlKey && (e.key.toLowerCase() === 'f' || e.key.toLowerCase() === 'k')) || (e.key === '/' && document.activeElement !== searchInput)) {
|
||||
e.preventDefault();
|
||||
searchInput.focus();
|
||||
searchInput.select();
|
||||
} else if (e.key === 'Escape') {
|
||||
if (searchDropdown) searchDropdown.classList.remove('active');
|
||||
if (lightboxModal && lightboxModal.classList.contains('active')) {
|
||||
closeLightbox();
|
||||
} else if (document.activeElement === searchInput) {
|
||||
@@ -267,29 +406,17 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 8. SCROLLSPY NAVIGATION
|
||||
// 9. ACTIVE PAGE SIDEBAR HIGHLIGHTING & LANDSCAPE SCROLL
|
||||
// ==========================================
|
||||
const navLinks = document.querySelectorAll('.doc-sidebar .nav-link');
|
||||
const sections = document.querySelectorAll('.hero-banner, .doc-section');
|
||||
const currentPath = window.location.pathname.split('/').pop() || 'index.html';
|
||||
|
||||
function updateActiveNavLink() {
|
||||
const scrollY = window.pageYOffset || document.documentElement.scrollTop;
|
||||
|
||||
sections.forEach(section => {
|
||||
const sectionTop = section.offsetTop - 120;
|
||||
const sectionHeight = section.offsetHeight;
|
||||
const sectionId = section.getAttribute('id');
|
||||
|
||||
if (scrollY >= sectionTop && scrollY < sectionTop + sectionHeight) {
|
||||
navLinks.forEach(link => {
|
||||
link.classList.remove('active');
|
||||
if (link.getAttribute('href') === `#${sectionId}`) {
|
||||
link.classList.add('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', updateActiveNavLink, { passive: true });
|
||||
navLinks.forEach(link => {
|
||||
const linkHref = link.getAttribute('href');
|
||||
if (linkHref === currentPath || (currentPath === '' && linkHref === 'index.html') || (currentPath === 'overview.html' && linkHref === 'index.html')) {
|
||||
link.classList.add('active');
|
||||
// On landscape or small screens, ensure active link is visible in scrollable sidebar
|
||||
link.scrollIntoView({ block: 'nearest' });
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user