-

Odoo - Home Screen Icon Layout (userScript)

Odoo ERP için geliştirmiş olduğum bu userScript sayesinde ana ekran simge düzeninizi özelleştirebilirsiniz.

Kullanım

Bu bir userScript betiğidir, çalıştırabilmek için kullandığınız tarayıcıda Tampermonkey, Violentmonkey vb. gibi bir komut dosyası yöneticisi yüklü olmalıdır.

Odoo - Home Screen Icon Layout (userScript)
Betiğin çalışma şeklini gösteren bir kesit
Bilgilendirme

userScript bir tarayıcı komut dosyası olarak çalışır, yani sadece yüklediğiniz tarayıcı ile bu betiği kullanabilirsiniz. userScript hakkında detaylı bilgi edinmek için buraya tıklayabilirsiniz.

Test Edilen Sürümler

  • Odoo 16.x (Chromium ve Tampermonkey ile test edildi)
  • Odoo 17.x (Chromium ve Tampermonkey ile test edildi)
  • Odoo 18.x (Chromium ve Tampermonkey ile test edildi)
  • Odoo 19.x (Chromium ve Tampermonkey ile test edildi)
Değişiklik günlüğü
1.8
  • En düşük metin boyutu %75'ten %50'ye esnetildi
  • @match kısmı *://*/* olarak değiştirildi, script artık mevcut sayfanın Odoo olup olmadığını "document.getElementById('web.layout.odooscript');" komutuyla tespit ediyor.
1.7
  • Görünüm ayarları penceresinin her zaman en üstte gözükmesi için z-index değeri 99999 olarak değiştirildi
  • Eklenti simgesi değiştirildi
  • Undo simgesi w3.org yerine fa-undo kullanılacak şekilde güncellendi
1.6
  • Artık simge boyutu değiştikçe metin boyutu da orantılı olarak değişiyor
  • Metin boyutu adında yeni bir ayar çubuğu eklendi, ekstra daha küçük ve daha büyük yapabilirsiniz
  • Artık görünüm ayarlarında her bir ayarda ve tüm ayarlarda yapılan değişiklikleri geri alabilirsiniz
  • Varsayılan değerde olan ayarlar için sıfırlama butonu gözükmüyor, değişiklik yapılan değerlerde ise geri al butonu gözüküyor
  • Script simgesi güncellendi
1.5
  • Maksimum simge boyutu 112px'ten 128px'e çıkartıldı
  • Köşe yuvarlatma artık rem değil yüzde cinsinden ayarlanıyor
  • Artık simgeler arası boşluk ayarlanabiliyor
1.4
  • Görünüm ayarlarından artık simge boşluğu ayarlanabiliyor
  • Görünüm ayarlarına Ekran genişliğine sığdır adında bir seçenek eklendi
1.3
  • Kullanıcı artık üst boşluğu ayarlayabiliyor.
1.2
  • Kullanıcı artık sıra sayısının yanısıra simgelerin boyutunu ve simge köşelerinin yumuşaklığını ayarlayabiliyor.
1.1
  • Kullanıcı artık sıra sayısını kod içerisinden ayarlamak yerine script menüsünden slider yardımı ile ayarlayabilir.
1.0

Bu betiğin yayınlandığı ilk sürümdür.

Yükleme adımlarını görmek için tıklayın
  1. Kullandığınız tarayıcıya Tampermonkey, Violentmonkey vb. gibi bir komut dosyası yöneticisi yükleyin.
  2. Yükledikten sonra uzantı seçeneklerinden "Kullanıcı Betiklerine İzin Ver" seçeneğini etkinleştirin.
  3. Chromium tabanlı bir tarayıcı kullanıyorsanız "Uzantılar" sayfasından geliştirici modunu etkinleştirin.
  4. Tarayıcınızı yeniden başlatın.
  5. Aşağıdaki snippetin sağ üst köşesinde bulunan "Aç" butonuna tıklayın.
  6. Karşınıza yükleme ekranı çıkacaktır, Yükle butonuna tıklayarak yükleme işlemini tamamlayabilirsiniz. Olası bir güncelleme yayınlanması durumunda bu ekran otomatik olarak tekrar karşınıza çıkacaktır.
