Last active
February 27, 2023 16:33
-
-
Save KevinBatdorf/322c68f532af6a4cc6773f906da0684d to your computer and use it in GitHub Desktop.
This Gist lets you download the Alpine version of TailwindUI components
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Download AlpineJs version from Tailwind UI | |
// @namespace kevinbatdorf | |
// @version 1.0 | |
// @description When you press copy, it will download an html file containing the script code and alpine HTML | |
// @author https://twitter.com/kevinbatdorf | |
// @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 | |
// Copy versio: https://gist.github.com/KevinBatdorf/8bd5f808fff6a59e100dfa08a7431822 | |
// 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(); | |
let fileName | |
try { | |
fileName = event.target.closest('[id^=component-]').querySelector('h2').textContent.trim().toLowerCase().replace(/[^a-z0-9_]+/gi, '-'); | |
} catch(e) { | |
fileName = 'tailwind-alpine' | |
} | |
const content = scripts ? `<script>${scripts}</script>` + markup : markup; | |
const link = document.createElement('a'); | |
link.download = `${fileName}.html`; | |
link.href = window.URL.createObjectURL(new Blob([content], {type: 'text/html'})); | |
link.click(); | |
}); | |
node.removeAttribute('@click'); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Copy to clipboard version here: https://gist.github.com/KevinBatdorf/8bd5f808fff6a59e100dfa08a7431822
That version has issues copying large components, so this one is probably preferred. You can use them both and toggle them as needed: