Custom search and highlighting aka (Ctrl+F)

search and highlight tool

As of 2025-11-01. See the latest version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name           Custom search and highlighting aka (Ctrl+F)
// @namespace      http://tampermonkey.net/
// @version        2025-10-31.1.33
// @description    search and highlight  tool
// @author         kr6r5kugkkgk
// @match          *://*/*
// @license        MIT
// @run-at         document-idle
// @icon           https://i.pinimg.com/originals/79/09/89/7909897ceea2691e5a4942766c678ff3.png
// ==/UserScript==


(function() {
    'use strict';
    // Переменные для функционала
    let matches = [];
    let currentIndex = -1;
    // Переменные для настроек подсветки (по умолчанию)
    let settings = {
        highlightDefaultBg: 'rgb(52, 22, 86)',
        highlightCurrentBg: 'rgb(179, 117, 238)',
        highlightTextColor: 'rgb(232, 248, 101)',
        highlightBorderColor: 'rgb(139, 248, 194)',
        highlightBorderRadius: 12,
        highlightBorderThickness: 2,
        highlightDefaultOpacity: 0.8,  // Новое: прозрачность для обычного фона (0-1)
        highlightCurrentOpacity: 1.0,  // Новое: прозрачность для текущего фона (0-1)
        highlightPadding: 5 , 
        lang: 'ru'
 // Новое: padding в px для mark
    };
    const translations = {
    ru: {
        toggleTooltip: 'Свернуть/развернуть поисковую панель',
        searchPlaceholder: 'Поиск по странице...',
        settingsTitle: 'Настройки подсветки',
        defaultBg: 'Цвет фона (обычный):',
        defaultOpacity: 'Прозрачность обычного фона (0-1):',
        currentBg: 'Цвет фона (текущий):',
        currentOpacity: 'Прозрачность текущего фона (0-1):',
        textColor: 'Цвет текста:',
        borderColor: 'Цвет бордера:',
        borderRadius: 'Скругление (px):',
        borderThickness: 'Толщина бордера (px):',
        padding: 'Padding (px):',
        save: 'Сохранить',
        cancel: 'Отмена',
        lang: 'Язык интерфейса:'
    },
    en: {
        toggleTooltip: 'Toggle search-wrapper-panel' ,
        searchPlaceholder: 'Search page...',
        settingsTitle: 'Highlight settings',
        defaultBg: 'Default background:',
        defaultOpacity: 'Default opacity (0-1):',
        currentBg: 'Current background:',
        currentOpacity: 'Current opacity (0-1):',
        textColor: 'Text color:',
        borderColor: 'Border color:',
        borderRadius: 'Border radius (px):',
        borderThickness: 'Border thickness (px):',
        padding: 'Padding (px):',
        save: 'Save',
        cancel: 'Cancel',
        lang: 'Interface language:'
    }
};

    // Загрузка настроек из localStorage, если есть
    const savedSettings = localStorage.getItem('pageSearcherSettings');
    if (savedSettings) {
        const parsed = JSON.parse(savedSettings);
        settings = { ...settings, ...parsed };
    }
     // Функция для конвертации rgb в rgba с opacity
    function rgbToRgba(rgb, opacity) {
        if (rgb.startsWith('rgb(')) {
            const [r, g, b] = rgb.match(/\d+/g).map(Number);
            return `rgba(${r}, ${g}, ${b}, ${opacity})`;
        }
        return rgb;
    }
    // Функция применения настроек к существующим подсветкам
   function applySettings() {
        // Применяем к существующим matches
        matches.forEach((mark, i) => {
            if (!mark) return;
            const isCurrent = i === currentIndex;
            mark.style.color = settings.highlightTextColor;
            mark.style.border = `${settings.highlightBorderThickness}px solid ${settings.highlightBorderColor}`;
            mark.style.borderRadius = `${settings.highlightBorderRadius}px`;
            mark.style.padding = `${settings.highlightPadding}px`;
            mark.style.backgroundColor = rgbToRgba(
                isCurrent ? settings.highlightCurrentBg : settings.highlightDefaultBg,
                isCurrent ? settings.highlightCurrentOpacity : settings.highlightDefaultOpacity
            );
        });
        // Сохранение в localStorage
        localStorage.setItem('pageSearcherSettings', JSON.stringify(settings));
    }
    //===== Создание wrapper 
    const wrapper = document.createElement('div');
    wrapper.id = 'modifiedcstm-page-searcher-wrapper-r6ujr5jre5';
    wrapper.style.cssText = `
        position: fixed;
        top: 10px;
        right: 10px;
        z-index: 999999 !important;
        display: flex;
        flex-direction: column;
        gap: 2px;
    `;
      //===== Кнопка сворачивания (всегда видна)
    const btnToggle = document.createElement('button');
    btnToggle.id = 'searche4nmx7hjn-toggle8nme5h-btnjre6';
    btnToggle.style.cssText  = ` 
               width: 30px;
               height: 30px;
               background: rgb(13, 61, 63);
               border: 1px solid rgb(139, 248, 194);
               border-radius: 5px;
               cursor: pointer;
               display: flex;
               align-items: center;
               justify-content: center;
               box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 10px;
               transition: background 0.3s;
               position: fixed;
               top: 1%;
               left: 58%;
               z-index: 999999 !important;
        `;
    // Обработчики для tooltip и клика
btnToggle.addEventListener('mouseenter', () => {
    tooltip.classList.add('show');
});
btnToggle.addEventListener('mouseleave', () => {
    tooltip.classList.remove('show');
});
btnToggle.addEventListener('click', () => {
    wrapper.classList.toggle('collapsed');
});

    const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    svg.setAttribute('viewBox', '0 0 24 24');
    svg.setAttribute('width', '16');
    svg.setAttribute('height', '16');
    svg.style.transition = 'transform 0.3s ease';
    const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    path.setAttribute('d', 'M7 10l5 5 5-5z');
    path.setAttribute('fill', 'rgb(139, 248, 194)');
    svg.appendChild(path);
    btnToggle.appendChild(svg);
    // Создание кастомного tooltip
    const tooltip = document.createElement('div');
    tooltip.id = 'customherjr6-tooltip-toggle';
    tooltip.textContent = translations[settings.lang].toggleTooltip || 'Свернуть/развернуть поиск';  // Текст из translations (добавьте ключ, если ещё не)
    tooltip.style.cssText = `
        position: absolute;
        bottom: -35px;  /* Позиция относительно кнопки: снизу */
        left: 50%;
        transform: translateX(-50%);
    `;
    btnToggle.appendChild(tooltip);  // Вставляем tooltip как дочерний элемент кнопки
    // Стили для анимации и скрытия (убрали стили для mark, так как теперь inline)
    const style = document.createElement('style');
    style.textContent = `
/* Кастомный tooltip для кнопки сворачивания */
#customherjr6-tooltip-toggle {
    position: absolute;
    background: rgb(13, 61, 63);
    color: rgb(139, 248, 194);
    padding: 3px 7px;
    border-radius: 5px;
    border: 1px solid rgb(139, 248, 194);
    font-size: 12px;
    font-family: Arial, sans-serif;
    white-space: nowrap;
    z-index: 999999 !important
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.3s ease, visibility 0.3s ease;
    pointer-events: none;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.43);
}
#customherjr6-tooltip-toggle.show {
    opacity: 1;
    visibility: visible;
    z-index: 999999 !important
}
#searche4nmx7hjn-toggle8nme5h-btnjre6:hover #customherjr6-tooltip-toggle {
    display: block;
}
 #modifiedcstm-page-searcher-wrapper-r6ujr5jre5.collapsed #modifiedcstm-page-search-container-r6ujr5jre5 {
       display: none !important;
 }
 #searche4nmx7hjn-toggle8nme5h-btnjre6:hover {
      background: rgb(20, 80, 82);
 }
 #modifiedcstm-page-searcher-wrapper-r6ujr5jre5.collapsed #searche4nmx7hjn-toggle8nme5h-btnjre6 svg {
      transform: rotate(180deg);
 }
 input#input-searcj-on-paggeweb-text {
    background: #1f2a2f !important;
    border: 2px solid #46968d !important;
    color: antiquewhite !important;
 }
 #modifiedcstm-page-search-container-r6ujr5jre5 {
    display: flex !important;
}
 #searcherUp-btnUp-5en8h4w5en8m {
    padding: 5px !important;
    background: rgb(20 29 43) !important;
    color: rgb(139, 248, 194) !important;
    border: 1px solid rgb(139, 248, 194) !important;
    border-radius: 3px !important;
    cursor: pointer !important;
    width: 28px !important;
    height: 28px !important;
}

#searcherDown-btnDown-5en8h4w5en8m {
    padding: 5px !important;
    background: rgb(20 29 43) !important;
    color: rgb(139, 248, 194) !important;
    border: 1px solid rgb(139, 248, 194) !important;
    border-radius: 3px !important;
    cursor: pointer !important;
    width: 28px !important;
    height: 28px !important;
}

 #searche4nmx7hjn-toggle8nme5h-btnjre6:hover,
#searcherUp-btnUp-5en8h4w5en8m:hover,
#closeSsearchWrapper-8n5e85egh8n-he5hedhe5d:hover,
#searcherDown-btnDown-5en8h4w5en8m:hover,
#settings-btnCstm-page-searcher:hover {
      background-color: rgb(39 118 117 / 96%) !important;
    transform: scale(1.3)  !important;
    transition: all 0.3s ease  !important;
    fill: #70f4a4 !important;
}
 #settingsuje-modalhjer5mr6f-for-webSeracherfor {
    background: rgb(13, 61, 63) !important;
    border: 1px solid rgb(139, 248, 194) !important;
    border-radius: 5px !important;
    padding: 20px !important;
    width: 300px !important;
    color:rgb(255, 254, 221) !important;
    font-family: Arial, sans-serif !important;
    position: absolute !important;
    top: 105px !important;
}

button#save-settings ,  
button#cancel-settings,   
input#current-opacity,   
input#default-opacity,   
input#padding, 
input#border-thickness,  
input#border-radius,   
input#border-color,   
input#text-color,   
input#current-bg, 
select#lang-select,
input#default-bg  {
    appearance: none !important;
    padding: 3px !important;
    background: rgb(20 29 43) !important;
    color: rgb(190 255 246) !important;
    border: 1px solid rgb(139, 248, 194) !important;
    border-radius: 5px !important;  
}

button#save-settings:hover, 
button#cancel-settings:hover,  
input#current-opacity:hover,  
input#default-opacity:hover,  
input#padding:hover,
input#border-thickness:hover, 
input#border-radius:hover,  
input#border-color:hover,  
input#text-color:hover,  
input#current-bg:hover, 
input#default-bg:hover {
    appearance: none !important; 
    background: rgb(52, 77, 85) !important;
    color: rgb(139, 248, 194) !important;
    border: 1px solid rgb(139, 248, 194) !important;
    border-radius: 5px !important; 
    scale: 1.5 !important; 
} 
 select#lang-select:hover {
    appearance: none !important; 
    background: rgb(52, 77, 85) !important;
    color: rgb(139, 248, 194) !important;
    border: 1px solid rgb(139, 248, 194) !important;
    border-radius: 3px !important;  
} 

    `;
    document.head.appendChild(style);
    // Создание контейнера (внутри wrapper)
    const container = document.createElement('div');
    container.id = 'modifiedcstm-page-search-container-r6ujr5jre5';
    container.style.cssText = `
        background: rgb(13, 61, 63);
        border: 1px solid rgb(139, 248, 194);
        border-radius: 5px;
        padding: 5px;
        display: flex;
        align-items: center;
        gap: 5px;
        font-family: Arial, sans-serif;
        font-size: 14px;
        box-shadow: 0 2px 10px rgba(0,0,0,0.2);
        position: relative;
        top: 45px;
        left: -150px;
    `;

    // Поле поиска
    const input = document.createElement('input');
    input.id = 'input-searcj-on-paggeweb-text';
    input.type = 'text';
    input.placeholder = translations[settings.lang].searchPlaceholder;

    input.style.cssText = 'padding: 5px; border: 1px solid #ccc; border-radius: 3px; width: 150px;';

      // Кнопки
    const btnNext = document.createElement('button');
    btnNext.id = 'searcherDown-btnDown-5en8h4w5en8m';
    btnNext.innerHTML = '↓';
    btnNext.style.cssText = 'padding: 5px; background: rgb(20 29 43); color: rgb(139, 248, 194); border: 1px solid rgb(139, 248, 194); border-radius: 3px; cursor: pointer; width: 28px; height: 28px;';

    const btnPrev = document.createElement('button');
    btnPrev.id = 'searcherUp-btnUp-5en8h4w5en8m';
    btnPrev.innerHTML = '↑';
    btnPrev.style.cssText = 'padding: 5px; background: rgb(20 29 43); color: rgb(139, 248, 194); border: 1px solid rgb(139, 248, 194); border-radius: 3px; cursor: pointer; width: 28px; height: 28px;';

    const btnClose = document.createElement('button');
     btnClose.id = 'closeSsearchWrapper-8n5e85egh8n-he5hedhe5d';
    btnClose.innerHTML = '×';
    btnClose.style.cssText = 'padding: 5px 8px; background: rgb(20 29 43); color: rgb(139, 248, 194); border: 1px solid rgb(139, 248, 194); border-radius: 3px; cursor: pointer; font-size: 16px; width: 28px; height: 28px;';

    // Кнопка настроек с SVG-иконкой шестеренки
    const btnSettings = document.createElement('button');
    btnSettings.id = 'settings-btnCstm-page-searcher';
    btnSettings.style.cssText = 'padding: 5px; background: rgb(20 29 43); color: rgb(139, 248, 194); border: 1px solid rgb(139, 248, 194); border-radius: 3px; cursor: pointer; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center;';

    const svgSettings = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    svgSettings.setAttribute('viewBox', '0 0 24 24');
    svgSettings.setAttribute('width', '16');
    svgSettings.setAttribute('height', '16');
    const pathSettings = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    pathSettings.setAttribute('d', 'M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.37-.29-.59-.22l-2.49.87c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-.87c-.23-.07-.47 0-.59.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.37.29.59.22l2.49-.87c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49.87c.23.07.47 0 .59-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z');
    pathSettings.setAttribute('fill', 'rgb(139, 248, 194)');
    svgSettings.appendChild(pathSettings);
    btnSettings.appendChild(svgSettings);

    // Обработчик для кнопки настроек
    btnSettings.addEventListener('click', () => {
        // Создание модального окна настроек
        const modal = document.createElement('div');
        modal.id = 'settings-modal-page-searcher';
        modal.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 999999;
        `;
        const modalContent = document.createElement('div');
        modalContent.id = 'settingsuje-modalhjer5mr6f-for-webSeracherfor';
        modalContent.style.cssText = `
            background: rgb(13, 61, 63);
            border: 1px solid rgb(139, 248, 194);
            border-radius: 5px;
            padding: 20px;
            width: 300px;
            color: antiquewhite;
            font-family: Arial, sans-serif;
        `;
       modalContent.innerHTML = `
    <h3>${translations[settings.lang].settingsTitle}</h3>

    <label>${translations[settings.lang].defaultBg}
        <input type="color" id="default-bg" value="${rgbToHex(settings.highlightDefaultBg)}">
    </label><br><br>

    <label>${translations[settings.lang].defaultOpacity}
        <input type="number" id="default-opacity" value="${settings.highlightDefaultOpacity}" min="0" max="1" step="0.1">
    </label><br><br>

    <label>${translations[settings.lang].currentBg}
        <input type="color" id="current-bg" value="${rgbToHex(settings.highlightCurrentBg)}">
    </label><br><br>

    <label>${translations[settings.lang].currentOpacity}
        <input type="number" id="current-opacity" value="${settings.highlightCurrentOpacity}" min="0" max="1" step="0.1">
    </label><br><br>

    <label>${translations[settings.lang].textColor}
        <input type="color" id="text-color" value="${rgbToHex(settings.highlightTextColor)}">
    </label><br><br>

    <label>${translations[settings.lang].borderColor}
        <input type="color" id="border-color" value="${rgbToHex(settings.highlightBorderColor)}">
    </label><br><br>

    <label>${translations[settings.lang].borderRadius}
        <input type="number" id="border-radius" value="${settings.highlightBorderRadius}" min="0" max="50">
    </label><br><br>

    <label>${translations[settings.lang].borderThickness}
        <input type="number" id="border-thickness" value="${settings.highlightBorderThickness}" min="1" max="10">
    </label><br><br>

    <label>${translations[settings.lang].padding}
        <input type="number" id="padding" value="${settings.highlightPadding}" min="0" max="20">
    </label><br><br>

    <label>${translations[settings.lang].lang}
        <select id="lang-select">
            <option value="ru" ${settings.lang==='ru'?'selected':''}>Русский</option>
            <option value="en" ${settings.lang==='en'?'selected':''}>English</option>
        </select>
    </label><br><br>

    <button id="save-settings">${translations[settings.lang].save}</button>
    <button id="cancel-settings">${translations[settings.lang].cancel}</button>
`;

        modal.appendChild(modalContent);
        document.body.appendChild(modal);

        // Обработчики в модальном окне
        document.getElementById('save-settings').addEventListener('click', () => {
            const defaultBgInput = document.getElementById('default-bg').value;
            const currentBgInput = document.getElementById('current-bg').value;
            const textColorInput = document.getElementById('text-color').value;
            const borderColorInput = document.getElementById('border-color').value;
            const defaultOpacityInput = document.getElementById('default-opacity').value;
            const currentOpacityInput = document.getElementById('current-opacity').value;
            settings.highlightDefaultBg = defaultBgInput ? hexToRgb(defaultBgInput) : settings.highlightDefaultBg;
            settings.highlightCurrentBg = currentBgInput ? hexToRgb(currentBgInput) : settings.highlightCurrentBg;
            settings.highlightTextColor = textColorInput ? hexToRgb(textColorInput) : settings.highlightTextColor;
            settings.highlightBorderColor = borderColorInput ? hexToRgb(borderColorInput) : settings.highlightBorderColor;
            settings.highlightBorderRadius = parseInt(document.getElementById('border-radius').value) || settings.highlightBorderRadius;
            settings.highlightBorderThickness = parseInt(document.getElementById('border-thickness').value) || settings.highlightBorderThickness;
            settings.highlightPadding = parseInt(document.getElementById('padding').value) || settings.highlightPadding;
            settings.lang = document.getElementById('lang-select').value; 
            settings.highlightDefaultOpacity = parseFloat(defaultOpacityInput) || settings.highlightDefaultOpacity;
            settings.highlightCurrentOpacity = parseFloat(currentOpacityInput) || settings.highlightCurrentOpacity;
            applySettings();
            // Пересоздаем подсветку, если нужно (или обновляем существующие)
            if (input.value.trim()) {
                searchAndHighlight(input.value);
            }
            input.placeholder = translations[settings.lang].searchPlaceholder;

            document.body.removeChild(modal);
        });
        document.getElementById('cancel-settings').addEventListener('click', () => {
            document.body.removeChild(modal);
        });
        // Закрытие по клику вне модала
        modal.addEventListener('click', (e) => {
            if (e.target === modal) document.body.removeChild(modal);
        });
    });

    container.appendChild(input);
    container.appendChild(btnPrev);
    container.appendChild(btnNext);
    container.appendChild(btnClose);
    container.appendChild(btnSettings); // Добавляем кнопку настроек рядом с контейнером
    wrapper.appendChild(btnToggle);
    wrapper.appendChild(container);
    wrapper.classList.add('collapsed');
    document.body.appendChild(wrapper);

      // Функция очистки подсветки
    function clearHighlights() {
        matches.forEach(mark => {
            const parent = mark.parentNode;
            if (!parent) return;
            parent.replaceChild(document.createTextNode(mark.textContent), mark);
            parent.normalize();
        });
        matches = [];
        currentIndex = -1;
    }

     // Функция поиска и подсветки
    function searchAndHighlight(query) {
        clearHighlights();
        if (!query.trim()) return;
        const regex = new RegExp(`(${query})`, 'gi');

        function walk(node) {
            if (node.nodeType === Node.TEXT_NODE && node.parentNode.tagName !== 'SCRIPT' && node.parentNode.tagName !== 'STYLE') {
                const text = node.textContent;
                const frag = document.createDocumentFragment();
                let lastIndex = 0;
                let match;
                while ((match = regex.exec(text)) !== null) {
                    if (match.index > lastIndex) {
                        frag.appendChild(document.createTextNode(text.slice(lastIndex, match.index)));
                    }
                    // Mark для совпадения
                    const mark = document.createElement('mark');
                    mark.id = 'markSearch-he5ngw4n-webpagebody';
                    mark.textContent = match[1];
                    mark.style.fontWeight = 'bold';
                    // Применяем стили подсветки
                    mark.style.color = settings.highlightTextColor;
                    mark.style.border = `${settings.highlightBorderThickness}px solid ${settings.highlightBorderColor}`;
                    mark.style.borderRadius = `${settings.highlightBorderRadius}px`;
                    mark.style.padding = `${settings.highlightPadding}px`;
                    mark.style.backgroundColor = rgbToRgba(settings.highlightDefaultBg, settings.highlightDefaultOpacity);
                    frag.appendChild(mark);
                    matches.push(mark);
                    lastIndex = match.index + match[1].length;
                }
                // Остаток текста
                if (lastIndex < text.length) {
                    frag.appendChild(document.createTextNode(text.slice(lastIndex)));
                }
                if (matches.length) node.parentNode.replaceChild(frag, node);
            } else if (node.nodeType === Node.ELEMENT_NODE) {
                Array.from(node.childNodes).forEach(child => walk(child));
            }
        }

        walk(document.body);
    }


    // Функция навигации
    function navigate(direction) {
        if (!matches.length) return;
        currentIndex += direction;
        if (currentIndex >= matches.length) currentIndex = 0;
        if (currentIndex < 0) currentIndex = matches.length - 1;
        matches.forEach((m, i) => {
           if (m) {
                const isCurrent = i === currentIndex;
                m.style.backgroundColor = rgbToRgba(
                    isCurrent ? settings.highlightCurrentBg : settings.highlightDefaultBg,
                    isCurrent ? settings.highlightCurrentOpacity : settings.highlightDefaultOpacity
                );
            }
        });
        matches[currentIndex].scrollIntoView({ behavior: 'smooth', block: 'center' });
    }

     // Обработчики событий
    input.addEventListener('input', e => searchAndHighlight(e.target.value));
    btnNext.addEventListener('click', () => navigate(1));
    btnPrev.addEventListener('click', () => navigate(-1));
    btnClose.addEventListener('click', () => {
        clearHighlights();
        wrapper.classList.add('collapsed');
        container.style.display = 'none';
    });

 // Горячие клавиши
    document.addEventListener('keydown', e => {
        if (e.ctrlKey && e.key === 'f') {
            e.preventDefault();
            wrapper.classList.remove('collapsed');
            input.focus();
        }
        if (!wrapper.classList.contains('collapsed') && container.style.display !== 'none' && input === document.activeElement) {
            if (e.key === 'Enter') navigate(e.shiftKey ? -1 : 1);
            if (e.key === 'Escape') btnClose.click();
        }
    });

   

     // Вспомогательные функции для цветов
    function rgbToHex(rgb) {
        if (rgb.startsWith('rgb(')) {
            const [r, g, b] = rgb.match(/\d+/g);
            return '#' + ((1 << 24) + (parseInt(r) << 16) + (parseInt(g) << 8) + parseInt(b)).toString(16).slice(1);
        }
        return rgb;
    }
    function hexToRgb(hex) {
        const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
        return result ? `rgb(${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)})` : hex;
    }
})();