Odoo-App-Drawer-Layout.user.js
// ==UserScript==
// @name            Odoo App Drawer Layout
// @name:tr         Odoo Uygulama Çekmecesi Yerleşim Düzeni
// @namespace       https://github.com/sipsak
// @version         1.8
// @description     Allows you to customize the layout of icons on the Odoo home screen
// @description:tr  Odoo ana ekrandaki simgelerin düzenini değiştirmenizi sağlar
// @author          Burak Şipşak
// @match           *://*/*
// @grant           GM_registerMenuCommand
// @grant           GM_getValue
// @grant           GM_setValue
// @icon            data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTAiIGhlaWdodD0iNTAiIHZpZXdCb3g9IjAgMCA1MCA1MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNDQuNTIxIDUuNWE0LjQ3NyA0LjQ3NyAwIDAgMSAwIDYuMzMybC0zNC4xOSAzNC4xOUg0VjM5LjY5TDM4LjE5IDUuNWE0LjQ3NyA0LjQ3NyAwIDAgMSA2LjMzMSAwWiIgZmlsbD0iIzJFQkNGQSIvPjxwYXRoIGQ9Ik0xMC45IDE1LjEyMiA0Ljg5OCA5LjEyYTkuMDA0IDkuMDA0IDAgMCAwIDEwLjQ4IDEyLjU2OGwyMy4wMDEgMjNhNC40NzcgNC40NzcgMCAwIDAgNi4zMzEtNi4zM2wtMjMtMjMuMDAxQTkuMDA0IDkuMDA0IDAgMCAwIDkuMTQxIDQuODc3bDYuMDAyIDYuMDAyLTQuMjQzIDQuMjQzWiIgZmlsbD0iIzk4NTE4NCIvPjxwYXRoIGQ9Ik0yNS4wMjMgMTguNjcgMTguNjkgMjVsNi4zMzIgNi4zMzFMMzEuMzUyIDI1bC02LjMzLTYuMzMxWiIgZmlsbD0iIzE0NDQ5NiIvPjwvc3ZnPgo=
// @updateURL       https://raw.githubusercontent.com/sipsak/Odoo-App-Drawer-Layout/main/Odoo-App-Drawer-Layout.user.js
// @downloadURL     https://raw.githubusercontent.com/sipsak/Odoo-App-Drawer-Layout/main/Odoo-App-Drawer-Layout.user.js
// ==/UserScript==

