Skip to content

Instantly share code, notes, and snippets.

@shelllee
Last active April 18, 2026 10:03
Show Gist options
  • Select an option

  • Save shelllee/88d6d48ba671101a63e5177fe127ffb4 to your computer and use it in GitHub Desktop.

Select an option

Save shelllee/88d6d48ba671101a63e5177fe127ffb4 to your computer and use it in GitHub Desktop.
Unity Asset Store Wishlist Tag Filter
// ==UserScript==
// @name Unity Asset Store Wishlist Tag Filter
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Add search box to Unity Asset Store collection dialog for quick filtering
// @author You
// @match https://assetstore.unity.com/*
// @grant none
// @run-at document-idle
// ==/UserScript==
(function () {
'use strict';
const STYLE_ID = 'ua-collection-search-style';
const INPUT_ID = 'ua-collection-search-input';
function injectStyle() {
if (document.getElementById(STYLE_ID)) return;
const style = document.createElement('style');
style.id = STYLE_ID;
style.textContent = `
.ua-search-wrap {
padding: 8px 16px;
position: relative;
}
.ua-search-wrap input {
width: 100%;
box-sizing: border-box;
padding: 8px 12px 8px 32px;
border: 1px solid #555;
border-radius: 6px;
background: #2a2a2a;
color: #eee;
font-size: 14px;
outline: none;
transition: border-color 0.2s;
}
.ua-search-wrap input:focus {
border-color: #4a90d9;
}
.ua-search-wrap input::placeholder {
color: #888;
}
.ua-search-wrap .ua-search-icon {
position: absolute;
left: 26px;
top: 50%;
transform: translateY(-50%);
color: #888;
font-size: 14px;
pointer-events: none;
}
.ua-search-count {
padding: 4px 16px 0;
font-size: 12px;
color: #888;
display: none;
}
.ua-search-count.visible {
display: block;
}
.ua-collection-hidden {
display: none !important;
}
`;
document.head.appendChild(style);
}
function createSearchUI(container) {
// Already injected
if (document.getElementById(INPUT_ID)) return;
// Find the scrollable collection list
const scrollable = container.querySelector('.modal-inner-scrollable');
if (!scrollable) return;
// Build search input wrapper
const wrap = document.createElement('div');
wrap.className = 'ua-search-wrap';
const icon = document.createElement('span');
icon.className = 'ua-search-icon';
icon.textContent = '\u{1F50D}';
const input = document.createElement('input');
input.id = INPUT_ID;
input.type = 'text';
input.placeholder = 'Search collections...';
// Match count display
const countEl = document.createElement('div');
countEl.className = 'ua-search-count';
wrap.appendChild(icon);
wrap.appendChild(input);
scrollable.parentElement.insertBefore(wrap, scrollable);
scrollable.parentElement.insertBefore(countEl, scrollable);
// Filter collections on input
input.addEventListener('input', () => {
const keyword = input.value.trim().toLowerCase();
const items = scrollable.querySelectorAll('._3bUE8');
let visibleCount = 0;
let totalCount = 0;
items.forEach(item => {
totalCount++;
const nameEl = item.querySelector('._1irTB');
const name = nameEl ? nameEl.textContent.toLowerCase() : '';
if (!keyword || name.includes(keyword)) {
item.classList.remove('ua-collection-hidden');
visibleCount++;
} else {
item.classList.add('ua-collection-hidden');
}
});
if (keyword) {
countEl.textContent = `${visibleCount} / ${totalCount} collections`;
countEl.classList.add('visible');
} else {
countEl.classList.remove('visible');
}
});
// Auto focus the search input
setTimeout(() => input.focus(), 100);
}
function cleanup() {
const existing = document.getElementById(INPUT_ID);
if (existing) {
existing.closest('.ua-search-wrap')?.remove();
}
const countEl = document.querySelector('.ua-search-count');
if (countEl) countEl.remove();
// Restore all hidden collection items
document.querySelectorAll('.ua-collection-hidden').forEach(el => {
el.classList.remove('ua-collection-hidden');
});
}
// Watch for the "add to list" dialog appearing
function init() {
injectStyle();
const observer = new MutationObserver(mutations => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (!(node instanceof HTMLElement)) continue;
// Check if the "add to list" dialog appeared
if (
node.querySelector?.('[aria-labelledby="add-to-list-title"]') ||
node.querySelector?.('.modal-inner-scrollable')
) {
setTimeout(() => createSearchUI(node), 150);
return;
}
// Check if the node itself is the dialog
if (
node.getAttribute?.('aria-labelledby') === 'add-to-list-title' ||
node.classList?.contains('modal-inner-scrollable')
) {
setTimeout(() => createSearchUI(node.closest('[role="dialog"]') || node), 150);
return;
}
}
// Cleanup when dialog is removed
for (const node of mutation.removedNodes) {
if (!(node instanceof HTMLElement)) continue;
if (node.querySelector?.('.modal-inner-scrollable')) {
cleanup();
return;
}
}
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
// Handle case where dialog is already open when script loads
function checkExisting() {
const dialog = document.querySelector('[aria-labelledby="add-to-list-title"]');
if (dialog && !document.getElementById(INPUT_ID)) {
createSearchUI(dialog);
}
}
if (document.readyState === 'complete') {
init();
checkExisting();
} else {
window.addEventListener('load', () => {
init();
checkExisting();
});
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment