# JavaScript Module System > Modern ES6+ modular JavaScript architecture with performance monitoring, state management, and component-based UI interactions. ## 📁 Module Structure ``` resources/js/ ├── main.js # Entry point ├── core/ # Core framework modules │ ├── index.js # Core exports │ ├── init.js # Initialization │ ├── router.js # SPA routing │ ├── state.js # State management │ ├── EventManager.js # Event system │ ├── PerformanceMonitor.js # Performance tracking │ └── logger.js # Logging utilities ├── modules/ # Feature modules │ ├── index.js # Module registry │ ├── ui/ # UI components │ │ ├── UIManager.js # UI coordinator │ │ └── components/ # Individual components │ ├── scroll-fx/ # Scroll animations │ ├── lightbox/ # Image lightbox │ └── parallax/ # Parallax effects ├── utils/ # Utility functions └── docs/ # Module documentation ``` ## 🚀 Core System ### Application Initialization ```javascript // main.js - Application entry point import { init } from './core/init.js'; import { ModuleRegistry } from './modules/index.js'; // Initialize core systems await init({ performance: true, router: true, state: true, logging: 'development' }); // Register and load modules ModuleRegistry.register('ui', () => import('./modules/ui/index.js')); ModuleRegistry.register('scrollfx', () => import('./modules/scrollfx/index.js')); // Auto-load modules based on DOM attributes ModuleRegistry.autoLoad(); ``` ### Router System ```javascript // SPA routing with layout animations import { Router } from './core/router.js'; const router = new Router({ mode: 'history', base: '/', transitions: true, prefetch: true }); // Route definitions router.addRoute('/admin/:page?', async (ctx) => { const { page = 'dashboard' } = ctx.params; // Layout animation if (ctx.isLayoutChange) { await animateLayoutSwitch('admin'); } // Load page content return await loadAdminPage(page); }); // Meta data extraction from HTML router.onNavigate((ctx) => { // Extract and apply meta data const metaTitle = ctx.dom.querySelector('[data-meta-title]'); if (metaTitle) { document.title = metaTitle.dataset.metaTitle; } const metaTheme = ctx.dom.querySelector('[data-meta-theme]'); if (metaTheme) { document.documentElement.style.setProperty('--theme-color', metaTheme.dataset.metaTheme); } }); ``` ### State Management ```javascript // Reactive state system import { State } from './core/state.js'; // Global state const appState = new State({ user: null, theme: 'light', admin: { currentPage: 'dashboard', notifications: [] } }); // Reactive updates appState.watch('theme', (newTheme, oldTheme) => { document.documentElement.dataset.theme = newTheme; localStorage.setItem('preferred-theme', newTheme); }); // Component state binding appState.bind('[data-user-name]', 'user.name'); appState.bind('[data-notification-count]', 'admin.notifications.length'); ``` ### Event System ```javascript // Centralized event management import { EventManager } from './core/EventManager.js'; const events = new EventManager(); // Global event delegation events.delegate('click', '[data-action]', (event, element) => { const action = element.dataset.action; const target = element.dataset.target; switch (action) { case 'toggle-theme': appState.set('theme', appState.get('theme') === 'light' ? 'dark' : 'light'); break; case 'show-modal': UIManager.showModal(target); break; } }); // Custom events events.on('admin:page-change', (data) => { appState.set('admin.currentPage', data.page); PerformanceMonitor.mark(`admin-${data.page}-loaded`); }); ``` ## 🧩 UI Component System ### Component Architecture ```javascript // Base component class class BaseComponent { constructor(element, options = {}) { this.element = element; this.options = { ...this.defaults, ...options }; this.state = new State(this.initialState); this.init(); this.bindEvents(); } init() { // Override in subclasses } bindEvents() { // Override in subclasses } destroy() { this.state.destroy(); this.element.removeEventListener(); } } ``` ### Modal Component ```javascript // UI Modal component class Modal extends BaseComponent { defaults = { closeOnOverlay: true, closeOnEscape: true, animation: 'fade' }; initialState = { isOpen: false, content: null }; init() { this.overlay = this.element.querySelector('.modal-overlay'); this.content = this.element.querySelector('.modal-content'); this.closeBtn = this.element.querySelector('[data-modal-close]'); // State reactivity this.state.watch('isOpen', (isOpen) => { this.element.classList.toggle('is-open', isOpen); this.element.setAttribute('aria-hidden', !isOpen); if (isOpen) { this.trapFocus(); } else { this.releaseFocus(); } }); } bindEvents() { if (this.closeBtn) { this.closeBtn.addEventListener('click', () => this.close()); } if (this.options.closeOnOverlay) { this.overlay.addEventListener('click', () => this.close()); } if (this.options.closeOnEscape) { document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && this.state.get('isOpen')) { this.close(); } }); } } open(content = null) { if (content) { this.setContent(content); } this.state.set('isOpen', true); events.emit('modal:opened', { modal: this }); } close() { this.state.set('isOpen', false); events.emit('modal:closed', { modal: this }); } setContent(content) { if (typeof content === 'string') { this.content.innerHTML = content; } else if (content instanceof HTMLElement) { this.content.innerHTML = ''; this.content.appendChild(content); } this.state.set('content', content); } } // Auto-initialization document.querySelectorAll('[data-modal]').forEach(element => { new Modal(element); }); ``` ### Admin-specific Components ```javascript // Admin Stats Card class AdminStatsCard extends BaseComponent { defaults = { updateInterval: 30000, animateChanges: true }; init() { this.valueElement = this.element.querySelector('.stat-value'); this.labelElement = this.element.querySelector('.stat-label'); this.trendElement = this.element.querySelector('.stat-trend'); if (this.options.updateInterval) { this.startPolling(); } } startPolling() { this.pollInterval = setInterval(() => { this.updateValue(); }, this.options.updateInterval); } async updateValue() { const endpoint = this.element.dataset.endpoint; if (!endpoint) return; try { const response = await fetch(endpoint); const data = await response.json(); if (this.options.animateChanges) { this.animateValueChange(data.value); } else { this.setValue(data.value); } if (data.trend) { this.setTrend(data.trend); } } catch (error) { console.error('Failed to update stat:', error); } } animateValueChange(newValue) { const currentValue = parseInt(this.valueElement.textContent) || 0; const duration = 1000; const steps = 60; const increment = (newValue - currentValue) / steps; let step = 0; const timer = setInterval(() => { step++; const value = Math.round(currentValue + (increment * step)); this.valueElement.textContent = value.toLocaleString(); if (step >= steps) { clearInterval(timer); this.valueElement.textContent = newValue.toLocaleString(); } }, duration / steps); } } ``` ## 📊 Performance Monitoring ```javascript // Performance tracking import { PerformanceMonitor } from './core/PerformanceMonitor.js'; // Page load metrics PerformanceMonitor.mark('page-start'); PerformanceMonitor.measure('page-load', 'page-start', 'page-end'); // Component performance class ComponentWithMetrics extends BaseComponent { init() { PerformanceMonitor.mark(`${this.constructor.name}-init-start`); // Component initialization super.init(); PerformanceMonitor.mark(`${this.constructor.name}-init-end`); PerformanceMonitor.measure( `${this.constructor.name}-init`, `${this.constructor.name}-init-start`, `${this.constructor.name}-init-end` ); } } // Performance reporting PerformanceMonitor.report((metrics) => { // Send to analytics if (window.gtag) { gtag('event', 'performance_metric', { custom_map: { metric_name: 'custom_metric_name' }, metric_name: metrics.name, value: metrics.duration }); } }); ``` ## 🎨 Admin Interface Integration ### Theme System ```javascript // Admin theme management class AdminThemeManager { constructor() { this.themes = ['light', 'dark', 'auto']; this.currentTheme = localStorage.getItem('admin-theme') || 'auto'; this.mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); this.init(); } init() { this.applyTheme(this.currentTheme); this.bindEvents(); } bindEvents() { // Theme toggle button document.addEventListener('click', (e) => { if (e.target.matches('[data-theme-toggle]')) { this.toggleTheme(); } }); // System theme changes this.mediaQuery.addEventListener('change', () => { if (this.currentTheme === 'auto') { this.applyTheme('auto'); } }); } applyTheme(theme) { let resolvedTheme = theme; if (theme === 'auto') { resolvedTheme = this.mediaQuery.matches ? 'dark' : 'light'; } document.documentElement.dataset.theme = resolvedTheme; document.documentElement.style.setProperty('--theme-preference', theme); // Update theme color meta tag const metaThemeColor = document.querySelector('meta[name="theme-color"]'); if (metaThemeColor) { const color = resolvedTheme === 'dark' ? '#1e293b' : '#ffffff'; metaThemeColor.setAttribute('content', color); } } toggleTheme() { const currentIndex = this.themes.indexOf(this.currentTheme); const nextIndex = (currentIndex + 1) % this.themes.length; const nextTheme = this.themes[nextIndex]; this.setTheme(nextTheme); } setTheme(theme) { this.currentTheme = theme; localStorage.setItem('admin-theme', theme); this.applyTheme(theme); events.emit('theme:changed', { theme, resolvedTheme: this.getResolvedTheme() }); } getResolvedTheme() { if (this.currentTheme === 'auto') { return this.mediaQuery.matches ? 'dark' : 'light'; } return this.currentTheme; } } // Initialize admin theme new AdminThemeManager(); ``` ### Data Tables ```javascript // Admin data table component class AdminDataTable extends BaseComponent { defaults = { sortable: true, filterable: true, paginated: true, pageSize: 25 }; init() { this.table = this.element.querySelector('table'); this.tbody = this.table.querySelector('tbody'); this.headers = [...this.table.querySelectorAll('th[data-sort]')]; this.filterInput = this.element.querySelector('[data-table-filter]'); this.data = this.extractData(); this.filteredData = [...this.data]; this.currentSort = { column: null, direction: 'asc' }; this.currentPage = 1; this.bindEvents(); this.render(); } bindEvents() { // Column sorting this.headers.forEach(header => { header.addEventListener('click', () => { const column = header.dataset.sort; this.sort(column); }); }); // Filtering if (this.filterInput) { this.filterInput.addEventListener('input', debounce(() => { this.filter(this.filterInput.value); }, 300)); } } sort(column) { if (this.currentSort.column === column) { this.currentSort.direction = this.currentSort.direction === 'asc' ? 'desc' : 'asc'; } else { this.currentSort.column = column; this.currentSort.direction = 'asc'; } this.filteredData.sort((a, b) => { const aVal = a[column]; const bVal = b[column]; const modifier = this.currentSort.direction === 'asc' ? 1 : -1; if (aVal < bVal) return -1 * modifier; if (aVal > bVal) return 1 * modifier; return 0; }); this.currentPage = 1; this.render(); } filter(query) { if (!query) { this.filteredData = [...this.data]; } else { const searchTerm = query.toLowerCase(); this.filteredData = this.data.filter(row => { return Object.values(row).some(value => String(value).toLowerCase().includes(searchTerm) ); }); } this.currentPage = 1; this.render(); } render() { // Update table body this.renderTableBody(); // Update sort indicators this.updateSortIndicators(); // Update pagination if (this.options.paginated) { this.renderPagination(); } } } ``` ## 🔧 Utility Functions ```javascript // Common utility functions export const utils = { // Debounce function calls debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; }, // Throttle function calls throttle(func, limit) { let inThrottle; return function(...args) { if (!inThrottle) { func.apply(this, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; }, // DOM manipulation helpers dom: { ready(fn) { if (document.readyState !== 'loading') { fn(); } else { document.addEventListener('DOMContentLoaded', fn); } }, create(tag, attributes = {}, children = []) { const element = document.createElement(tag); Object.entries(attributes).forEach(([key, value]) => { if (key === 'className') { element.className = value; } else if (key.startsWith('data-')) { element.dataset[key.slice(5)] = value; } else { element.setAttribute(key, value); } }); children.forEach(child => { if (typeof child === 'string') { element.appendChild(document.createTextNode(child)); } else { element.appendChild(child); } }); return element; } }, // Format utilities format: { bytes(bytes, decimals = 2) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i]; }, duration(ms) { if (ms < 1000) return `${ms}ms`; if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`; return `${(ms / 60000).toFixed(1)}m`; } } }; ``` --- *For specific module documentation, see individual files in `/resources/js/docs/`* *For performance optimization, see [Performance Guidelines](../development/performance.md)* *For component integration, see [UI Components](components.md)*