210 lines
7.3 KiB
JavaScript
210 lines
7.3 KiB
JavaScript
// static/admin/js/icons-page.js
|
||
|
||
// Setup logging
|
||
const ICONS_PAGE_LOG_LEVEL = 3;
|
||
|
||
const iconsLog = {
|
||
error: (...args) => ICONS_PAGE_LOG_LEVEL >= 1 && console.error('❌ [ICONS PAGE ERROR]', ...args),
|
||
warn: (...args) => ICONS_PAGE_LOG_LEVEL >= 2 && console.warn('⚠️ [ICONS PAGE WARN]', ...args),
|
||
info: (...args) => ICONS_PAGE_LOG_LEVEL >= 3 && console.info('ℹ️ [ICONS PAGE INFO]', ...args),
|
||
debug: (...args) => ICONS_PAGE_LOG_LEVEL >= 4 && console.log('🔍 [ICONS PAGE DEBUG]', ...args)
|
||
};
|
||
|
||
/**
|
||
* Icons Browser Alpine.js Component
|
||
* Browse and search all available icons
|
||
*/
|
||
function adminIcons() {
|
||
return {
|
||
// ✅ CRITICAL: Inherit base layout functionality
|
||
...data(),
|
||
|
||
// ✅ CRITICAL: Set page identifier
|
||
currentPage: 'icons',
|
||
|
||
// Search and filter
|
||
searchQuery: '',
|
||
activeCategory: 'all',
|
||
|
||
// Icon categories
|
||
categories: [
|
||
{ id: 'all', name: 'All Icons', icon: 'collection' },
|
||
{ id: 'navigation', name: 'Navigation', icon: 'menu' },
|
||
{ id: 'user', name: 'User & Profile', icon: 'user' },
|
||
{ id: 'actions', name: 'Actions', icon: 'lightning-bolt' },
|
||
{ id: 'ecommerce', name: 'E-commerce', icon: 'shopping-bag' },
|
||
{ id: 'inventory', name: 'Inventory', icon: 'cube' },
|
||
{ id: 'communication', name: 'Communication', icon: 'mail' },
|
||
{ id: 'files', name: 'Files', icon: 'document' },
|
||
{ id: 'settings', name: 'Settings', icon: 'cog' },
|
||
{ id: 'status', name: 'Status', icon: 'check-circle' },
|
||
{ id: 'testing', name: 'Testing', icon: 'beaker' }
|
||
],
|
||
|
||
// All icons organized by category
|
||
iconsByCategory: {},
|
||
allIcons: [],
|
||
filteredIcons: [],
|
||
|
||
// Selected icon for detail view
|
||
selectedIcon: null,
|
||
|
||
// ✅ CRITICAL: Proper initialization with guard
|
||
async init() {
|
||
iconsLog.info('=== ICONS PAGE INITIALIZING ===');
|
||
|
||
// Prevent multiple initializations
|
||
if (window._iconsPageInitialized) {
|
||
iconsLog.warn('Icons page already initialized, skipping...');
|
||
return;
|
||
}
|
||
window._iconsPageInitialized = true;
|
||
|
||
// Load icons from global Icons object
|
||
this.loadIcons();
|
||
|
||
iconsLog.info('=== ICONS PAGE INITIALIZATION COMPLETE ===');
|
||
},
|
||
|
||
/**
|
||
* Load icons from global Icons object
|
||
*/
|
||
loadIcons() {
|
||
if (!window.Icons) {
|
||
iconsLog.error('Icons object not found! Make sure icons.js is loaded.');
|
||
return;
|
||
}
|
||
|
||
// Get all icon names
|
||
this.allIcons = Object.keys(window.Icons).map(name => ({
|
||
name: name,
|
||
category: this.categorizeIcon(name)
|
||
}));
|
||
|
||
// Organize by category
|
||
this.iconsByCategory = this.allIcons.reduce((acc, icon) => {
|
||
if (!acc[icon.category]) {
|
||
acc[icon.category] = [];
|
||
}
|
||
acc[icon.category].push(icon);
|
||
return acc;
|
||
}, {});
|
||
|
||
// Initial filter
|
||
this.filterIcons();
|
||
|
||
iconsLog.info(`Loaded ${this.allIcons.length} icons across ${Object.keys(this.iconsByCategory).length} categories`);
|
||
},
|
||
|
||
/**
|
||
* Categorize icon based on name
|
||
*/
|
||
categorizeIcon(iconName) {
|
||
const categoryMap = {
|
||
navigation: ['home', 'menu', 'search', 'arrow', 'chevron'],
|
||
user: ['user', 'identification', 'badge'],
|
||
actions: ['edit', 'delete', 'plus', 'check', 'close', 'refresh', 'duplicate', 'eye', 'filter', 'dots'],
|
||
ecommerce: ['shopping', 'credit-card', 'currency', 'gift', 'tag', 'truck', 'receipt'],
|
||
inventory: ['cube', 'collection', 'photograph', 'chart'],
|
||
communication: ['mail', 'phone', 'chat', 'bell', 'inbox'],
|
||
files: ['document', 'folder', 'download', 'upload'],
|
||
settings: ['cog', 'adjustments', 'calendar', 'moon', 'sun'],
|
||
status: ['exclamation', 'information', 'spinner', 'star', 'heart', 'flag'],
|
||
testing: ['view-grid', 'beaker', 'clipboard-list', 'check-circle', 'lightning-bolt', 'clock', 'lock-closed', 'database', 'light-bulb', 'book-open', 'play']
|
||
};
|
||
|
||
for (const [category, keywords] of Object.entries(categoryMap)) {
|
||
if (keywords.some(keyword => iconName.includes(keyword))) {
|
||
return category;
|
||
}
|
||
}
|
||
return 'navigation'; // default
|
||
},
|
||
|
||
/**
|
||
* Filter icons based on search and category
|
||
*/
|
||
filterIcons() {
|
||
let icons = this.allIcons;
|
||
|
||
// Filter by category
|
||
if (this.activeCategory !== 'all') {
|
||
icons = icons.filter(icon => icon.category === this.activeCategory);
|
||
}
|
||
|
||
// Filter by search query
|
||
if (this.searchQuery.trim()) {
|
||
const query = this.searchQuery.toLowerCase();
|
||
icons = icons.filter(icon => icon.name.toLowerCase().includes(query));
|
||
}
|
||
|
||
this.filteredIcons = icons;
|
||
iconsLog.debug(`Filtered to ${icons.length} icons`);
|
||
},
|
||
|
||
/**
|
||
* Set active category
|
||
*/
|
||
setCategory(categoryId) {
|
||
iconsLog.info('Setting category:', categoryId);
|
||
this.activeCategory = categoryId;
|
||
this.filterIcons();
|
||
},
|
||
|
||
/**
|
||
* Select icon for detail view
|
||
*/
|
||
selectIcon(iconName) {
|
||
iconsLog.info('Selected icon:', iconName);
|
||
this.selectedIcon = iconName;
|
||
},
|
||
|
||
/**
|
||
* Copy icon usage code to clipboard
|
||
*/
|
||
async copyIconUsage(iconName) {
|
||
const code = `x-html="$icon('${iconName}', 'w-5 h-5')"`;
|
||
try {
|
||
await navigator.clipboard.writeText(code);
|
||
Utils.showToast(`'${iconName}' code copied!`, 'success');
|
||
iconsLog.debug('Icon usage code copied:', iconName);
|
||
} catch (error) {
|
||
iconsLog.error('Failed to copy code:', error);
|
||
Utils.showToast('Failed to copy code', 'error');
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Copy icon name to clipboard
|
||
*/
|
||
async copyIconName(iconName) {
|
||
try {
|
||
await navigator.clipboard.writeText(iconName);
|
||
Utils.showToast(`'${iconName}' copied!`, 'success');
|
||
iconsLog.debug('Icon name copied:', iconName);
|
||
} catch (error) {
|
||
iconsLog.error('Failed to copy name:', error);
|
||
Utils.showToast('Failed to copy name', 'error');
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Get category info
|
||
*/
|
||
getCategoryInfo(categoryId) {
|
||
return this.categories.find(c => c.id === categoryId) || this.categories[0];
|
||
},
|
||
|
||
/**
|
||
* Get icon count for category
|
||
*/
|
||
getCategoryCount(categoryId) {
|
||
if (categoryId === 'all') {
|
||
return this.allIcons.length;
|
||
}
|
||
return this.iconsByCategory[categoryId]?.length || 0;
|
||
}
|
||
};
|
||
}
|
||
|
||
iconsLog.info('Icons page module loaded'); |