lmarena chat only

When you open the site https://lmarena.ai/ goes to the "Direct Chat" tab makes the model selection blocks, the chat window and the query input block fixed above all other elements.

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

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

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu betiği yüklemek için bir betik yöneticisi eklentisi yüklemeniz gerekecektir.

(Zaten bir betik yöneticim var, hadi yükleyelim!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name         lmarena chat only
// @namespace    Apache-2.0
// @version      1.5.3
// @description  When you open the site https://lmarena.ai/ goes to the "Direct Chat" tab makes the model selection blocks, the chat window and the query input block fixed above all other elements.
// @author       Tony 0tis
// @license      Apache-2.0
// @match        *://lmarena.ai/
// @icon         https://lmarena.ai/favicon.ico
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    if(localStorage.alertShown){
        const originalAlert = window.alert;
        window.alert = ()=>{};
        setTimeout(()=>{
            window.alert = originalAlert
        }, 1000);
    }
    localStorage.alertShown = true;

    class lmsysChat {
        constructor(){
            this.button = null;
            this.tab = null;
            this.mode = null;
            this.timeouts = {};

            console.log('start check');
            this.setCss();
            this.setMeta();
            this.setObserver();
            this.setManifest('https://raw.githubusercontent.com/tony-0tis/manifests/refs/heads/main/lmarena.ai/manifest.json');
        }

        setMeta(){
            const meta = document.createElement('meta');
            meta.name = 'viewport';
            meta.content = 'width=device-width, initial-scale=1';
            document.head.appendChild(meta);
        }

        setObserver(){
            const observer = new MutationObserver((mutationsList, observer)=>{
                for (const mutation of mutationsList) {
                    for(const node of mutation.addedNodes){
                        if(node.nodeName === 'BUTTON' && node.innerText.includes('Direct Chat')){
                            console.log('select chat');
                            this.riseChat(node);
                        }
                    }
                }
            });
            observer.observe(document, {attributes: false, childList: true, characterData: false, subtree:true});
            document.addEventListener('beforeunload', ()=>{
                observer.disconnect();
            });
        }

        async riseChat(button){
            if(this.mode === 'tabs') {
                return;
            }

            if(!button.classList.contains('selected')){
                this.button = button;
                button.dispatchEvent(new Event('click'));
                await this._timeout(200);
            }

            const tab = document.querySelector(`#${button.getAttribute('aria-controls')}`);
            if(!tab) return;
            this.tab = tab;
            this.mode = 'chat';

            if(tab.classList.contains('directChat')) return;

            tab.classList.add('directChat');

            const inputComponent = this._find(tab, '[id="input_box"]', el=>el, true);
            if(inputComponent && !inputComponent.classList.contains('directChatInput')){
                inputComponent.classList.add('directChatInput');
                const button = inputComponent.querySelector('button');
                if(button && !button.classList.contains('directChatSend')){
                    button.classList.add('directChatSend');
                }
            }

            const descriptionsComponent = this._find(tab, 'button', el=>el.innerText.includes('Expand to see the'), true);
            if(descriptionsComponent && !descriptionsComponent.classList.contains('directChatDescriptions')){
                descriptionsComponent.classList.add('directChatDescriptions');
            }

            const upvoteComponent = this._find(tab, 'button', el=>el.innerText.includes('Upvote'), true);
            if(upvoteComponent && !upvoteComponent.classList.contains('directChatVotes')){
                upvoteComponent.classList.add('directChatVotes');
            }

            const maxTokensComponent = this._find(tab, 'span', el=>el.innerText.includes('Max output tokens'), true);
            if(maxTokensComponent){
                [...maxTokensComponent.querySelectorAll('input')].forEach(el=>{
                    el.value = el.max || 4096;
                });
            }

            const parametrs = this._find(tab, 'span', el=>el.innerText.includes('Parameters'));
            if(parametrs){
                parametrs.innerText += ' (Fine tuning)';
            }

            const selector = tab.querySelector('[role="listbox"]');
            if(selector && !tab.querySelector('.chatModeSwitcher')){
                const button = document.createElement('button');
                button.classList.add('chatModeSwitcher');
                button.addEventListener('click', e=>this._switchChatMode(e));
                button.innerHTML = '🪟';
                button.title = 'Switch fullscreen/tabs';
                selector.parentNode.insertBefore(button, selector);

                while(!tab.querySelector('.progress-text')){
                    await this._timeout(null, 'progress');
                }

                while(tab.querySelector('.progress-text')){
                    await this._timeout(null, 'progress');
                }

                let model = localStorage.getItem('lmsysChatModel');
                if(model){
                    this.model = model;
                    if(model !== selector.value){
                        selector.dispatchEvent(new Event('focus'));
                        await this._timeout(50, 'progress');

                        const select = tab.querySelector(`[aria-label="${model}"]`);
                        if(select){
                            console.log('change selected model to', select.innerText);
                            select.dispatchEvent(new Event('mousedown', {bubbles: true}));
                        }
                    }
                }
                setInterval(()=>this._changeModel(selector), 500);
            }
        }

        _switchChatMode(e){
            if(!this.tab) return;
            if(this.tab.classList.contains('directChat')){
                this.mode = 'tabs';
                this.tab.classList.remove('directChat');
                document.querySelector('html').style.overflow = 'auto'
            }
            else{
                this.mode = 'chat';
                this.tab.classList.add('directChat');
                document.querySelector('html').style.overflow = 'hidden';
            }
        }

        _changeModel(selector){
            if(!this.tab) return;
            if(selector.value === this.model) return;
            this.model = selector.value;
            localStorage.setItem('lmsysChatModel', selector.value);
            console.log('save selected model to:', selector.value);
        }

        _find(doc, where, filter, findParentComponent){
            let el = [...doc.querySelectorAll(where)].filter(filter)[0];

            if(el && findParentComponent){
                let s = el.parentNode;
                while(s){
                    if(s.id?.includes('component')){
                        break;
                    }

                    s = s.parentNode;
                }

                if(s) {
                    el = s;
                }
            }

            return el;
        }

        _timeout(timeout = 200, name = 'default'){
            clearTimeout(this.timeouts[name]);

            return new Promise(resolve=>{
                this.timeouts[name] = setTimeout(resolve, timeout);
            });
        }

        setManifest(manifestUrl){
            const manifest = document.createElement('link');
            manifest.rel = 'manifest'
            manifest.href = manifestUrl;
            document.head.appendChild(manifest);
        }

        setCss(){
            const css = document.createElement('style');
            css.innerHTML = `
html{
    overflow: hidden;
}
.directChat{
    position: fixed !important;
    left: 0;
    right: 0;
    bottom: 0;
    top: 0;
    z-index: 1000;
    padding: 5px !important;
    background: var(--body-background-fill);
}
.directChat>div{
    gap: 7px !important;
    height: 100%;
    max-width: 900px;
    margin: 0 auto;
}
.directChat>div>div:has(#chatbot){
    height: calc(100% - 305px);
}
.directChat>div>div>div:has(#chatbot){
    height: 100%;
}
.directChat #share-region-named, .directChat #share-region-named>div{
    height: 100%;
}
.directChat #notice_markdown, .directChat #ack_markdown{
    display: none;
}
.directChat .directChatSend{
    min-width: 90px !important;
}
.directChat .options{
    max-height: calc(100vh - 150px) !important;
}
.directChat .directChatDescriptions{
    display: none;
}
.directChat .directChatVotes{
    gap: 5px;
}
.directChat .directChatVotes>button{
    min-width: auto;
    padding: 5px;
    line-height: 1;
}
.directChat .directChatInput{
    gap: 5px;
}
.directChat #chatbot{
    height: 100% !important;
}
.directChat #input_box{
    padding: 0;
}
.chatModeSwitcher {
    padding: 8px !important;
    border-radius: 3px !important;
    background: #f36812 !important;
    margin: -6px 0 !important;
    margin-left: -12px !important;
    width: 55px !important;
    margin-right: 10px !important;
}
.chatModeSwitcher:hover{
    opacity: 0.8;
}
`;
            document.head.appendChild(css);
        }
    }

    new lmsysChat();
})();