Skip to content

Instantly share code, notes, and snippets.

@wpeasy
Last active October 27, 2025 04:21
Show Gist options
  • Select an option

  • Save wpeasy/741114f7dde704c9274c1b968e3ec054 to your computer and use it in GitHub Desktop.

Select an option

Save wpeasy/741114f7dde704c9274c1b968e3ec054 to your computer and use it in GitHub Desktop.
Advanced Themer, Move
/* UPDATED 23/10/2025 */
(() => {
// ====================================
// Detect if in Bricks Builder Editor
// ====================================
const isInBricksEditor = () => {
// Check for bricks=run query parameter (most reliable)
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get('bricks') === 'run';
};
// ====================================
// Run your code only in Bricks editor
// ====================================
if (isInBricksEditor()) {
// YOUR CODE HERE
// Add your editor-specific code below
}
// ====================================
// Or wait for DOM ready
// ====================================
document.addEventListener('DOMContentLoaded', () => {
if (isInBricksEditor()) {
// YOUR CODE HERE
}
});
// ====================================
// Wait for Bricks editor to initialize
// ====================================
if (isInBricksEditor()) {
// State management
const STORAGE_KEY = 'bricks_move_sticky_css_enabled';
let isEnabled = localStorage.getItem(STORAGE_KEY) === 'true';
let mainObserver = null;
let resizeObserver = null;
let styleObserver = null;
const cleanupObservers = () => {
if (resizeObserver) {
resizeObserver.disconnect();
resizeObserver = null;
}
if (styleObserver) {
styleObserver.disconnect();
styleObserver = null;
}
};
const setupObserver = () => {
// Set up MutationObserver for #brxcStructureBottomContainer
const targetElement = document.querySelector('#bricks-structure main #brxcStructureBottomContainer');
if (targetElement) {
mainObserver = new MutationObserver((mutations) => {
if (!isEnabled) return; // Skip if disabled
mutations.forEach((mutation) => {
// Check for added nodes
mutation.addedNodes.forEach((node) => {
if (node.nodeType === 1 && node.id === 'brxc-sticky-css') {
const iframeWrapper = document.querySelector('#bricks-builder-iframe-wrapper');
if (iframeWrapper) {
// Append as last child of the wrapper
iframeWrapper.appendChild(node);
// Inject CSS for styling .brxc-action elements
const styleId = 'brxc-sticky-custom-styles';
if (!document.getElementById(styleId)) {
const style = document.createElement('style');
style.id = styleId;
style.textContent = `
#brxc-sticky-css .brxc-action {
color: var(--builder-color-accent) !important;
fill: var(--builder-color-accent) !important;
}
`;
document.head.appendChild(style);
}
const builderIframe = iframeWrapper.querySelector('iframe#bricks-builder-iframe');
if (builderIframe) {
// Clean up any existing observers first
cleanupObservers();
// Function to calculate and set iframe height
const updateIframeHeight = () => {
const stickyCssHeight = node.offsetHeight;
builderIframe.setAttribute('style', `height: calc(100% - ${stickyCssHeight + 7}px);`);
};
// Set initial height
updateIframeHeight();
// Watch for height changes on #brxc-sticky-css
resizeObserver = new ResizeObserver(() => {
if (isEnabled) {
updateIframeHeight();
}
});
resizeObserver.observe(node);
// Also watch for style attribute changes (for immediate updates)
styleObserver = new MutationObserver(() => {
if (isEnabled) {
updateIframeHeight();
}
});
styleObserver.observe(node, {
attributes: true,
attributeFilter: ['style']
});
}
}
}
});
// Check for removed nodes
mutation.removedNodes.forEach((node) => {
if (node.nodeType === 1 && node.id === 'brxc-sticky-css') {
const iframeWrapper = document.querySelector('#bricks-builder-iframe-wrapper');
if (iframeWrapper) {
const builderIframe = iframeWrapper.querySelector('iframe#bricks-builder-iframe');
if (builderIframe) {
builderIframe.style.height = '';
}
}
}
});
});
});
// Start observing
mainObserver.observe(targetElement, {
childList: true, // Watch for direct children changes
subtree: true // Watch all descendants
});
return true;
} else {
return false;
}
};
// Toggle function
window.toggleMoveStickyCSS = () => {
isEnabled = !isEnabled;
localStorage.setItem(STORAGE_KEY, isEnabled);
// Update button state
const button = document.querySelector('.brxc-item[data-balloon="Move Sticky CSS"]');
if (button) {
if (isEnabled) {
button.classList.add('active');
// If sticky CSS already exists, move it immediately
const stickyElement = document.querySelector('#brxc-sticky-css');
if (stickyElement) {
const iframeWrapper = document.querySelector('#bricks-builder-iframe-wrapper');
if (iframeWrapper && !iframeWrapper.contains(stickyElement)) {
iframeWrapper.appendChild(stickyElement);
// Inject CSS
const styleId = 'brxc-sticky-custom-styles';
if (!document.getElementById(styleId)) {
const style = document.createElement('style');
style.id = styleId;
style.textContent = `
#brxc-sticky-css .brxc-action {
color: var(--builder-color-accent) !important;
fill: var(--builder-color-accent) !important;
}
`;
document.head.appendChild(style);
}
const builderIframe = iframeWrapper.querySelector('iframe#bricks-builder-iframe');
if (builderIframe) {
const updateIframeHeight = () => {
const stickyCssHeight = stickyElement.offsetHeight;
builderIframe.setAttribute('style', `height: calc(100% - ${stickyCssHeight + 7}px);`);
};
updateIframeHeight();
const resizeObserver = new ResizeObserver(() => {
updateIframeHeight();
});
resizeObserver.observe(stickyElement);
const styleObserver = new MutationObserver(() => {
updateIframeHeight();
});
styleObserver.observe(stickyElement, {
attributes: true,
attributeFilter: ['style']
});
}
}
}
} else {
button.classList.remove('active');
}
}
// If disabling, move sticky CSS back to original location
if (!isEnabled) {
cleanupObservers();
const stickyElement = document.querySelector('#brxc-sticky-css');
const originalContainer = document.querySelector('#bricks-structure main #brxcStructureBottomContainer');
const iframeWrapper = document.querySelector('#bricks-builder-iframe-wrapper');
const builderIframe = iframeWrapper?.querySelector('iframe#bricks-builder-iframe');
// Reset iframe BEFORE moving element
if (builderIframe) {
builderIframe.removeAttribute('style');
}
// Then move element back
if (stickyElement && originalContainer && !originalContainer.contains(stickyElement)) {
originalContainer.appendChild(stickyElement);
}
// Reset iframe again AFTER moving element (in case something triggered)
setTimeout(() => {
if (builderIframe) {
builderIframe.removeAttribute('style');
}
}, 100);
}
};
// Try to set up observer immediately
if (!setupObserver()) {
// If not ready, wait for DOM and try again
document.addEventListener('DOMContentLoaded', () => {
if (!setupObserver()) {
// If still not ready, wait for full load
window.addEventListener('load', () => {
setTimeout(() => {
setupObserver();
}, 500);
});
}
});
}
// Add custom button to panel header
const addPanelButton = () => {
const panelActions = document.querySelector('#bricks-structure #bricks-panel-header .actions');
// Check if Sticky CSS button exists and is active
const stickyCssButton = panelActions?.querySelector('[data-balloon="Sticky CSS"]');
if (!stickyCssButton || !stickyCssButton.classList.contains('active')) {
return; // Don't show our button if Sticky CSS is not active
}
if (panelActions && !document.querySelector('.brxc-item[data-balloon="Move Sticky CSS"]')) {
const li = document.createElement('li');
li.className = isEnabled ? 'brxc-item active' : 'brxc-item';
li.setAttribute('data-balloon', 'Move Sticky CSS');
li.setAttribute('data-balloon-pos', 'bottom');
li.onclick = () => window.toggleMoveStickyCSS();
li.innerHTML = `<span class="bricks-svg-wrapper"><svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill:currentColor;fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2" viewBox="0 0 24 24"><path d="M3.495 1.754c-.21 0-.42.072-.56.199a.51.51 0 0 0-.18.471l2 13.555c.03.232.23.423.51.495l6 1.595c.14.04.3.04.44 0l7-1.595c.29-.064.5-.263.54-.502l2-13.556a.52.52 0 0 0-.18-.471.85.85 0 0 0-.56-.199h-17zm4 3.19c-.41 0-.75.271-.75.598s.34.598.75.598h5.98l-5.83 2.464c-.3.127-.46.406-.38.669.08.264.38.455.73.455h7.17l-.37 2.926-2.8.638-2.8-.638-.15-1.188c-.04-.327-.41-.566-.82-.534s-.71.327-.67.654l.2 1.595c.03.239.24.446.54.518l3.5.797c.14.032.28.032.41 0l3.5-.797c.3-.064.51-.271.54-.518l.5-3.987a.54.54 0 0 0-.19-.463.83.83 0 0 0-.56-.199h-4.98l5.83-2.464c.3-.128.46-.407.38-.67s-.38-.454-.73-.454z" style="fill:currentColor"/><path d="M3.597 21.62a1 1 0 0 1 0-2h16.217a1 1 0 0 1 0 2z"/></svg></span>`;
panelActions.appendChild(li);
}
};
// Try to add button after a delay to ensure panel is loaded
setTimeout(addPanelButton, 1000);
// Also try on window load as fallback
window.addEventListener('load', () => {
setTimeout(addPanelButton, 500);
});
// Watch for changes to the Sticky CSS button to show/hide our button
const watchStickyCssButton = () => {
const panelActions = document.querySelector('#bricks-structure #bricks-panel-header .actions');
if (!panelActions) {
// Retry if panel not found
setTimeout(watchStickyCssButton, 500);
return;
}
const checkAndUpdateButton = () => {
const ourButton = document.querySelector('.brxc-item[data-balloon="Move Sticky CSS"]');
const stickyCssButton = panelActions.querySelector('[data-balloon="Sticky CSS"]');
if (stickyCssButton && stickyCssButton.classList.contains('active')) {
if (!ourButton) {
addPanelButton();
}
} else {
if (ourButton) {
ourButton.remove();
}
// Reset everything when Sticky CSS button is toggled off
const stickyElement = document.querySelector('#brxc-sticky-css');
const originalContainer = document.querySelector('#bricks-structure main #brxcStructureBottomContainer');
const iframeWrapper = document.querySelector('#bricks-builder-iframe-wrapper');
// Move sticky element back to original location if it was moved
if (stickyElement && originalContainer && !originalContainer.contains(stickyElement)) {
originalContainer.appendChild(stickyElement);
}
// Reset iframe height to 100%
if (iframeWrapper) {
const builderIframe = iframeWrapper.querySelector('iframe#bricks-builder-iframe');
if (builderIframe) {
builderIframe.removeAttribute('style');
}
}
// Also disable our toggle if it was enabled
if (isEnabled) {
isEnabled = false;
localStorage.setItem(STORAGE_KEY, 'false');
}
}
};
// Watch for any mutations in the panel actions area
const observer = new MutationObserver(() => {
checkAndUpdateButton();
});
observer.observe(panelActions, {
attributes: true,
childList: true,
subtree: true,
attributeFilter: ['class']
});
// Also check initially
checkAndUpdateButton();
// Periodically check as backup (in case mutation observer misses something)
setInterval(checkAndUpdateButton, 2000);
};
setTimeout(watchStickyCssButton, 1000);
window.addEventListener('load', () => {
setTimeout(watchStickyCssButton, 500);
});
// YOUR OTHER CODE HERE (runs in editor)
} else {
// YOUR FRONTEND CODE HERE
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment