I wanted to be able to download all the Vercel Geist icons however I didn't see an option to do this on the page (may exist now of course). I decided to write my own script in the browser to do it for me.
If you're using Chrome and want follow along with this you'll need to enable pasting within the console otherwise you'll be hit with a warning.
Browser consoleallow pastingTo start I identified the svg element of the icon them gathered them all with a node list.
Browser consoleconst allIcons = document.querySelectorAll("div[class='-mt-1.5'] > div > svg");I thought I would experiment and start with one. I want to target the outerHtml property of the first element in the node list. This will give me the .svg as a string.
Browser consoleconst newIcon = allIcons[0].outerHTML;Then we need to create a function that turns our Icon into a file. This will allow us to use it as an object we can download from the browser.
Furthermore we'll need to programmatically enable the download of this file by creating an a element and setting some of it's attributes.
Browser consolefunction downloadBlob(dataFile, filename) {
//Create the blob of the SVG file
const file = new File([dataFile], "icon.svg", {
type: "image/svg+xml",
});
// Create an object URL for the blob object
const url = URL.createObjectURL(file);
// Create a new anchor element
const a = document.createElement('a');
// Set the href and download attributes for the anchor element
a.href = url;
a.download = filename || 'download';
// Click handler that releases the object URL after the element has been clicked
// This is required for one-off downloads of the blob content
const clickHandler = () => {
setTimeout(() => {
URL.revokeObjectURL(url);
removeEventListener('click', clickHandler);
}, 150);
};
// Return the anchor element
return a;
}We return the new a from the function using the passed dataFile and fileName arguments.
Browser consoleconst newLink = downloadBlob(file, "test.svg");As we how have an element that is usable within the DOM we can simulate a click on our returned a element.
Browser consolenewLink.click()Re-using our function from before I want to target the outer divs of the svgs so that we can determine the right name for the downloaded files.
Browser consoleconst allIconGroups = document.querySelectorAll("div[class='hover:bg-background-100 flex h-28 w-full cursor-pointer flex-col items-center rounded px-4 text-gray-900']")I then need to turn the node list into an array to be able to iterate over it.
Browser consoleconst iconGroupArr = Array.from(allIconGroups)This works. Chrome (and other browsers) have a max sequential download limit of 10 within a second, I create a small 1 second wait after each 10 are downloaded so as not to be blocked by the browser.
Browser console
function download(el) {
const name = el.querySelector('p').innerHTML;
const svgText = el.querySelector("div[class='-mt-1.5'] > div > svg").outerHTML;
const file = new File([svgText], name+".svg", {
type: "image/svg+xml",
});
// Create an object URL for the blob object
const url = URL.createObjectURL(file);
// Create a new anchor element
const a = document.createElement('a');
// Set the href and download attributes for the anchor element
a.href = url;
a.download = name || 'download';
// Click handler that releases the object URL after the element has been clicked
// This is required for one-off downloads of the blob content
const clickHandler = () => {
setTimeout(() => {
URL.revokeObjectURL(url);
removeEventListener('click', clickHandler);
}, 150);
};
// Add the click event listener on the anchor element
a.addEventListener('click', clickHandler, false);
a.click();
}
function pause(msec) {
return new Promise(
(resolve, reject) => {
setTimeout(resolve, msec || 1000);
}
);
}
async function downloadAll(elements) {
var count = 0;
for (var e in elements) {
download(elements[e]);
if (++count >= 10) {
await pause(1000);
count = 0;
}
}
}I then call my function with the array of icons to download them all. It may take ~30 seconds.
Browser consoledownloadAll(iconGroupArr);I hope this was useful!