(function () {
    'use strict';

    const DEFAULT_ICON_COUNT = 6;
    const DEFAULT_ICON_SIZE = 70;
    const DEFAULT_ICON_RADIUS = 17.1428571;
    const DEFAULT_TOP_MARGIN = 48;
    const DEFAULT_ICON_SPACING = 10;
    const DEFAULT_ICON_MARGIN = 16;
    const DEFAULT_FONT_SIZE_MULTIPLIER = 100;
    const DEFAULT_FIT_TO_SCREEN_WIDTH = false;

    const MIN_ICON_COUNT = 4;
    const MAX_ICON_COUNT = 15;
    const MIN_ICON_SIZE = 60;
    const MAX_ICON_SIZE = 128;
    const MIN_ICON_RADIUS = 0;
    const MAX_ICON_RADIUS = 100;
    const MIN_TOP_MARGIN = 0;
    const MAX_TOP_MARGIN = 96;
    const MIN_ICON_SPACING = 5;
    const MAX_ICON_SPACING = 20;
    const MIN_ICON_MARGIN = 0;
    const MAX_ICON_MARGIN = 64;
    const MIN_FONT_SIZE_MULTIPLIER = 50;
    const MAX_FONT_SIZE_MULTIPLIER = 250;

    const UNDO_ICON_SVG = `<i class="fa fa-undo" aria-hidden="true"></i>`;

    const styleElementId = 'odoo-app-drawer-style';
    const sliderModalId = 'odoo-app-drawer-modal';

    function getSetting(key, fallback) {
        let value = GM_getValue(key, fallback);
        if (typeof fallback === 'number' && !isNaN(parseFloat(value))) {
            value = parseFloat(value);
        } else if (typeof fallback === 'boolean') {
            value = (value === 'true' || value === true);
        }
        return isNaN(value) && typeof fallback === 'number' ? fallback : value;
    }

    function applyPreviewStyles(iconCount, iconSize, iconRadius, topMargin, iconSpacing, fitToScreenWidth, iconMargin, fontSizeMultiplier) {
        let style = document.getElementById(styleElementId);
        const widthPercent = (100 / iconCount).toFixed(8) + '%';
        const borderRadiusInPx = (iconSize / 2) * (iconRadius / 100);
        const baseFontSize = (iconSize * (0.875 / 70));
        const finalFontSize = baseFontSize * (fontSizeMultiplier / 100);

        let maxWidthCss = '';
        if (fitToScreenWidth) {
            maxWidthCss = `max-width: ${window.innerWidth - 40}px !important;`;
        } else {
            const spacingCount = iconCount - 1;
            const baseMaxWidthPx = iconCount * 75 + spacingCount * 80;
            const sizeAdjustment = (iconSize - DEFAULT_ICON_SIZE) * 8;
            const maxWidthPx = baseMaxWidthPx + sizeAdjustment;
            maxWidthCss = `max-width: ${maxWidthPx}px !important;`;
        }

        const css = `
            @media (min-width: 768px) {
                .o_home_menu { font-size: ${finalFontSize}rem !important; }
                .o_home_menu .row-cols-6 > *, .o_home_menu .row-cols-sm-6 > *, .o_home_menu .row-cols-md-6 > *, .o_home_menu .row-cols-lg-6 > *, .o_home_menu .row-cols-xl-6 > *, .o_home_menu .row-cols-xxl-6 > *, .o_home_menu .col-2, .o_home_menu .col-sm-2, .o_home_menu .col-md-2, .o_home_menu .col-lg-2, .o_home_menu .col-xl-2, .o_home_menu .col-xxl-2 { width: ${widthPercent} !important; flex: 0 0 auto !important; }
                .o_home_menu .offset-2, .o_home_menu .offset-sm-2, .o_home_menu .offset-md-2, .o_home_menu .offset-lg-2, .o_home_menu .offset-xl-2, .o_home_menu .offset-xxl-2 { margin-left: ${widthPercent} !important; }
                .o_home_menu .container, .o_home_menu .o_container_small { ${maxWidthCss} }
                .o_home_menu .o_app .o_app_icon { width: ${iconSize}px !important; height: ${iconSize}px !important; border-radius: ${borderRadiusInPx}px !important; padding: ${iconSpacing}px !important; }
                .o_home_menu .mb-3 { margin-bottom: ${iconMargin}px !important; }
            }
            .mt-5 { margin-top: ${topMargin}px !important; }
        `;

        if (style) {
            style.textContent = css;
        } else {
            style = document.createElement('style');
            style.id = styleElementId;
            style.textContent = css;
            document.head.appendChild(style);
        }
    }

    function applyCustomStyles() {
        applyPreviewStyles(
            getSetting('iconCount', DEFAULT_ICON_COUNT), getSetting('iconSize', DEFAULT_ICON_SIZE), getSetting('iconRadius', DEFAULT_ICON_RADIUS), getSetting('topMargin', DEFAULT_TOP_MARGIN), getSetting('iconSpacing', DEFAULT_ICON_SPACING), getSetting('fitToScreenWidth', DEFAULT_FIT_TO_SCREEN_WIDTH), getSetting('iconMargin', DEFAULT_ICON_MARGIN), getSetting('fontSizeMultiplier', DEFAULT_FONT_SIZE_MULTIPLIER)
        );
    }

    function createSlider(id, label, min, max, current, step = 1, unit = '', decimalPlaces = 0, defaultValue) {
        const valueFormatted = decimalPlaces === 0 ? Math.round(current) : parseFloat(current).toFixed(decimalPlaces);
        return `
            <div class="mb-3">
                <label for="${id}" class="form-label d-flex justify-content-between align-items-center">
                    <span>${label}: <strong id="${id}Value">${valueFormatted}${unit}</strong></span>
                    <span id="${id}Actions">
                        <button type="button" class="btn btn-sm btn-light px-2 py-0" data-undo-single="${id}" title="Değişikliği geri al" style="display: none;">${UNDO_ICON_SVG}</button>
                        <button type="button" class="btn btn-sm btn-light px-2 py-0" data-reset-single="${id}" data-default-value="${defaultValue}" title="Varsayılana sıfırla" style="display: none;">Sıfırla</button>
                    </span>
                </label>
                <input type="range" class="form-range" id="${id}" min="${min}" max="${max}" step="${step}" value="${current}">
                <div class="d-flex justify-content-between text-muted small mt-1">
                    <span>${min}${unit}</span>
                    <span>${max}${unit}</span>
                </div>
            </div>
        `;
    }

    function createSliderModal() {
        const oldModal = document.getElementById(sliderModalId);
        if (oldModal) oldModal.remove();

        const initialSettings = {
            iconCount: getSetting('iconCount', DEFAULT_ICON_COUNT), iconSize: getSetting('iconSize', DEFAULT_ICON_SIZE), fontSizeMultiplier: getSetting('fontSizeMultiplier', DEFAULT_FONT_SIZE_MULTIPLIER), iconSpacing: getSetting('iconSpacing', DEFAULT_ICON_SPACING), iconMargin: getSetting('iconMargin', DEFAULT_ICON_MARGIN), iconRadius: getSetting('iconRadius', DEFAULT_ICON_RADIUS), topMargin: getSetting('topMargin', DEFAULT_TOP_MARGIN), fitToScreenWidth: getSetting('fitToScreenWidth', DEFAULT_FIT_TO_SCREEN_WIDTH)
        };
        const defaultSettings = {
            iconCount: DEFAULT_ICON_COUNT, iconSize: DEFAULT_ICON_SIZE, fontSizeMultiplier: DEFAULT_FONT_SIZE_MULTIPLIER, iconSpacing: DEFAULT_ICON_SPACING, iconMargin: DEFAULT_ICON_MARGIN, iconRadius: DEFAULT_ICON_RADIUS, topMargin: DEFAULT_TOP_MARGIN, fitToScreenWidth: DEFAULT_FIT_TO_SCREEN_WIDTH
        };

        const modalWrapper = document.createElement('div');
        modalWrapper.id = sliderModalId;
        modalWrapper.className = 'modal fade show';
        modalWrapper.setAttribute('tabindex', '-1');
        modalWrapper.style.cssText = `display: block; background-color: rgba(0, 0, 0, 0.5); position: fixed; inset: 0; z-index: 99999;`;

        modalWrapper.innerHTML = `
            <div class="modal-dialog modal-dialog-centered" style="max-width: 400px;">
                <div class="modal-content">
                    <header class="modal-header">
                        <h4 class="modal-title text-break">Görünüm Ayarları</h4>
                        <button type="button" class="btn-close" aria-label="Close"></button>
                    </header>
                    <main class="modal-body">
                        ${createSlider('iconCountSlider', 'Sütun sayısı', MIN_ICON_COUNT, MAX_ICON_COUNT, initialSettings.iconCount, 1, '', 0, DEFAULT_ICON_COUNT)}
                        ${createSlider('iconSizeSlider', 'Simge boyutu', MIN_ICON_SIZE, MAX_ICON_SIZE, initialSettings.iconSize, 1, 'px', 0, DEFAULT_ICON_SIZE)}
                        ${createSlider('fontSizeSlider', 'Metin boyutu', MIN_FONT_SIZE_MULTIPLIER, MAX_FONT_SIZE_MULTIPLIER, initialSettings.fontSizeMultiplier, 1, '%', 0, DEFAULT_FONT_SIZE_MULTIPLIER)}
                        ${createSlider('iconSpacingSlider', 'Simge içi boşluk', MIN_ICON_SPACING, MAX_ICON_SPACING, initialSettings.iconSpacing, 1, 'px', 0, DEFAULT_ICON_SPACING)}
                        ${createSlider('iconMarginSlider', 'Simgeler arası boşluk', MIN_ICON_MARGIN, MAX_ICON_MARGIN, initialSettings.iconMargin, 1, 'px', 0, DEFAULT_ICON_MARGIN)}
                        ${createSlider('iconRadiusSlider', 'Köşe yuvarlatma', MIN_ICON_RADIUS, MAX_ICON_RADIUS, initialSettings.iconRadius, 'any', '%', 0, DEFAULT_ICON_RADIUS)}
                        ${createSlider('topMarginSlider', 'Üst boşluk', MIN_TOP_MARGIN, MAX_TOP_MARGIN, initialSettings.topMargin, 1, 'px', 0, DEFAULT_TOP_MARGIN)}
                        <div class="form-check mt-3">
                            <input class="form-check-input" type="checkbox" id="fitToScreenWidthCheckbox" ${initialSettings.fitToScreenWidth ? 'checked' : ''}>
                            <label class="form-check-label" for="fitToScreenWidthCheckbox">Ekran genişliğine sığdır</label>
                        </div>
                    </main>
                    <footer class="modal-footer justify-content-between">
                        <div>
                            <button id="sliderOkBtn" class="btn btn-primary me-2">Tamam</button>
                            <button id="sliderCancelBtn" class="btn btn-secondary">İptal</button>
                        </div>
                        <div>
                           <button id="sliderUndoAllBtn" class="btn btn-warning me-2" title="Tüm değişiklikleri geri al" style="display: none;">${UNDO_ICON_SVG}</button>
                           <button id="sliderResetAllBtn" class="btn btn-info" title="Tümünü varsayılana sıfırla" style="display: none;">Tümünü sıfırla</button>
                        </div>
                    </footer>
                </div>
            </div>
        `;
        document.body.appendChild(modalWrapper);

        const modal = document.getElementById(sliderModalId);
        const sliders = { iconCount: modal.querySelector('#iconCountSlider'), iconSize: modal.querySelector('#iconSizeSlider'), fontSize: modal.querySelector('#fontSizeSlider'), iconSpacing: modal.querySelector('#iconSpacingSlider'), iconMargin: modal.querySelector('#iconMarginSlider'), iconRadius: modal.querySelector('#iconRadiusSlider'), topMargin: modal.querySelector('#topMarginSlider') };
        const labels = { iconCount: modal.querySelector('#iconCountSliderValue'), iconSize: modal.querySelector('#iconSizeSliderValue'), fontSize: modal.querySelector('#fontSizeSliderValue'), iconSpacing: modal.querySelector('#iconSpacingSliderValue'), iconMargin: modal.querySelector('#iconMarginSliderValue'), iconRadius: modal.querySelector('#iconRadiusSliderValue'), topMargin: modal.querySelector('#topMarginSliderValue') };
        const fitToScreenWidthCheckbox = modal.querySelector('#fitToScreenWidthCheckbox');

        const sliderKeyMap = { iconCountSlider: 'iconCount', iconSizeSlider: 'iconSize', fontSizeSlider: 'fontSizeMultiplier', iconSpacingSlider: 'iconSpacing', iconMarginSlider: 'iconMargin', iconRadiusSlider: 'iconRadius', topMarginSlider: 'topMargin' };

        function updateButtonVisibility() {
            let isAnyChangedFromInitial = false;
            let isAnyDifferentFromDefault = false;

            for (const slider of Object.values(sliders)) {
                const key = sliderKeyMap[slider.id];
                const currentValue = parseFloat(slider.value);
                const initialValue = initialSettings[key];
                const defaultValue = defaultSettings[key];
                const undoBtn = modal.querySelector(`[data-undo-single="${slider.id}"]`);
                const resetBtn = modal.querySelector(`[data-reset-single="${slider.id}"]`);

                let isSameAsInitial, isSameAsDefault;

                if (key === 'iconRadius') {
                    isSameAsInitial = Math.abs(currentValue - initialValue) < 0.00001;
                    isSameAsDefault = Math.abs(currentValue - defaultValue) < 0.00001;
                } else {
                    isSameAsInitial = currentValue === initialValue;
                    isSameAsDefault = currentValue === defaultValue;
                }

                undoBtn.style.display = isSameAsInitial ? 'none' : 'inline-block';
                resetBtn.style.display = isSameAsDefault ? 'none' : 'inline-block';

                if (!isSameAsInitial) isAnyChangedFromInitial = true;
                if (!isSameAsDefault) isAnyDifferentFromDefault = true;
            }

            const isCheckboxChanged = fitToScreenWidthCheckbox.checked !== initialSettings.fitToScreenWidth;
            if (isCheckboxChanged) isAnyChangedFromInitial = true;

            const isCheckboxDifferentFromDefault = fitToScreenWidthCheckbox.checked !== defaultSettings.fitToScreenWidth;
            if (isCheckboxDifferentFromDefault) isAnyDifferentFromDefault = true;

            modal.querySelector('#sliderUndoAllBtn').style.display = isAnyChangedFromInitial ? 'inline-block' : 'none';
            modal.querySelector('#sliderResetAllBtn').style.display = isAnyDifferentFromDefault ? 'inline-block' : 'none';
        }

        function updatePreview() {
            labels.iconCount.textContent = sliders.iconCount.value;
            labels.iconSize.textContent = sliders.iconSize.value + 'px';
            labels.fontSize.textContent = sliders.fontSize.value + '%';
            labels.iconSpacing.textContent = sliders.iconSpacing.value + 'px';
            labels.iconMargin.textContent = sliders.iconMargin.value + 'px';
            labels.iconRadius.textContent = Math.round(sliders.iconRadius.value) + '%';
            labels.topMargin.textContent = sliders.topMargin.value + 'px';

            applyPreviewStyles(parseInt(sliders.iconCount.value), parseInt(sliders.iconSize.value), parseFloat(sliders.iconRadius.value), parseInt(sliders.topMargin.value), parseInt(sliders.iconSpacing.value), fitToScreenWidthCheckbox.checked, parseInt(sliders.iconMargin.value), parseInt(sliders.fontSize.value));
            updateButtonVisibility();
        }

        Object.values(sliders).forEach(s => s.addEventListener('input', updatePreview));
        fitToScreenWidthCheckbox.addEventListener('change', updatePreview);

        modal.querySelectorAll('[data-reset-single]').forEach(btn => {
            btn.addEventListener('click', () => {
                const sliderId = btn.getAttribute('data-reset-single');
                document.getElementById(sliderId).value = btn.getAttribute('data-default-value');
                updatePreview();
            });
        });

        modal.querySelectorAll('[data-undo-single]').forEach(btn => {
            btn.addEventListener('click', () => {
                const sliderId = btn.getAttribute('data-undo-single');
                const key = sliderKeyMap[sliderId];
                document.getElementById(sliderId).value = initialSettings[key];
                updatePreview();
            });
        });

        function undoAllChanges() {
            for (const slider of Object.values(sliders)) {
                const key = sliderKeyMap[slider.id];
                slider.value = initialSettings[key];
            }
            fitToScreenWidthCheckbox.checked = initialSettings.fitToScreenWidth;
            updatePreview();
        }

        function resetAllSliders() {
            for (const slider of Object.values(sliders)) {
                const key = sliderKeyMap[slider.id];
                slider.value = defaultSettings[key];
            }
            fitToScreenWidthCheckbox.checked = defaultSettings.fitToScreenWidth;
            updatePreview();
        }

        modal.querySelector('#sliderUndoAllBtn').addEventListener('click', undoAllChanges);
        modal.querySelector('#sliderResetAllBtn').addEventListener('click', resetAllSliders);

        modal.querySelector('#sliderOkBtn').addEventListener('click', () => {
            GM_setValue('iconCount', parseInt(sliders.iconCount.value));
            GM_setValue('iconSize', parseInt(sliders.iconSize.value));
            GM_setValue('fontSizeMultiplier', parseInt(sliders.fontSize.value));
            GM_setValue('iconSpacing', parseInt(sliders.iconSpacing.value));
            GM_setValue('iconMargin', parseInt(sliders.iconMargin.value));
            GM_setValue('iconRadius', parseFloat(sliders.iconRadius.value));
            GM_setValue('topMargin', parseInt(sliders.topMargin.value));
            GM_setValue('fitToScreenWidth', fitToScreenWidthCheckbox.checked);
            closeModal(true);
        });

        const closeModal = (isSaved = false) => {
            if (!isSaved) applyCustomStyles();
            modal.remove();
            document.removeEventListener('keydown', escHandler);
            window.removeEventListener('resize', applyCustomStyles);
        };

        const escHandler = e => { if (e.key === 'Escape') closeModal(); };
        modal.querySelector('#sliderCancelBtn').addEventListener('click', () => closeModal());
        modal.querySelector('.btn-close').addEventListener('click', () => closeModal());
        modal.addEventListener('click', e => { if (e.target === modal) closeModal(); });

        document.addEventListener('keydown', escHandler);
        window.addEventListener('resize', updatePreview);
        updateButtonVisibility();
    }

    async function init() {
        const scriptTag = document.getElementById('web.layout.odooscript');
        if (!scriptTag) {
            return;
        }

        GM_registerMenuCommand("Görünüm Ayarları", createSliderModal);

        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', () => {
                applyCustomStyles();
                window.addEventListener('resize', applyCustomStyles);
            });
        } else {
            applyCustomStyles();
            window.addEventListener('resize', applyCustomStyles);
        }
    }

    init();
})();