Skip to content

Instantly share code, notes, and snippets.

@KevinBatdorf
Last active October 23, 2024 09:21
Show Gist options
  • Save KevinBatdorf/8bd5f808fff6a59e100dfa08a7431822 to your computer and use it in GitHub Desktop.
Save KevinBatdorf/8bd5f808fff6a59e100dfa08a7431822 to your computer and use it in GitHub Desktop.
Auto copy the Alpine code from Tailwind UI's copy button
// ==UserScript==
// @name Add AlpineJs to Tailwind UI
// @namespace http://tampermonkey.net/
// @version 3.0
// @description Add Alpine JS code to Tailwind Ui copy/paste
// @author https://gist.github.com/KevinBatdorf/8bd5f808fff6a59e100dfa08a7431822
// @match https://tailwindui.com/components/*
// @grant none
// ==/UserScript==
// Requires Tampermonkey
// Chrome - https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo?hl=en
// FF - https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/
// Find me on Twitter: https://twitter.com/kevinbatdorf
// Get the version that downloads the code into a file here:
// https://gist.github.com/KevinBatdorf/322c68f532af6a4cc6773f906da0684d
// If it seems to not be working, check the classes here are matching
const code = Array.from(document.querySelectorAll('button')).filter(
b => b.classList.value === 'group relative ml-2 hidden h-9 w-9 items-center justify-center sm:flex'
);
code.forEach(node => {
node.addEventListener('click', function(event) {
event.preventDefault();
// This is the iFrame the component is in
const iFrame = event.target.closest('[id^=component-]').querySelector('[name][id^=frame]');
const contentArea = iFrame.contentWindow.document.querySelector('body > div');
const markup = contentArea.innerHTML;
// This will attempt to extract the function used in the x-data, like x-data="Component.popover"
const scripts = Array.from(contentArea.querySelectorAll('[x-data]'))
.filter((n) => /\(.*\)/.test(n.getAttribute('x-data').toString()))
.map((n) => {
const fnNameSplit = n
.getAttribute('x-data')
.replace('window.', '')
.replace(/\(.*\)/, '')
.split('.');
// We need to get the string representation of the method
const method = new Function(`return ${iFrame.contentWindow[fnNameSplit[0]][fnNameSplit[1]]};`);
// This adds checks to create the global object then register it.
return `
window.${fnNameSplit[0]} = window.${fnNameSplit[0]} ?? {}
window.${fnNameSplit[0]}['${fnNameSplit[1]}'] = ${method}()
`
})
.join(';')
.toString();
const textarea = document.createElement('textarea');
textarea.textContent = scripts ? `<script>${scripts}</script>` + markup : markup;
document.body.appendChild(textarea);
setTimeout(() => {
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
}, 50);
})
})
@KevinBatdorf
Copy link
Author

Can you share a component it's not working on? I tried it on the hero sections and a few others and it's working

Screen Shot 2023-02-01 at 10 38 11 AM

@KevinBatdorf
Copy link
Author

Just got it to work on a modal component. It seems spotty in what it can extract.

Saw this after I commented. I can try to see why some aren't working. It could be they changed something.

@ovp87
Copy link

ovp87 commented Feb 6, 2023

@KevinBatdorf Kudos for still maintaining this 👍

@aitoehigie
Copy link

It no longer seems to work?

@KevinBatdorf
Copy link
Author

@aitoehigie I just tried it on a dropdown and it worked. Which componen isn't working?

@morgler
Copy link

morgler commented May 7, 2024

I can confirm, it worked for me on the full Application UI Sidebar layout

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment