Civitai Model Versions Wraparound + Search + Sort

Wraps CivitAI versions into multiple rows, adds a search bar, and allows for sorting alphabetically.

目前为 2025-02-21 提交的版本。查看 最新版本

// ==UserScript==
// @name         Civitai Model Versions Wraparound + Search + Sort
// @version      0.2.0
// @description  Wraps CivitAI versions into multiple rows, adds a search bar, and allows for sorting alphabetically.
// @author       RedTvpe
// @match        https://civitai.com/models/*
// @grant        none
// @namespace https://gf.qytechs.cn/users/1418032
// ==/UserScript==

(function () {
    'use strict';

    // Inject our controls (search, sort, and counter) above the versions container
    function injectControls(container) {
        // Prevent duplicate insertion
        if (document.getElementById('versionControls')) return;

        // Create a control panel
        const controlPanel = document.createElement('div');
        controlPanel.id = 'versionControls';
        controlPanel.style.marginBottom = '10px';

        // Version counter
        const versionCountLabel = document.createElement('span');
        versionCountLabel.style.marginRight = '15px';
        versionCountLabel.style.fontWeight = 'bold';
        versionCountLabel.textContent = `Total Versions: ${container.children.length}`;

        // Search input
        const searchInput = document.createElement('input');
        searchInput.type = 'text';
        searchInput.placeholder = 'Search versions...';
        searchInput.style.marginRight = '10px';

        // Sort buttons
        const sortAscBtn = document.createElement('button');
        sortAscBtn.textContent = 'Sort A–Z';
        sortAscBtn.style.marginRight = '5px';

        const sortDescBtn = document.createElement('button');
        sortDescBtn.textContent = 'Sort Z–A';

        // Append everything to the control panel
        controlPanel.appendChild(versionCountLabel);
        controlPanel.appendChild(searchInput);
        controlPanel.appendChild(sortAscBtn);
        controlPanel.appendChild(sortDescBtn);

        // Insert the control panel before the versions container
        container.parentNode.insertBefore(controlPanel, container);

        // Implement search filter
        searchInput.addEventListener('input', function () {
            const query = searchInput.value.toLowerCase();
            const items = container.children;
            Array.from(items).forEach(item => {
                const text = item.textContent.toLowerCase();
                // Show/hide based on whether text includes the query
                item.style.display = text.includes(query) ? '' : 'none';
            });
        });

        // Implement sort
        sortAscBtn.addEventListener('click', function () {
            sortVersions('asc');
        });
        sortDescBtn.addEventListener('click', function () {
            sortVersions('desc');
        });
    }

    // Sort the version items within the container
    function sortVersions(order) {
        const container = document.querySelector('.mantine-ScrollArea-viewport .mantine-Group-root');
        if (!container) return;

        // Convert HTMLCollection to an array
        const items = Array.from(container.children);
        items.sort((a, b) => {
            const aText = a.textContent.trim().toLowerCase();
            const bText = b.textContent.trim().toLowerCase();
            if (aText < bText) return order === 'asc' ? -1 : 1;
            if (aText > bText) return order === 'asc' ? 1 : -1;
            return 0;
        });
        // Re-append in sorted order
        items.forEach(item => container.appendChild(item));
    }

    // Apply the layout fix and insert controls
    function adjustLayout() {
        // Select the container that holds the model versions
        const scrollArea = document.querySelector('.mantine-ScrollArea-viewport .mantine-Group-root');
        if (scrollArea) {
            // Make versions wrap into rows
            scrollArea.style.display = 'flex';
            scrollArea.style.flexWrap = 'wrap';
            scrollArea.style.gap = '8px';
            scrollArea.style.overflowX = 'visible';

            // Insert our search/sort/counter panel
            injectControls(scrollArea);
        }
    }

    // Watch for dynamic content changes
    const observer = new MutationObserver((mutations) => {
        for (const mutation of mutations) {
            if (mutation.addedNodes.length > 0) {
                adjustLayout();
            }
        }
    });

    // Observe the body for changes
    const targetNode = document.querySelector('body');
    if (targetNode) {
        observer.observe(targetNode, { childList: true, subtree: true });
    }

    // Run once on load
    adjustLayout();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址