/** * Bootstrap to Tailwind Migration Helper * * This script provides class mappings for migrating Bootstrap templates to Tailwind CSS. * Usage: Include this script temporarily during migration to add Bootstrap-compatible classes. * * NOTE: This is a temporary compatibility layer. Templates should be properly migrated * to use px360.css classes (hh-* prefix) for long-term maintainability. */ (function() { // Bootstrap to Tailwind class mappings const bootstrapToTailwind = { // Container & Layout 'container': 'max-w-7xl mx-auto px-4 sm:px-6 lg:px-8', 'container-fluid': 'w-full px-4', 'row': 'flex flex-wrap -mx-2', 'col': 'w-full px-2', 'col-auto': 'w-auto px-2', // Grid columns (simplified mapping) 'col-1': 'w-1/12 px-2', 'col-2': 'w-2/12 px-2', 'col-3': 'w-3/12 px-2', 'col-4': 'w-4/12 px-2', 'col-5': 'w-5/12 px-2', 'col-6': 'w-6/12 px-2', 'col-7': 'w-7/12 px-2', 'col-8': 'w-8/12 px-2', 'col-9': 'w-9/12 px-2', 'col-10': 'w-10/12 px-2', 'col-11': 'w-11/12 px-2', 'col-12': 'w-full px-2', // Responsive breakpoints 'col-md-1': 'md:w-1/12 px-2', 'col-md-2': 'md:w-2/12 px-2', 'col-md-3': 'md:w-3/12 px-2', 'col-md-4': 'md:w-4/12 px-2', 'col-md-6': 'md:w-6/12 px-2', 'col-md-8': 'md:w-8/12 px-2', 'col-md-12': 'md:w-full px-2', 'col-lg-3': 'lg:w-3/12 px-2', 'col-lg-4': 'lg:w-4/12 px-2', 'col-lg-6': 'lg:w-6/12 px-2', 'col-lg-8': 'lg:w-8/12 px-2', 'col-lg-12': 'lg:w-full px-2', // Display & Flex 'd-flex': 'flex', 'd-inline-flex': 'inline-flex', 'd-block': 'block', 'd-inline-block': 'inline-block', 'd-none': 'hidden', 'd-grid': 'grid', 'justify-content-start': 'justify-start', 'justify-content-end': 'justify-end', 'justify-content-center': 'justify-center', 'justify-content-between': 'justify-between', 'justify-content-around': 'justify-around', 'align-items-start': 'items-start', 'align-items-end': 'items-end', 'align-items-center': 'items-center', 'align-items-baseline': 'items-baseline', 'align-items-stretch': 'items-stretch', 'flex-row': 'flex-row', 'flex-column': 'flex-col', 'flex-wrap': 'flex-wrap', 'flex-nowrap': 'flex-nowrap', 'flex-grow-1': 'flex-grow', 'flex-shrink-0': 'flex-shrink-0', // Spacing (simplified) 'm-0': 'm-0', 'm-1': 'm-1', 'm-2': 'm-2', 'm-3': 'm-4', 'm-4': 'm-6', 'm-5': 'm-8', 'mt-1': 'mt-1', 'mt-2': 'mt-2', 'mt-3': 'mt-4', 'mt-4': 'mt-6', 'mt-5': 'mt-8', 'mb-1': 'mb-1', 'mb-2': 'mb-2', 'mb-3': 'mb-4', 'mb-4': 'mb-6', 'mb-5': 'mb-8', 'ms-1': 'ms-1', 'ms-2': 'ms-2', 'ms-3': 'ms-4', 'ms-auto': 'ms-auto', 'me-1': 'me-1', 'me-2': 'me-2', 'me-3': 'me-4', 'me-auto': 'me-auto', 'p-0': 'p-0', 'p-1': 'p-1', 'p-2': 'p-2', 'p-3': 'p-4', 'p-4': 'p-6', 'p-5': 'p-8', 'px-1': 'px-1', 'px-2': 'px-2', 'px-3': 'px-4', 'px-4': 'px-6', 'py-1': 'py-1', 'py-2': 'py-2', 'py-3': 'py-4', 'py-4': 'py-6', 'gap-1': 'gap-1', 'gap-2': 'gap-2', 'gap-3': 'gap-4', // Text 'text-start': 'text-left', 'text-end': 'text-right', 'text-center': 'text-center', 'text-truncate': 'truncate', 'text-wrap': 'break-words', 'text-nowrap': 'whitespace-nowrap', 'fw-bold': 'font-bold', 'fw-semibold': 'font-semibold', 'fw-normal': 'font-normal', 'fw-light': 'font-light', 'fst-italic': 'italic', 'text-muted': 'text-gray-500', 'text-primary': 'text-blue-600', 'text-success': 'text-green-600', 'text-danger': 'text-red-600', 'text-warning': 'text-yellow-600', 'text-info': 'text-blue-500', 'fs-1': 'text-5xl', 'fs-2': 'text-4xl', 'fs-3': 'text-3xl', 'fs-4': 'text-2xl', 'fs-5': 'text-xl', 'fs-6': 'text-base', 'small': 'text-sm', // Background & Colors 'bg-primary': 'bg-blue-600', 'bg-secondary': 'bg-gray-500', 'bg-success': 'bg-green-500', 'bg-danger': 'bg-red-500', 'bg-warning': 'bg-yellow-500', 'bg-info': 'bg-blue-400', 'bg-light': 'bg-gray-100', 'bg-dark': 'bg-gray-800', 'bg-white': 'bg-white', 'bg-transparent': 'bg-transparent', // Border 'border': 'border', 'border-0': 'border-0', 'border-top': 'border-t', 'border-end': 'border-e', 'border-bottom': 'border-b', 'border-start': 'border-s', 'rounded': 'rounded', 'rounded-0': 'rounded-none', 'rounded-1': 'rounded-sm', 'rounded-2': 'rounded', 'rounded-3': 'rounded-lg', 'rounded-circle': 'rounded-full', // Sizing 'w-25': 'w-1/4', 'w-50': 'w-1/2', 'w-75': 'w-3/4', 'w-100': 'w-full', 'w-auto': 'w-auto', 'h-25': 'h-1/4', 'h-50': 'h-1/2', 'h-75': 'h-3/4', 'h-100': 'h-full', 'h-auto': 'h-auto', // Position 'position-static': 'static', 'position-relative': 'relative', 'position-absolute': 'absolute', 'position-fixed': 'fixed', 'position-sticky': 'sticky', // Overflow 'overflow-auto': 'overflow-auto', 'overflow-hidden': 'overflow-hidden', // Visibility 'visible': 'visible', 'invisible': 'invisible', // Screen readers 'visually-hidden': 'sr-only', 'visually-hidden-focusable': 'sr-only focus:not-sr-only', }; // Component-specific mappings (these need more complex handling) const componentMappings = { // Table classes - use px360.css hh-table instead 'table': 'hh-table', 'table-hover': '', // hh-table has hover built-in 'table-striped': '', // would need separate class 'table-bordered': 'border-collapse border', 'table-sm': 'text-sm', 'table-responsive': 'overflow-x-auto', // Card classes - use px360.css hh-card instead 'card': 'hh-card', 'card-body': 'hh-card-body', 'card-header': 'hh-card-header', 'card-footer': 'hh-card-footer', 'card-title': 'text-lg font-semibold', 'card-text': 'text-gray-600', // Button classes - use px360.css hh-btn-* instead 'btn': 'hh-btn', 'btn-primary': 'hh-btn hh-btn-primary', 'btn-secondary': 'hh-btn hh-btn-secondary', 'btn-success': 'hh-btn hh-btn-success', 'btn-danger': 'hh-btn hh-btn-danger', 'btn-warning': 'hh-btn hh-btn-primary', // fallback 'btn-info': 'hh-btn hh-btn-primary', // fallback 'btn-light': 'hh-btn hh-btn-secondary', 'btn-dark': 'hh-btn hh-btn-primary', 'btn-link': 'hh-btn hh-btn-ghost', 'btn-sm': 'hh-btn-sm', 'btn-lg': 'hh-btn-lg', 'btn-block': 'hh-btn-block', // Badge classes - use px360.css hh-badge-* instead 'badge': 'hh-badge', 'rounded-pill': 'rounded-full', // Alert classes - use px360.css hh-alert-* instead 'alert': 'hh-alert', 'alert-success': 'hh-alert hh-alert-success', 'alert-danger': 'hh-alert hh-alert-danger', 'alert-warning': 'hh-alert hh-alert-warning', 'alert-info': 'hh-alert hh-alert-info', 'alert-dismissible': '', // would need JS handling // Form classes - use px360.css hh-form-* instead 'form-control': 'hh-form-input', 'form-select': 'hh-form-select', 'form-label': 'hh-form-label', 'form-text': 'text-sm text-gray-500 mt-1', 'form-check': 'flex items-center gap-2', 'form-check-input': 'w-4 h-4', 'form-check-label': 'text-sm', // Pagination classes - use px360.css hh-pagination instead 'pagination': 'hh-pagination', 'page-item': '', // handled by hh-pagination-btn 'page-link': 'hh-pagination-btn', 'active': 'active', // combined with pagination class 'disabled': 'opacity-50 cursor-not-allowed', // List group 'list-group': 'divide-y divide-gray-200 border rounded-xl', 'list-group-item': 'p-4', 'list-group-item-action': 'hover:bg-gray-50 cursor-pointer', // Breadcrumb classes - use px360.css hh-breadcrumb instead 'breadcrumb': 'hh-breadcrumb', 'breadcrumb-item': 'hh-breadcrumb-item', 'active': 'active', // Dropdown - preserve original classes alongside new ones 'dropdown': 'hh-dropdown', 'dropdown-menu': 'hh-dropdown-menu dropdown-menu', 'dropdown-item': 'hh-dropdown-item dropdown-item', 'dropdown-toggle': 'dropdown-toggle', 'dropdown-divider': 'hh-dropdown-divider', // Modal 'modal': 'hh-modal-overlay', 'modal-dialog': '', // part of overlay 'modal-content': 'hh-modal', 'modal-header': 'hh-modal-header', 'modal-body': 'hh-modal-body', 'modal-footer': 'hh-modal-footer', 'modal-title': 'hh-modal-title', 'fade': '', // handled by CSS 'show': 'active', // Navbar 'navbar': 'flex items-center justify-between py-4', 'navbar-brand': 'text-xl font-bold', 'navbar-nav': 'flex items-center gap-4', 'nav-item': '', 'nav-link': 'text-gray-600 hover:text-gray-900', // Tabs 'nav-tabs': 'hh-tabs', 'nav-link': 'hh-tab', 'active': 'active', // Spinner 'spinner-border': 'hh-loading', 'spinner-border-sm': 'w-4 h-4', }; // Merge all mappings const allMappings = { ...bootstrapToTailwind, ...componentMappings }; // Function to convert Bootstrap classes to Tailwind function convertBootstrapClasses(element) { if (!element.classList) return; const classes = Array.from(element.classList); const newClasses = []; let hasBootstrap = false; classes.forEach(cls => { if (allMappings[cls]) { hasBootstrap = true; if (allMappings[cls]) { newClasses.push(...allMappings[cls].split(' ').filter(c => c)); } } else { newClasses.push(cls); } }); if (hasBootstrap) { element.className = newClasses.join(' '); } // Recursively process children Array.from(element.children).forEach(child => { convertBootstrapClasses(child); }); } // Run conversion after DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { convertBootstrapClasses(document.body); }); } else { convertBootstrapClasses(document.body); } console.log('[Bootstrap→Tailwind] Migration helper loaded. Bootstrap classes converted to Tailwind/px360.css classes.'); })();