|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Gradio Icon Gallery</title> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
<style> |
|
|
|
|
|
::-webkit-scrollbar { width: 8px; } |
|
|
::-webkit-scrollbar-track { background: #1f2937; } |
|
|
::-webkit-scrollbar-thumb { background: #4b5563; border-radius: 4px; } |
|
|
::-webkit-scrollbar-thumb:hover { background: #6b7280; } |
|
|
|
|
|
.icon-container > svg { |
|
|
animation: none !important; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="bg-gray-900 text-gray-200 font-sans"> |
|
|
|
|
|
<div id="app" class="container mx-auto p-4 md:p-8"> |
|
|
<header class="text-center mb-8"> |
|
|
<h1 class="text-4xl font-bold text-white">Gradio Icon Gallery</h1> |
|
|
<p class="text-gray-400 mt-2">Browse and search all available icons from <code class="bg-gray-700 text-orange-400 px-2 py-1 rounded">@gradio/icons</code>.</p> |
|
|
</header> |
|
|
|
|
|
<div class="sticky top-4 z-10 mb-8"> |
|
|
<input |
|
|
type="text" |
|
|
id="search-input" |
|
|
placeholder="Search for an icon (e.g., 'Check', 'Download')..." |
|
|
class="w-full p-3 bg-gray-800 border border-gray-700 rounded-lg text-white focus:ring-2 focus:ring-orange-500 focus:outline-none transition" |
|
|
> |
|
|
</div> |
|
|
|
|
|
<div id="icon-grid" class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8 gap-4"> |
|
|
|
|
|
<div id="loading-message" class="col-span-full text-center py-10"> |
|
|
<p class="text-lg">Fetching icons from CDN...</p> |
|
|
<p class="text-sm text-gray-500">This may take a moment.</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<script type="module"> |
|
|
|
|
|
const ICON_NAMES = [ |
|
|
"ArrowDown", "ArrowUp", "Back", "Backward", "Brush", "BrushSize", "Calendar", |
|
|
"Camera", "Chart", "Chat", "Check", "Circle", "Clear", "Code", "Color", |
|
|
"ColorPickerSolid", "Community", "Copy", "Crop", "Download", "DropdownArrow", |
|
|
"DropdownCircularArrow", "Edit", "Erase", "Error", "Eyedropper", "File", |
|
|
"Forward", "Image", "ImagePaste", "ImageResize", "Info", "JSON", "Layers", |
|
|
"LineChart", "Maximise", "Maximize", "Microphone", "Minimize", "Music", |
|
|
"Palette", "Pan", "Paperclip", "Pause", "Play", "Plot", "Plus", "Redo", |
|
|
"Remove", "Resize", "Retry", "Rotate", "ScrollDownArrow", "Send", "Settings", |
|
|
"Sketch", "Spinner", "Square", "Success", "Table", "TextHighlight", "Trash", |
|
|
"Tree", "Trim", "Undo", "Upload", "Video", "Visibility", "VisibilityOff", |
|
|
"VolumeHigh", "VolumeLow", "VolumeMuted", "Warning", "Webcam", "ZoomIn", "ZoomOut" |
|
|
].sort(); |
|
|
|
|
|
const iconGrid = document.getElementById('icon-grid'); |
|
|
const searchInput = document.getElementById('search-input'); |
|
|
const loadingMessage = document.getElementById('loading-message'); |
|
|
|
|
|
let allIconData = []; |
|
|
|
|
|
function renderIcons(filter = '') { |
|
|
iconGrid.innerHTML = ''; |
|
|
const lowerCaseFilter = filter.toLowerCase(); |
|
|
|
|
|
const filteredIcons = allIconData.filter(icon => |
|
|
icon.name.toLowerCase().includes(lowerCaseFilter) |
|
|
); |
|
|
|
|
|
if (filteredIcons.length === 0) { |
|
|
iconGrid.innerHTML = `<div class="col-span-full text-center py-10"><p class="text-lg">No icons found for "${filter}"</p></div>`; |
|
|
} |
|
|
|
|
|
filteredIcons.forEach(iconData => { |
|
|
const card = document.createElement('div'); |
|
|
card.className = "flex flex-col items-center justify-center p-4 bg-gray-800 rounded-lg border border-gray-700 hover:bg-gray-700 hover:border-orange-500 transition cursor-pointer"; |
|
|
|
|
|
const iconContainer = document.createElement('div'); |
|
|
iconContainer.className = "w-10 h-10 mb-3 text-white icon-container"; |
|
|
|
|
|
iconContainer.innerHTML = iconData.svgString; |
|
|
|
|
|
const nameLabel = document.createElement('p'); |
|
|
nameLabel.className = "text-sm text-center font-mono break-all"; |
|
|
nameLabel.textContent = iconData.name; |
|
|
|
|
|
card.appendChild(iconContainer); |
|
|
card.appendChild(nameLabel); |
|
|
|
|
|
card.addEventListener('click', () => { |
|
|
const textToCopy = `<${iconData.name} />`; |
|
|
navigator.clipboard.writeText(textToCopy).then(() => { |
|
|
const originalText = nameLabel.textContent; |
|
|
nameLabel.textContent = "Copied!"; |
|
|
nameLabel.classList.add('text-green-400'); |
|
|
setTimeout(() => { |
|
|
nameLabel.textContent = originalText; |
|
|
nameLabel.classList.remove('text-green-400'); |
|
|
}, 1500); |
|
|
}); |
|
|
}); |
|
|
|
|
|
iconGrid.appendChild(card); |
|
|
}); |
|
|
} |
|
|
|
|
|
async function init() { |
|
|
try { |
|
|
|
|
|
const fetchPromises = ICON_NAMES.map(name => |
|
|
fetch(`https://cdn.jsdelivr.net/npm/@gradio/[email protected]/src/${name}.svelte`) |
|
|
.then(response => { |
|
|
if (!response.ok) { |
|
|
throw new Error(`HTTP error! status: ${response.status} for ${name}`); |
|
|
} |
|
|
return response.text(); |
|
|
}) |
|
|
); |
|
|
|
|
|
const loadedSvgStrings = await Promise.all(fetchPromises); |
|
|
|
|
|
allIconData = ICON_NAMES.map((name, index) => ({ |
|
|
name: name, |
|
|
svgString: loadedSvgStrings[index] |
|
|
})); |
|
|
|
|
|
} catch (error) { |
|
|
loadingMessage.innerHTML = `<p class="text-red-400">Failed to load icons. Check the browser console for details.</p>`; |
|
|
console.error("Error fetching Gradio icons:", error); |
|
|
return; |
|
|
} |
|
|
|
|
|
loadingMessage.style.display = 'none'; |
|
|
renderIcons(); |
|
|
|
|
|
searchInput.addEventListener('input', (e) => { |
|
|
renderIcons(e.target.value); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
init(); |
|
|
|
|
|
</script> |
|
|
</body> |
|
|
</html> |