// ==UserScript==
// @name ChatGPT Widescreen Mode 🖥️
// @name:af ChatGPT Widescreen Modus 🖥️
// @name:ar ChatGPT وضع شاشة عريضة 🖥️
// @name:az ChatGPT Geniş Ekran Rejimi 🖥️
// @name:be ChatGPT Рэжым шырокага экрана 🖥️
// @name:bg ChatGPT Широкоекранен режим 🖥️
// @name:bn ChatGPT উইডস্ক্রিন মোড 🖥️
// @name:bo ChatGPT རྒྱུ་ཆེན་གཞི་བསྒྲུབ་ རྒྱལ་བཤད། 🖥️
// @name:bs ChatGPT Režim širokog ekrana 🖥️
// @name:ca ChatGPT Mode de pantalla ampla 🖥️
// @name:ckb ChatGPT دەستکاری چوارچێوەی ڕووکاری 🖥️
// @name:cs ChatGPT Režim širokoúhlé obrazovky 🖥️
// @name:cy ChatGPT Mod Sgrin Lled 🖥️
// @name:da ChatGPT Bredformat-tilstand 🖥️
// @name:de ChatGPT Breitbildmodus 🖥️
// @name:dv ChatGPT ވިސްނުވެއް މޯޑި 🖥️
// @name:dz ChatGPT འབྲེལ་བ་གཞུང་ལས་སྤྱི་ཚོགས་གླེང་། 🖥️
// @name:el ChatGPT Λειτουργία ευρείας οθόνης 🖥️
// @name:eo ChatGPT Larĝekrana reĝimo 🖥️
// @name:es ChatGPT Modo de pantalla panorámica 🖥️
// @name:et ChatGPT Laiarakenduse režiim 🖥️
// @name:eu ChatGPT Pantaila Zabalaren Modua 🖥️
// @name:fa ChatGPT حالت تلویزیونی 🖥️
// @name:fi ChatGPT Laajakuva-tila 🖥️
// @name:fo ChatGPT Búðarformaður háttur 🖥️
// @name:fr ChatGPT Mode Écran Large 🖥️
// @name:fr-CA ChatGPT Mode Écran Large 🖥️
// @name:gd ChatGPT Dreach-sgrìn Leud 🖥️
// @name:gl ChatGPT Modo de pantalla ancha 🖥️
// @name:gu ChatGPT પ્રશાંત સ્ક્રીન મોડ 🖥️
// @name:he ChatGPT מצב מסך רחב 🖥️
// @name:hi ChatGPT चहचटजीपटी वाइडस्क्रीन मोड 🖥️
// @name:hr ChatGPT Način širokog zaslona 🖥️
// @name:ht ChatGPT Mod Fomat Gwo 🖥️
// @name:hu ChatGPT Szélesvásznú mód 🖥️
// @name:hy ChatGPT լայնէկրանանշանի ռեժիմ 🖥️
// @name:id ChatGPT Mode Layar Lebar 🖥️
// @name:is ChatGPT Breiðskjásstilling 🖥️
// @name:it ChatGPT Modalità schermo panoramica 🖥️
// @name:ja ChatGPT ワイドスクリーンモード 🖥️
// @name:jv ChatGPT Mode Layar Lebar 🖥️
// @name:ka ChatGPT ფანტსარიშის რეჟიმი 🖥️
// @name:kab ChatGPT Amezwaru n Tikliwin Isellalen 🖥️
// @name:kk ChatGPT Көлеңкескен түрі 🖥️
// @name:km ChatGPT របៀបបង្អស្សមួយធ្វើដំបូង 🖥️
// @name:kn ChatGPT ChatGPT ವೈಡ್ಸ್ಕ್ರೀನ್ ಮೋಡ್ 🖥️
// @name:ko ChatGPT 와이드 스크린 모드 🖥️
// @name:ku ChatGPT Moda Pêlên Dirêj 🖥️
// @name:ky ChatGPT Жогорку Экрандык Режим 🖥️
// @name:la ChatGPT Modus Latus Plenus 🖥️
// @name:lb ChatGPT Breitbild-Modus 🖥️
// @name:lo ChatGPT ຮູບແບບໂປຣຟອນໃຫຍ່ 🖥️
// @name:lt ChatGPT Išplėstojo ekrano režimas 🖥️
// @name:lv ChatGPT Plašā ekrāna režīms 🖥️
// @name:mg ChatGPT Tarehimarika tamin'ny Widescreen 🖥️
// @name:mi ChatGPT Āhua Whātika ā-Raupapa 🖥️
// @name:mk ChatGPT Режим на широк екран 🖥️
// @name:ml ChatGPT വൈഡ്സ്ക്രീൻ മോഡ് 🖥️
// @name:mn ChatGPT Жинхэнэ Экранны Арга 🖥️
// @name:ms ChatGPT Mod Skrin Lebar 🖥️
// @name:mt ChatGPT Modalità Widescreen 🖥️
// @name:my ChatGPT အများနှုန်းကျော်ဘုံ 🖥️
// @name:ne ChatGPT विस्तृत प्राण्डविक पद्धति 🖥️
// @name:nl ChatGPT Breedbeeldmodus 🖥️
// @name:no ChatGPT Bredskjermmodus 🖥️
// @name:ny ChatGPT Mawonekedwe Wathandiza 🖥️
// @name:pa ChatGPT ਵਾਇਡਸਕ੍ਰੀਨ ਮੋਡ 🖥️
// @name:pl ChatGPT Tryb szerokoekranowy 🖥️
// @name:ps ChatGPT د ډیسپلې موډ 🖥️
// @name:pt ChatGPT Modo Tela Larga 🖥️
// @name:pt-BR ChatGPT Modo Tela Larga 🖥️
// @name:ro ChatGPT Mod ecran lat 🖥️
// @name:ru ChatGPT Режим широкоформатного экрана 🖥️
// @name:rw ChatGPT Ibindi by'umuhondo bw'ishusho 🖥️
// @name:sg ChatGPT Mode Écran Large 🖥️
// @name:si ChatGPT විශේෂාංග පෙළක්ෂාව 🖥️
// @name:sk ChatGPT Režim širokouhlého displeja 🖥️
// @name:sl ChatGPT Način širokega zaslona 🖥️
// @name:sm ChatGPT Laititi Fuamatala 🖥️
// @name:sn ChatGPT Zvimwe Zvitsva Mode 🖥️
// @name:so ChatGPT hab Widescreen Mode 🖥️
// @name:sr ChatGPT Режим широког екрана 🖥️
// @name:sv ChatGPT Bredbildsläge 🖥️
// @name:sw ChatGPT Njia ya Skrini Panoramio 🖥️
// @name:ta ChatGPT விரிவான திரை முறை 🖥️
// @name:te ChatGPT ChatGPT వైడ్ స్క్రీన్ మోడ్ 🖥️
// @name:tg ChatGPT Возачи Режаи Дисплеи Барнома 🖥️
// @name:th ChatGPT โหมดหน้าจอแบบเต็มจอ 🖥️
// @name:ti ቻትጂፒቲ ዋይድስክሪን ሞድ 🖥️
// @name:tk ChatGPT Giň Ekran Tertibi 🖥️
// @name:tn ChatGPT Nyemba Yemba Mzizo 🖥️
// @name:to ChatGPT Moli ʻo e Ngaahi Fatongi ʻo Haʻaneesi 🖥️
// @name:tr ChatGPT Geniş Ekran Modu 🖥️
// @name:uk ChatGPT Режим широкого екрана 🖥️
// @name:ur ChatGPT وائڈ اسکرین موڈ 🖥️
// @name:uz ChatGPT Keng ekranga rejim 🖥️
// @name:vi ChatGPT Chế độ Màn hình Rộng 🖥️
// @name:xh ChatGPT Indlela ye-Widescreen Mode 🖥️
// @name:yi ChatGPT ווידעסקרעען מאָדע 🖥️
// @name:zh ChatGPT 宽屏模式 🖥️
// @name:zh-CN ChatGPT 宽屏模式 🖥️
// @name:zh-HK ChatGPT 寬螢幕模 🖥️
// @name:zh-SG ChatGPT 宽屏模式 🖥️
// @name:zh-TW ChatGPT 寬螢幕模 🖥️
// @name:zu ChatGPT Isimo sokudlalwa emkhumbini 🖥️
// @description Adds Widescreen + Fullscreen modes to ChatGPT for enhanced viewing + reduced scrolling
// @description:af Voeg Widescreen + Volledige skermmodusse by ChatGPT vir verbeterde kyk + verminderde skrol
// @description:am የራስ መጠን በ ChatGPT ውስጥ የተከፈተውን ወደ ትንቢት ማድረግ + ድምፅ እንዲታትና
// @description:ar إضافة وضعي الشاشة العريضة + الشاشة الكاملة إلى ChatGPT لتحسين العرض + تقليل التمرير
// @description:az ChatGPT üçün Geniş Ekran + Tam Ekran rejimləri əlavə etmək, görüntünü yaxşılaşdırmaq + səlahətən keçirməni azaltmaq
// @description:be Дадае рэжымы шырокага экрана + поўнага экрана да ChatGPT для паляпшэнага прагляду + змяншэння скролінгу
// @description:bem Ena Mode ya Widescreen + ya Fullscreen ku ChatGPT pa kuongeza kulandila + ukukonda scrolling
// @description:bg Добавя режими на Широк екран + Пълен екран към ChatGPT за подобрено гледане + намалено плъзгане
// @description:bn এক্স এগ্রিসিভ দেখার জন্য ChatGPT-এ ওয়াইডস্ক্রিন + ফুলস্ক্রিন মোড যুক্ত করে + স্ক্রলিং হ্রাস করে
// @description:bo བཅའ་དྲུག་རྒྱུས་པ་+ བདེ་ཆེན་རྒྱུས་པ་འདི་ChatGPT་ནང་ལས་བསྒྲགས་བཞག་བའི་ལྷག་པ་ཞིག་ཁམས་པའི་བརྟག་ཞིབ་བཅོ་སྒྲིག་འདུག
// @description:bs Dodaje Widescreen + Fullscreen režime ChatGPT-u za poboljšani prikaz + smanjenje klizanja
// @description:ca Afegeix els modes de pantalla ampla + pantalla completa a ChatGPT per a una visualització millorada + reducció de desplaçament
// @description:ceb Gidugang ang Mga Modo sa Widescreen + Fullscreen sa ChatGPT alang sa labaw nga pagtan-aw + paggamot sa pag-scroll
// @description:ckb Mode Widescreen + Mode Fullscreen bo ChatGPT zêde bike ji bo nêzîkbûna başkirinê + kam kirina birevandinê
// @description:cs Přidává režimy Widescreen + Fullscreen do ChatGPT pro zlepšené zobrazení + snížení posouvání
// @description:cy Ychwanega dulliau Sgrin Llydan + Sgrin Lawn i ChatGPT ar gyfer gwylio well + lleihau sgrolio
// @description:da Tilføjer Widescreen + Fuldscreen-tilstande til ChatGPT for forbedret visning + reduceret rulning
// @description:de Fügt Widescreen + Vollbildmodus zu ChatGPT für verbesserte Ansicht + reduziertes Scrollen hinzu
// @description:dv ChatGPT ބޮޓޮބޭސީ + ފަންވައިދާ މޯޑިއުލްއަޤް ހެދުމަށް ކަނޑުގެންނަވަން + ރުސަބް ބެންކުރުމަށްވެއްޖެ
// @description:dz ChatGPT སྒྲུབ་ཐབས་ + མིང་དཔྱད་ཆེས་དང་པ་ཡོངས་ཀྱི་ལྷག་པ་ཁྱབ་ལ་ཉོ་གར་བཞག་པ་དང་བདེན་པས་ཆེད་པ་དང་ཚིག་རྐྱང་ལ་མགོ་ནི་
// @description:el Προσθέτει λειτουργίες Widescreen + Fullscreen στο ChatGPT για βελτιωμένη προβολή + μείωση της κύλισης
// @description:eo Aldonas larĝekranajn + plenekranajn reĝimojn al ChatGPT por plibonigita vidado + malpliigo de ŝovado
// @description:es Agrega modos de pantalla panorámica + pantalla completa a ChatGPT para una visualización mejorada + desplazamiento reducido
// @description:et Lisab ChatGPT-le Widescreen + Täisekraani režiimid parema vaatamise ja vähenenud kerimisega
// @description:eu Gehitu Widescreen + Pantaila oso moduak ChatGPT-ra ikusmen hobetu + mugimendua gutxituz
// @description:fa اضافه کردن حالت های واید اسکرین + تمام صفحه به ChatGPT برای مشاهده بهتر + کاهش اسکرول
// @description:fi Lisää Widescreen + Koko näytön tilat ChatGPT:hen paremman katselun + vähentyneen vierityksen ansiosta
// @description:fo Leggur til Widescreen + Fullscreen hamrar á ChatGPT fyri bætta sýning + minnka skúvsetan
// @description:fr Ajoute les modes écran large + plein écran à ChatGPT pour une meilleure visualisation + un défilement réduit
// @description:fr-CA Ajoute les modes écran large + plein écran à ChatGPT pour une meilleure visualisation + un défilement réduit
// @description:gd Cuir gnèithean Leudachaidh + Faidhlichean sàbhaladh sgrùdair gu ChatGPT airson sealladh air àrdachadh + sgroladh lag
// @description:gl Engade os modos de pantalla panorámica + pantalla completa a ChatGPT para unha visualización mellorada + desprazamento reducido
// @description:gu એન્હાનો જોડાણ કરો વાઈડસ્ક્રીન + ફુલસ્ક્રીન મોડ તેમજ ChatGPT માટે સુધારેલ જોઈન્ટ પ્રદર્શન + કમેલી સ્ક્રોલિંગ માટે
// @description:haw Kālele i nā Ao Waiwai + Ao Piha i loko o ChatGPT no ka ho'ohana'ana ikaika + ka'u hā'ule 'ana
// @description:he מוסיף מצבי מסך מורחב + מסך מלא ל־ChatGPT לשיפור תצוגה + הפחתת גלילה
// @description:hi बढ़िया दृश्य + कम स्क्रोलिंग के लिए ChatGPT में वाइडस्क्रीन + फुलस्क्रीन मोड जोड़ता है
// @description:hr Dodaje Widescreen + Fullscreen načine na ChatGPT za poboljšani prikaz + smanjenje klizanja
// @description:ht Ajoute modes Widescreen + Fullscreen nan ChatGPT pou amelyore gade + redui defileman
// @description:hu Hozzáadja a Widescreen + Teljes képernyő módokat a ChatGPT-hoz jobb megtekintés + görgetés csökkentése érdekében
// @description:hy Ավելացնում է Widescreen + Fullscreen ռեժիմները ChatGPT-ում բարելավված դիտումի համար + սահմանափակումը
// @description:id Menambahkan mode Widescreen + Layar Penuh ke ChatGPT untuk penampilan yang lebih baik + pengurangan pengguliran
// @description:is Bætir við Widescreen + Fullskjárshamra í ChatGPT til að bæta sýn + draga úr skruni
// @description:it Aggiunge le modalità Widescreen + Schermo intero a ChatGPT per una visualizzazione migliorata + riduzione dello scorrimento
// @description:ja ChatGPTの表示を向上するために、ワイドスクリーン+フルスクリーンモードを追加します
// @description:jv Nambahi Modus Widescreen + Fullscreen menyang ChatGPT kanggo tampilan sing ditingkatake + ngecilake scrolling
// @description:ka დაამატებს Widescreen + Fullscreen რეჟიმებს ChatGPT-ში გაუმჯობესებული ნახვა + გამოკლებული გადადების მიზნით
// @description:kk ChatGPT-ге Widescreen + Fullscreen режимдерін қосу арқылы көрініс үздіктемелеу + скроллауды кеміту
// @description:km បន្ថែមរបៀប Widescreen + Fullscreen ទៅក្នុង ChatGPT សម្រាប់ការមើលឡើងប្រហែលជាក្រុមហ៊ុន + ការរងចាំខ្លួនឯងប៉ុណ្ណោះ
// @description:kn ಅಭ್ಯಾಸಕ್ರಮದ ದೃಷ್ಟಿಗೆ ಅನುಗುಣವಾಗಿ Widescreen + Fullscreen ಮೋಡ್ಗಳನ್ನು ChatGPTಗೆ ಸೇರಿಸುತ್ತದೆ
// @description:ko ChatGPT에 와이드스크린 + 전체화면 모드를 추가하여 개선된 화면 표시 + 스크롤 감소
// @description:ku Dihênîne modên Widescreen + Fullscreenê bo ChatGPTê ji bo pêşînkirina nîşandina + kêmkirina kayanînê
// @description:ky ChatGPT-го Widescreen + Fullscreen режимдору кошо аркылуу жакшы көрүнүштү + скроллоо жоготуу
// @description:la TV + Fullscreen modos addit ChatGPT ad augendam viewing + reducta scrolling
// @description:lb Füügt Widescreen + Fullscreen Modi dem ChatGPT bäi fir verbessert Visioun + reduzéiert Scrollen
// @description:lo ເພີ່ມຮູບແບບ Widescreen + Fullscreen ໃຫ້ໄດ້ຮຽນ ChatGPT ສຳເລັດຂອງການສະແດງອ້າງວ່າງ + ການປະເມີດໃຫ້ນ້ໍາຂາຍຫນ້າ
// @description:lt Prideda Widescreen + Fullscreen režimus į ChatGPT, siekiant pagerinti peržiūrą ir sumažinti slinkimą
// @description:lv Pievieno Widescreen + Fullscreen režīmus ChatGPT, lai uzlabotu skatīšanos + samazinātu ritināšanu
// @description:mg Mametraka ny fomba Widescreen + Fullscreen amin'ny ChatGPT mba handresy ny fandefasana + famindrampoana ny firotsahana
// @description:mi Ka whakarite ana i ngā āhuatanga Widescreen + Fullscreen ki te ChatGPT mō te whakaatu whakapai ake + te whakaiti i te whakararuraru
// @description:mk Додава режими на Widescreen + Fullscreen во ChatGPT за подобрување на приказот + намалување на скролирањето
// @description:ml വായ്ഡ്സ്ക്രീൻ + പൂർണ്ണസ്ക്രീൻ മോഡുകൾ ചേർക്കുന്നു ChatGPT-യിൽ മിക്കവാറും കാഴ്ചപ്പാട് + കുറവ് തിരിക്കൽ ചെയ്യുന്നതിന്
// @description:mn Widescreen + Fullscreen горимуудыг ChatGPT рүү нэмэх нь дэлгэцэнд хувцаслан + гүйлгээний эвдрэлдээ хянахыг оруулна
// @description:mr व्हाइडस्क्रीन + फुलस्क्रीन मोड्स चे ChatGPTमध्ये जोडले जातात व पाहणी वाढविण्यासाठी स्क्रोलिंग कमी करतात
// @description:ms Menambah mod Widescreen + Layar Penuh ke ChatGPT untuk tampilan yang lebih baik + pengurangan penatalan
// @description:mt Jiddoqq modes Widescreen + Fullscreen għal ChatGPT għall-viżwalizzazzjoni miġġielda + qasam it-telf
// @description:my ပိုမိုကောင်းမွန်သောကြည့်ရှုရန်အတွက် ChatGPT တွင် Widescreen + မျက်နှာပြင်အပြည့်မုဒ်များကို ထည့်သွင်းထားသည်။
// @description:ne सुधारिएको दृश्य + कम स्क्रोलिंगका लागि वाइडस्क्रिन + फुलस्क्रिन मोडहरूलाई ChatGPTमा थप्दछ
// @description:nl Voegt Widescreen + Fullscreen modi toe aan ChatGPT voor verbeterde weergave + verminderd scrollen
// @description:no Legger til Widescreen + Fullskjerm-moduser i ChatGPT for forbedret visning + redusert rulling
// @description:ny Ndiwonetsa zolengedwa + Zomwe zosowa ndi ChatGPT kwa kudzaza kuona + kuchotsa kupinda
// @description:pa ਚਾਟਜੀਪੀਟੀ ਵਿੱਚ Widescreen + Fullscreen ਮੋਡਾਂ ਸ਼ਾਮਿਲ ਕਰਦਾ ਹੈ ਜਿਹਨਾਂ ਨਾਲ ਵੇਖਾਉਣ ਵਧੀਆ ਹੋ ਜਾਂਦਾ ਹੈ + ਘੂਮਣ ਦੀ ਘਟ-ਪੁਟ ਹੋ ਜਾਂਦੀ ਹੈ
// @description:pl Dodaje tryby Widescreen + Fullscreen do ChatGPT dla lepszej widoczności + zmniejszonego przewijania
// @description:ps ځانګړې + ټولې پرده په ChatGPT کې اضافه کړي لپاره لاسرسی ترلاسه کړي + کوښښول په کمته
// @description:pt Adiciona modos Widescreen + Tela cheia ao ChatGPT para visualização aprimorada + rolagem reduzida
// @description:pt-BR Adiciona modos Widescreen + Tela cheia ao ChatGPT para visualização aprimorada + rolagem reduzida
// @description:ro Adaugă modurile Widescreen + Ecran complet la ChatGPT pentru vizualizare îmbunătățită + defilare redusă
// @description:ru Добавляет режимы Widescreen + Fullscreen в ChatGPT для улучшенного просмотра + сокращенной прокрутки
// @description:rw Ongeraho Mugari Mugari + Byuzuye Mugaragaza kuri ChatGPT kugirango ubone kureba neza + kugabanya umuzingo
// @description:sg Ajoute les modes écran large + plein écran à ChatGPT pour une meilleure visualisation + un défilement réduit
// @description:si ChatGPT සඳහා Widescreen + Fullscreen ප්රදර්ශනයක් එක් කරයි තවත් පෙන්වන්නේ දැන් සිතූවාසිකාරක්ෂක විසින් සහ කෙසේදැයි ඇති අගයන් හුස්ම ක්රියාවලියකි
// @description:sk Pridáva Widescreen + Fullscreen režimy do ChatGPT pre vylepšené zobrazenie + zníženie posúvania
// @description:sl Dodaja Widescreen + Fullscreen načine v ChatGPT za izboljšan prikaz + zmanjšano premikanje
// @description:sm Faamauina Widescreen + Fullscreen faavae i le ChatGPT mo le faailoga faapea le mafaufau + le auina faavaivai
// @description:sn Ongorora Mutaundi wa Widescreen + Fullscreen muChatGPT kutora dzokubvumidzwa + kusha kusweropfuura
// @description:so Wax ka beddelaa Hababka Widescreen + Fullscreen ee ChatGPT si aad u fiirsato + si aad u yaraato garaabinta
// @description:sq Shton modalitete Widescreen + Fullscreen në ChatGPT për pamje të përmirësuar + ulje të skrollimit
// @description:sr Додаје Widescreen + Fullscreen режиме у ЧатГПТ за унапређен приказ + смањено листање
// @description:st E ngolisitsoe mokhabo Widescreen + Fullscreen ho ChatGPT bakeng sa mofuta ona le ho fokotsa liphalantere
// @description:sv Lägger till Widescreen + Fullscreen-lägen i ChatGPT för förbättrad visning + minskad scrollning
// @description:sw Inaongeza modes Widescreen + Fullscreen kwenye ChatGPT kwa kuimarisha kuonyesha + kupunguza kusokota
// @description:ta மேலதிரும் பார்வை + சுழற்சியை மோதித்து சாட்ஜிபிடியில் Widescreen + Fullscreen முறைகளைச் சேர்க்கிறது
// @description:te Widescreen + Fullscreen మోడ్లను ChatGPTకి చేర్చుకోవడంతో చంపుకునే వీక్షణ కనిపించడానికి స్క్రోల్ తక్కువగా మార్చండి
// @description:tg Маводиҳои Widescreen + Fullscreen-ро ба ChatGPT илова мекунад, барои кӯҳнашудаи намоиш + кам кардани скроллаш
// @description:th เพิ่มโหมดจอแบบ Widescreen + Fullscreen ใน ChatGPT สำหรับการดูที่ดีขึ้น + การเลื่อนลดลง
// @description:ti ንዝለዓለ ምርኣይ + ምጉዳል ምዝዋር ኣብ ChatGPT Widescreen + Fullscreen modes ይውስኽ
// @description:tk Giňeldilen görmek + peseltmek üçin ChatGPT-ä giň ekran + Doly ekran reesimlerini goşýar
// @description:tl Nagdaragdag ng mga mode ng Widescreen + Fullscreen sa ChatGPT para sa pinabuting pagtingin + pinaikling pag-scroll
// @description:tn Inowedzera Widescreen + Fullscreen modes kuChatGPT yekuwedzera kutarisa + kuderedzwa kupuruzira
// @description:to Hoʻohui i ka Widescreen + Fullscreen modes i ChatGPT no ka hoʻonui ʻia ʻana o ka nānā ʻana + hoʻemi i ka ʻōwili ʻana
// @description:tr Geliştirilmiş görüntüleme + azaltılmış kaydırma için ChatGPT'ye Widescreen + Fullscreen modları ekler
// @description:tt ChatGPT-га Widescreen + Fullscreen рәжимләрен өстәәдегезгә, күрүләштеңләри үткәргә + скроллауны буянтартарга
// @description:ug ChatGPTغا Widescreen + Fullscreen كۆرۈنمە پەسەند قىلىش+يىتىپ ئاجرا قىلىش مۆچىيى
// @description:uk Додає режими Widescreen + Fullscreen до ChatGPT для поліпшеного перегляду + зменшення прокрутки
// @description:ur ترقی یافتہ دیکھائی کے لئے ChatGPT میں وائڈ اسکرین + پوری اسکرین موڈز شامل کرتا ہے
// @description:uz ChatGPT-ga Widescreen + Fullscreen rejimlarini qo'shadi, ko'rishni yaxshilash + aylantirishni kamaytirish uchun
// @description:vi Thêm chế độ Widescreen + Fullscreen vào ChatGPT để cải thiện hiển thị + giảm cuộn trang
// @description:wo Bëgg na ñiis-ñiis Widescreen + Fullscreen ci ChatGPT buñ leen waxtu dib lu jàmm + ñaari jëm
// @description:xh Enza izimvo Widescreen + Fullscreen kwakuhlanganiselelwa kwiChatGPT ukuze kube khona okukhulu + kokucima kwesithombe
// @description:yi מוסיף Widescreen + Fullscreen מאָדעס צו ChatGPT פֿאַר ימפּרוווד וויוינג + רידוסט סקראָללינג
// @description:yo Fi àwọn ohun ọrọ Widescreen + Fullscreen si ChatGPT fun iwọle aiyewo + iwọle ififunwọle
// @description:zh 向 ChatGPT 添加宽屏 + 全屏模式以增强查看效果 + 减少滚动
// @description:zh-CN 向 ChatGPT 添加宽屏 + 全屏模式以增强查看效果 + 减少滚动
// @description:zh-HK 向 ChatGPT 添加寬屏 + 全屏模式以增強查看效果 + 減少滾動
// @description:zh-SG 向 ChatGPT 添加宽屏 + 全屏模式以增强查看效果 + 减少滚动
// @description:zh-TW 向 ChatGPT 添加寬屏 + 全屏模式以增強查看效果 + 減少滾動
// @description:zu Engeza izinhlobo zezimodi ze-Widescreen + Fullscreen ku-ChatGPT ukuze kube nokubonakala + ukuncitsha ukusukela
// @author Adam Lui
// @namespace https://github.com/adamlui
// @version 2024.8.30.1
// @license MIT
// @compatible chrome
// @compatible firefox
// @compatible edge
// @compatible opera
// @compatible brave
// @compatible vivaldi
// @compatible librewolf
// @compatible ghost
// @compatible qq
// @match *://chatgpt.com/*
// @match *://chat.openai.com/*
// @match *://poe.com/*
// @icon https://media.chatgptwidescreen.com/images/icons/widescreen-robot-emoji/icon48.png?9a393be
// @icon64 https://media.chatgptwidescreen.com/images/icons/widescreen-robot-emoji/icon64.png?9a393be
// @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.1.0/dist/chatgpt.min.js#sha256-7NZavwKnOeU+AC6WBVJP9kl6BNFlT7go8qSKat7Ey4Y=
// @connect cdn.jsdelivr.net
// @connect greasyfork.org
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_xmlhttpRequest
// @grant GM.xmlHttpRequest
// @noframes
// @homepageURL https://www.chatgptwidescreen.com
// @supportURL https://support.chatgptwidescreen.com
// @contributionURL https://github.com/sponsors/adamlui
// ==/UserScript==
// Documentation: https://docs.chatgptwidescreen.com
// NOTE: This script relies on the powerful chatgpt.js library @ https://chatgpt.js.org © 2023–2024 KudoAI & contributors under the MIT license.
(async () => { /* global newChatBtn, wideScreenBtn, fullWindowBtn, fullScreenBtn */
const site = new URL(document.location.href).hostname.split('.').slice(-2, -1)[0]
// Init CONFIG
const config = {
appName: 'ChatGPT Widescreen Mode', appSymbol: '🖥️', keyPrefix: site + 'Widescreen',
gitHubURL: 'https://github.com/adamlui/chatgpt-widescreen',
greasyForkURL: 'https://greasyfork.org/scripts/461473-chatgpt-widescreen-mode',
latestAssetCommitHash: 'd112844' } // for messages.json
config.updateURL = config.greasyForkURL.replace('https://', 'https://update.')
.replace(/(\d+)-?([a-zA-Z-]*)$/, (_, id, name) => `${ id }/${ !name ? 'script' : name }.meta.js`)
config.supportURL = config.gitHubURL + '/issues/new'
config.assetHostURL = config.gitHubURL.replace('github.com', 'cdn.jsdelivr.net/gh') + `@${config.latestAssetCommitHash}/`
config.userLanguage = chatgpt.getUserLanguage()
loadSetting('autoFocusChatbarDisabled', 'fullerWindows', 'fullWindow', 'hiddenFooter', 'hiddenHeader',
'notifDisabled', 'ncbDisabled', 'tcbDisabled', 'widerChatbox', 'wideScreen')
// Init FETCHER
const xhr = getUserscriptManager() == 'OrangeMonkey' ? GM_xmlhttpRequest : GM.xmlHttpRequest
// Define MESSAGES
const msgsLoaded = new Promise(resolve => {
const msgHostDir = config.assetHostURL + 'greasemonkey/_locales/',
msgLocaleDir = ( config.userLanguage ? config.userLanguage.replace('-', '_') : 'en' ) + '/'
let msgHref = msgHostDir + msgLocaleDir + 'messages.json', msgXHRtries = 0
xhr({ method: 'GET', url: msgHref, onload: onLoad })
function onLoad(resp) {
try { // to return localized messages.json
const msgs = JSON.parse(resp.responseText), flatMsgs = {}
for (const key in msgs) // remove need to ref nested keys
if (typeof msgs[key] == 'object' && 'message' in msgs[key])
flatMsgs[key] = msgs[key].message
resolve(flatMsgs)
} catch (err) { // if bad response
msgXHRtries++ ; if (msgXHRtries == 3) return resolve({}) // try up to 3X (original/region-stripped/EN) only
msgHref = config.userLanguage.includes('-') && msgXHRtries == 1 ? // if regional lang on 1st try...
msgHref.replace(/([^_]+_[^_]+)_[^/]*(\/.*)/, '$1$2') // ...strip region before retrying
: ( msgHostDir + 'en/messages.json' ) // else use default English messages
xhr({ method: 'GET', url: msgHref, onload: onLoad })
}
}
}) ; const msgs = await msgsLoaded
// Define SCRIPT functions
function loadSetting(...keys) { keys.forEach(key => config[key] = GM_getValue(`${ config.keyPrefix }_${ site }_${ key }`, false)) }
function saveSetting(key, value) { GM_setValue(`${ config.keyPrefix }_${ site }_${ key }`, value) ; config[key] = value }
function safeWindowOpen(url) { window.open(url, '_blank', 'noopener') } // to prevent backdoor vulnerabilities
function getUserscriptManager() { try { return GM_info.scriptHandler } catch (err) { return 'other' }}
// Define MENU functions
function registerMenu() {
// Add command to also activate wide screen in full-window
const fwLabel = menuState.symbol[+config.fullerWindows] + ' '
+ ( msgs.menuLabel_fullerWins || 'Fuller Windows' )
+ menuState.separator + menuState.word[+config.fullerWindows]
menuIDs.push(GM_registerMenuCommand(fwLabel, () => {
saveSetting('fullerWindows', !config.fullerWindows)
syncFullerWindows(config.fullerWindows) // live update on click
if (!config.notifDisabled) notify(
`${ ( msgs.menuLabel_fullerWins || 'Fuller Windows' ) }: ${ menuState.word[+config.fullerWindows] }`)
refreshMenu()
}))
// Add command to toggle taller chatbox when typing
const tcbLabel = '↕️ ' + ( msgs.menuLabel_tallerChatbox || 'Taller Chatbox' )
+ menuState.separator + menuState.word[+!config.tcbDisabled]
menuIDs.push(GM_registerMenuCommand(tcbLabel, () => {
saveSetting('tcbDisabled', !config.tcbDisabled)
updateTweaksStyle()
if (!config.notifDisabled) notify(
`${ msgs.menuLabel_tallerChatbox || 'Taller Chatbox' }: ${ menuState.word[+!config.tcbDisabled] }`)
refreshMenu()
}))
// Add command to toggle wider chatbox w/ widescreen mode in Poe
if (site == 'poe') {
const wcbLabel = '↔️ ' + ( msgs.menuLabel_widerChatbox || 'Wider Chatbox' )
+ menuState.separator + menuState.word[+config.widerChatbox]
menuIDs.push(GM_registerMenuCommand(wcbLabel, () => {
saveSetting('widerChatbox', !config.widerChatbox)
updateWidescreenStyle()
if (!config.notifDisabled) notify(
`${ msgs.menuLabel_widerChatbox || 'Wider Chatbox' }: ${ menuState.word[+config.widerChatbox] }`)
refreshMenu()
}))
}
// Add command to hide New Chat button
const hncLabel = menuState.symbol[+!config.ncbDisabled] + ' '
+ ( msgs.menuLabel_newChatBtn || 'New Chat Button' )
+ menuState.separator + menuState.word[+!config.ncbDisabled]
menuIDs.push(GM_registerMenuCommand(hncLabel, () => {
saveSetting('ncbDisabled', !config.ncbDisabled)
updateTweaksStyle()
notify(`${ msgs.menuLabel_newChatBtn || 'New Chat Button' }: ${ menuState.word[+!config.ncbDisabled] }`)
refreshMenu()
}))
if (/chatgpt|openai/.test(site)) {
// Add command to toggle Auto-Focus Chatbar
const afcLabel = menuState.symbol[+!config.autoFocusChatbarDisabled] + ' '
+ ( msgs.menuLabel_autoFocusChatbar || 'Auto-Focus Chatbar' ) + ' '
+ menuState.separator + menuState.word[+!config.autoFocusChatbarDisabled]
menuIDs.push(GM_registerMenuCommand(afcLabel, () => {
saveSetting('autoFocusChatbarDisabled', !config.autoFocusChatbarDisabled)
notify(( msgs.menuLabel_autoFocusChatbar || 'Auto-Focus Chatbar' ) + ' '
+ menuState.word[+!config.autoFocusChatbarDisabled])
if (!config.autoFocusChatbarDisabled) document.querySelector(inputSelector)?.focus()
refreshMenu()
}))
// Add command to toggle hidden header
const hhLabel = menuState.symbol[+config.hiddenHeader] + ' '
+ ( msgs.menuLabel_hiddenHeader || 'Hidden Header' )
+ menuState.separator + menuState.word[+config.hiddenHeader]
menuIDs.push(GM_registerMenuCommand(hhLabel, () => {
saveSetting('hiddenHeader', !config.hiddenHeader)
updateTweaksStyle()
if (!config.notifDisabled) notify(
`${ msgs.menuLabel_hiddenHeader || 'Hidden Header' }: ${ menuState.word[+config.hiddenHeader] }`)
refreshMenu()
}))
// Add command to toggle hidden footer
const hfLabel = menuState.symbol[+config.hiddenFooter] + ' '
+ ( msgs.menuLabel_hiddenFooter || 'Hidden Footer' )
+ menuState.separator + menuState.word[+config.hiddenFooter]
menuIDs.push(GM_registerMenuCommand(hfLabel, () => {
saveSetting('hiddenFooter', !config.hiddenFooter)
updateTweaksStyle()
if (!config.notifDisabled) notify(
`${ msgs.menuLabel_hiddenFooter || 'Hidden Footer' }: ${ menuState.word[+config.hiddenFooter] }`)
refreshMenu()
}))
}
// Add command to show notifications when switching modes
const mnLabel = menuState.symbol[+!config.notifDisabled] + ' '
+ ( msgs.menuLabel_modeNotifs || 'Mode Notifications' )
+ menuState.separator + menuState.word[+!config.notifDisabled]
menuIDs.push(GM_registerMenuCommand(mnLabel, () => {
saveSetting('notifDisabled', !config.notifDisabled)
notify(`${ msgs.menuLabel_modeNotifs || 'Mode Notifications' }: ${ menuState.word[+!config.notifDisabled] }`)
refreshMenu()
}))
// Add command to launch About modal
const amLabel = `💡 ${ msgs.menuLabel_about || 'About' } ${ msgs.appName || config.appName }`
menuIDs.push(GM_registerMenuCommand(amLabel, launchAboutModal))
}
function refreshMenu() {
if (getUserscriptManager() == 'OrangeMonkey') return
for (const id of menuIDs) { GM_unregisterMenuCommand(id) } registerMenu()
}
function launchAboutModal() {
// Show alert
const chatgptJSver = (/chatgpt-([\d.]+)\.min/.exec(GM_info.script.header) || [null, ''])[1],
headingStyle = 'font-size: 1.15rem',
pStyle = 'position: relative ; left: 3px',
pBrStyle = 'position: relative ; left: 4px ',
aStyle = 'color: ' + ( chatgpt.isDarkMode() ? '#c67afb' : '#8325c4' ) // purple
const aboutModalID = siteAlert(
msgs.appName || config.appName, // title
`<span style="${ headingStyle }"><b>🏷️ <i>${ msgs.about_version || 'Version' }</i></b>: </span>`
+ `<span style="${ pStyle }">${ GM_info.script.version }</span>\n`
+ `<span style="${ headingStyle }"><b>⚡ <i>${ msgs.about_poweredBy || 'Powered by' }</i></b>: </span>`
+ `<span style="${ pStyle }"><a style="${ aStyle }" href="https://chatgpt.js.org" target="_blank" rel="noopener">`
+ 'chatgpt.js</a>' + ( chatgptJSver ? ( ' v' + chatgptJSver ) : '' ) + '</span>\n'
+ `<span style="${ headingStyle }"><b>📜 <i>${ msgs.about_sourceCode || 'Source code' }</i></b>:</span>\n`
+ `<span style="${ pBrStyle }"><a href="${ config.gitHubURL }" target="_blank" rel="nopener">`
+ config.gitHubURL + '</a></span>',
[ // buttons
function checkForUpdates() { updateCheck() },
function getSupport() { safeWindowOpen(config.supportURL) },
function leaveAReview() { // show new modal
const reviewModalID = chatgpt.alert(( msgs.alert_choosePlatform || 'Choose a Platform' ) + ':', '',
[ function greasyFork() { safeWindowOpen(config.greasyForkURL + '/feedback#post-discussion') },
function productHunt() { safeWindowOpen(
'https://www.producthunt.com/products/chatgpt-widescreen-mode/reviews/new') }])
document.getElementById(reviewModalID).querySelector('button')
.style.display = 'none' }, // hide dismiss button
function moreChatGPTapps() { safeWindowOpen('https://github.com/adamlui/chatgpt-apps') }
], '', 478 // set width
)
// Re-format buttons to include emoji + localized label + hide Dismiss button
for (const button of document.getElementById(aboutModalID).querySelectorAll('button')) {
if (/updates/i.test(button.textContent)) button.textContent = (
'🚀 ' + ( msgs.btnLabel_updateCheck || 'Check for Updates' ))
else if (/support/i.test(button.textContent)) button.textContent = (
'🧠 ' + ( msgs.btnLabel_getSupport || 'Get Support' ))
else if (/review/i.test(button.textContent)) button.textContent = (
'⭐ ' + ( msgs.btnLabel_leaveReview || 'Leave Review' ))
else if (/apps/i.test(button.textContent)) button.textContent = (
'🤖 ' + ( msgs.btnLabel_moreApps || 'More ChatGPT Apps' ))
else button.style.display = 'none' // hide Dismiss button
}
}
function updateCheck() {
// Fetch latest meta
const currentVer = GM_info.script.version
xhr({
method: 'GET', url: config.updateURL + '?t=' + Date.now(),
headers: { 'Cache-Control': 'no-cache' },
onload: response => { const updateAlertWidth = 377
// Compare versions
const latestVer = /@version +(.*)/.exec(response.responseText)[1]
for (let i = 0 ; i < 4 ; i++) { // loop thru subver's
const currentSubVer = parseInt(currentVer.split('.')[i], 10) || 0,
latestSubVer = parseInt(latestVer.split('.')[i], 10) || 0
if (currentSubVer > latestSubVer) break // out of comparison since not outdated
else if (latestSubVer > currentSubVer) { // if outdated
// Alert to update
const updateModalID = siteAlert(`🚀 ${ msgs.alert_updateAvail || 'Update available' }!`, // title
`${ msgs.alert_newerVer || 'An update to' } ${ config.appName } `
+ ( msgs.appName || config.appName ) + ' '
+ `(v${ latestVer }) ${ msgs.alert_isAvail || 'is available' }! `
+ '<a target="_blank" rel="noopener" style="font-size: 0.7rem" '
+ 'href="' + config.gitHubURL + '/commits/main/greasemonkey/'
+ config.updateURL.replace(/.*\/(.*)meta\.js/, '$1user.js') + '"'
+ `> ${ msgs.link_viewChanges || 'View changes' }</a>`,
function update() { // button
safeWindowOpen(config.updateURL.replace('meta.js', 'user.js') + '?t=' + Date.now())
}, '', updateAlertWidth
)
// Localize button labels if needed
if (!config.userLanguage.startsWith('en')) {
const updateAlert = document.querySelector(`[id="${ updateModalID }"]`),
updateBtns = updateAlert.querySelectorAll('button')
updateBtns[1].textContent = msgs.btnLabel_update || 'Update'
updateBtns[0].textContent = msgs.btnLabel_dismiss || 'Dismiss'
}
return
}}
// Alert to no update, return to About modal
siteAlert(( msgs.alert_upToDate || 'Up-to-date' ) + '!', // title
`${ msgs.appName || config.appName } (v${ currentVer }) ` // msg
+ ( msgs.alert_isUpToDate || 'is up-to-date' ) + '!',
'', '', updateAlertWidth
)
launchAboutModal()
}})}
// Define FEEDBACK functions
function notify(msg, position = '', notifDuration = '', shadow = '') {
// Strip state word to append colored one later
const foundState = menuState.word.find(word => msg.includes(word))
if (foundState) msg = msg.replace(foundState, '')
// Show notification
chatgpt.notify(`${ config.appSymbol } ${ msg }`, position, notifDuration, shadow || chatgpt.isDarkMode() ? '' : 'shadow')
const notifs = document.querySelectorAll('.chatgpt-notif'),
notif = notifs[notifs.length -1]
// Append styled state word
if (foundState) {
const styledState = document.createElement('span')
styledState.style.cssText = `color: ${
foundState == menuState.word[0] ? '#ef4848 ; text-shadow: rgba(255, 169, 225, 0.44) 2px 1px 5px'
: '#5cef48 ; text-shadow: rgba(255, 250, 169, 0.38) 2px 1px 5px' }`
styledState.append(foundState) ; notif.append(styledState)
}
}
function siteAlert(title = '', msg = '', btns = '', checkbox = '', width = '') {
return chatgpt.alert(title, msg, btns, checkbox, width )}
// Define BUTTON functions
function setBtnColor() { return (
/chatgpt|openai/.test(site) ? (
document.querySelector('.dark.bg-black, [class*="dark:bg-gray"]') // temp chat post-GPT4-o, pre-GPT-4o
|| chatgpt.isDarkMode() ? 'white' : '#202123' )
: site == 'poe' ? 'currentColor' : ''
)}
function insertBtns() {
// Init chatbar
const chatbar = document.querySelector(inputSelector)?.parentNode.parentNode
if (!chatbar || chatbar.contains(wideScreenBtn)) return // if chatbar missing or buttons aren't missing, exit
// Tweak chatbar
if (/chatgpt|openai/.test(site)) // allow tooltips to overflow
chatbar.classList.remove('overflow-hidden')
else if (site == 'poe') { // left-align attach file button
const attachFileBtn = chatbar.querySelector('button[class*="File"]')
if (attachFileBtn) {
attachFileBtn.style.cssText = 'position: absolute ; left: 1rem ; bottom: 0.35rem'
document.querySelector(inputSelector).style.padding = '0 13px 0 40px' // accommodate new btn pos
}
}
// Insert buttons
const elemsToInsert = [newChatBtn, wideScreenBtn, fullWindowBtn, fullScreenBtn, tooltipDiv]
const elemToInsertBefore = (
/chatgpt|openai/.test(site) ? chatbar.querySelector('button[class*="right"]') // ChatGPT pre-5/2024
|| chatbar.lastChild // ChatGPT post-5/2024 + Poe
: chatbar.children[1] ) // Poe
elemsToInsert.forEach(elem => chatbar.insertBefore(elem, elemToInsertBefore))
}
function updateBtnSVG(mode, state = '') {
// Define SVG viewbox + elems
const svgViewBox = ( mode == 'newChat' ? '11 6 ' : mode == 'fullWindow' ? '-2 -0.5 ' : '8 8 ' ) // move to XY coords to crop whitespace
+ ( mode == 'newChat' ? '13 13' : mode == 'fullWindow' ? '24 24' : '20 20' ) // shrink to fit size
const fullScreenONelems = [
createSVGelem('path', { fill: btnColor, d: 'm14,14-4,0 0,2 6,0 0,-6 -2,0 0,4 0,0 z' }),
createSVGelem('path', { fill: btnColor, d: 'm22,14 0,-4 -2,0 0,6 6,0 0,-2 -4,0 0,0 z' }),
createSVGelem('path', { fill: btnColor, d: 'm20,26 2,0 0,-4 4,0 0,-2 -6,0 0,6 0,0 z' }),
createSVGelem('path', { fill: btnColor, d: 'm10,22 4,0 0,4 2,0 0,-6 -6,0 0,2 0,0 z' }) ]
const fullScreenOFFelems = [
createSVGelem('path', { fill: btnColor, d: 'm10,16 2,0 0,-4 4,0 0,-2 L 10,10 l 0,6 0,0 z' }),
createSVGelem('path', { fill: btnColor, d: 'm20,10 0,2 4,0 0,4 2,0 L 26,10 l -6,0 0,0 z' }),
createSVGelem('path', { fill: btnColor, d: 'm24,24 -4,0 0,2 L 26,26 l 0,-6 -2,0 0,4 0,0 z' }),
createSVGelem('path', { fill: btnColor, d: 'M 12,20 10,20 10,26 l 6,0 0,-2 -4,0 0,-4 0,0 z' }) ]
const fullWindowElems = [
createSVGelem('rect', { x: '3', y: '3', width: '17', height: '17', rx: '2', ry: '2' }),
createSVGelem('line', { x1: '9', y1: '3', x2: '9', y2: '21' }) ]
const wideScreenONelems = [
createSVGelem('path', { fill: btnColor, 'fill-rule': 'evenodd',
d: 'm26,13 0,10 -16,0 0,-10 z m-14,2 12,0 0,6 -12,0 0,-6 z' }) ]
const wideScreenOFFelems = [
createSVGelem('path', { fill: btnColor, 'fill-rule': 'evenodd',
d: 'm28,11 0,14 -20,0 0,-14 z m-18,2 16,0 0,10 -16,0 0,-10 z' }) ]
const newChatElems = [ createSVGelem('path', { fill: btnColor, d: 'M22,13h-4v4h-2v-4h-4v-2h4V7h2v4h4V13z' }) ]
// Pick appropriate button/elements
const [button, ONelems, OFFelems] = (
mode == 'fullScreen' ? [fullScreenBtn, fullScreenONelems, fullScreenOFFelems]
: mode == 'fullWindow' ? [fullWindowBtn, fullWindowElems, fullWindowElems]
: mode == 'wideScreen' ? [wideScreenBtn, wideScreenONelems, wideScreenOFFelems]
: [newChatBtn, newChatElems, newChatElems])
// Set SVG attributes
const buttonSVG = button.querySelector('svg') || document.createElementNS('http://www.w3.org/2000/svg', 'svg')
buttonSVG.setAttribute('height', 18) // prevent shrinking
if (mode == 'fullWindow') { // stylize full-window button
buttonSVG.setAttribute('stroke', btnColor)
buttonSVG.setAttribute('fill', 'none')
buttonSVG.setAttribute('stroke-width', '2')
buttonSVG.setAttribute('height', site == 'poe' ? '2em' : 17)
buttonSVG.setAttribute('width', site == 'poe' ? '2em' : 17)
}
buttonSVG.setAttribute('viewBox', svgViewBox) // set pre-tweaked viewbox
buttonSVG.style.pointerEvents = 'none' // prevent triggering tooltips twice
if (/chatgpt|openai/.test(site)) // override button resizing
buttonSVG.style.height = buttonSVG.style.width = `${ isGPT4oUI ? 1.25 : 1.3 }rem`
// Update SVG elements
while (buttonSVG.firstChild) { buttonSVG.removeChild(buttonSVG.firstChild) }
const svgElems = config[mode] || state.toLowerCase() == 'on' ? ONelems : OFFelems
svgElems.forEach(elem => buttonSVG.append(elem))
// Update SVG
if (!button.contains(buttonSVG)) button.append(buttonSVG)
}
function sendBtnIsLoaded() { // for borrowing classes
return new Promise(resolve => {
new MutationObserver((mutations, obs) => {
if (chatgpt.getSendBtn()) { obs.disconnect() ; resolve(true) }}
).observe(document.body, { childList: true, subtree: true })
})
}
function createSVGelem(tagName, attributes) {
const elem = document.createElementNS('http://www.w3.org/2000/svg', tagName)
for (const attr in attributes) elem.setAttributeNS(null, attr, attributes[attr])
return elem
}
// Define TOOLTIP functions
function toggleTooltip(event) {
updateTooltip(event.currentTarget.id.replace(/-button$/, ''))
tooltipDiv.style.opacity = event.type == 'mouseover' ? '1' : '0'
}
function updateTooltip(buttonType) { // text & position
tooltipDiv.innerText = msgs['tooltip_' + buttonType + (
!/full|wide/i.test(buttonType) ? '' : (config[buttonType] ? 'OFF' : 'ON'))]
const ctrAddend = 25 + ( site == 'poe' ? 45 : 12 ),
spreadFactor = site == 'poe' ? 35 : 30.5,
iniRoffset = spreadFactor * ( buttonType.includes('fullScreen') ? 1
: buttonType.includes('fullWindow') ? 2
: buttonType.includes('wide') ? 3 : 4 ) + ctrAddend
tooltipDiv.style.right = `${ // horizontal position
iniRoffset - tooltipDiv.getBoundingClientRect().width /2 }px`
}
// Define TOGGLE functions
function activateMode(mode) {
if (mode == 'wideScreen') { document.head.append(wideScreenStyle) ; syncMode('wideScreen') }
else if (mode == 'fullWindow') {
document.head.append(fullWindowStyle)
if (site == 'poe') syncMode('fullWindow') ; else chatgpt.sidebar.hide()
} else if (mode == 'fullScreen') document.documentElement.requestFullscreen()
}
function deactivateMode(mode) {
if (mode == 'wideScreen')
try { document.head.removeChild(wideScreenStyle) ; syncMode('wideScreen') } catch (err) {}
else if (mode == 'fullWindow') {
try { document.head.removeChild(fullWindowStyle) } catch (err) {}
if (/chatgpt|openai/.test(site)) chatgpt.sidebar.show()
else if (site == 'poe') syncMode('fullWindow') // since not sidebarObserve()'d
} else if (mode == 'fullScreen') {
if (config.f11)
siteAlert(msgs.alert_pressF11 || 'Press F11 to exit full screen',
( msgs.alert_f11reason || 'F11 was used to enter full screen, and due to browser security reasons,'
+ 'the same key must be used to exit it' ) + '.')
document.exitFullscreen().catch(err => console.error(config.appSymbol + ' » Failed to exit fullscreen', err))
}
}
function toggleMode(mode, state = '') {
switch (state.toUpperCase()) {
case 'ON' : activateMode(mode) ; break
case 'OFF' : deactivateMode(mode) ; break
default : config[mode] ? deactivateMode(mode) : activateMode(mode)
}
}
// Define SYNC functions
function isFullWindow() {
return site == 'poe' ? !!document.getElementById('fullWindow-mode')
: chatgpt.sidebar.isOff()
}
function syncMode(mode) { // setting + icon + tooltip
const state = ( mode == 'wideScreen' ? !!document.getElementById('wideScreen-mode')
: mode == 'fullWindow' ? isFullWindow()
: chatgpt.isFullScreen() )
saveSetting(mode, state) ; updateBtnSVG(mode) ; updateTooltip(mode)
if (mode == 'fullWindow') syncFullerWindows(state)
if (!config.notifDisabled) // notify synced state
notify(`${ msgs['mode_' + mode] } ${ state ? 'ON' : 'OFF' }`)
config.modeSynced = true ; setTimeout(() => config.modeSynced = false, 100) // prevent repetition
}
function syncFullerWindows(fullWindowState) {
if (fullWindowState && config.fullerWindows && !config.wideScreen) { // activate fuller windows
document.head.append(wideScreenStyle) ; updateBtnSVG('wideScreen', 'on')
} else if (!fullWindowState) { // de-activate fuller windows
try { document.head.removeChild(fullWindowStyle) } catch (err) {} // to remove style too so sidebar shows
if (!config.wideScreen) { // disable widescreen if result of fuller window
try { document.head.removeChild(wideScreenStyle) } catch (err) {}
updateBtnSVG('wideScreen', 'off')
}}}
function updateTweaksStyle() {
tweaksStyle.innerText = (
/chatgpt|openai/.test(site) ? (
( inputSelector + '{ margin-right: -43px }' ) // widen/narrow input to be flush w/ btns
+ ( '[id$="-button"]:hover { opacity: 80% !important }' ) // dim chatbor btns on hover
+ ( config.hiddenHeader ? hhStyle : '' ) // hide header
+ ( config.hiddenFooter ? hfStyle : '' )) // hide footer
: site == 'poe' ? 'button[class*="Voice"] { margin: 0 -3px 0 -8px }' // h-pad mic btn for even spread
: '' )
+ ( !config.tcbDisabled ? tcbStyle : '' ) // expand text input vertically
+ `#newChat-button { display: ${ config.ncbDisabled ? 'none' : 'flex' }}`
}
function updateWidescreenStyle() {
wideScreenStyle.innerText = (
/chatgpt|openai/.test(site) ? (
'.text-base { max-width: 100% !important }' // widen outer container
+ '.text-base:nth-of-type(2) { max-width: 97% !important }' // widen inner container
+ '#__next > div > div.flex { width: 100px }' ) // prevent sidebar shrinking when zoomed
: site == 'poe' ? (
'[class*="ChatMessagesView"] { width: 100% !important }' // widen outer container
+ '[class^="Message"] { max-width: 100% !important }' ) // widen speech bubbles
: '' )
if (config.widerChatbox) wideScreenStyle.innerText += wcbStyle
}
// Run MAIN routine
// Init MENU objs
const menuIDs = [] // to store registered cmds for removal while preserving order
const menuState = {
symbol: ['❌', '✔️'], word: ['OFF', 'ON'],
separator: getUserscriptManager() == 'Tampermonkey' ? ' — ' : ': '
}
// Define UI element SELECTORS
const inputSelector = /chatgpt|openai/.test(site) ? '#prompt-textarea'
: site == 'poe' ? '[class*="InputContainer_textArea"] textarea, [class*="InputContainer_textArea"]::after' : '',
sidebarSelector = /chatgpt|openai/.test(site) ? '#__next > div > div.dark'
: site == 'poe' ? 'menu[class*="sidebar"], aside[class*="sidebar"]' : '',
sidepadSelector = '#__next > div > div',
headerSelector = /chatgpt|openai/.test(site) ? 'main .sticky' : ''
let footerSelector = 'footer'
try { footerSelector = /chatgpt|openai/.test(site) ?
chatgpt.getFooterDiv()?.classList.toString().replace(/([:[\]\\])/g, '\\$1').replace(/^| /g, '.') : ''
} catch (err) {}
// Create browser TOOLBAR MENU or DISABLE SCRIPT if extension installed
const extensionInstalled = await Promise.race([
new Promise(resolve => {
(function checkExtensionInstalled() {
if (document.querySelector('[cwm-extension-installed]')) resolve(true)
else setTimeout(checkExtensionInstalled, 200)
})()
}), new Promise(resolve => setTimeout(() => resolve(false), 1500))])
if (extensionInstalled) { // disable script/menu
GM_registerMenuCommand(menuState.symbol[0] + ' ' + ( msgs.menuLabel_disabled || 'Disabled (extension installed)' ),
() => { return }) // disable menu
return // exit script
} else registerMenu() // create functional menu
// AUTO-FOCUS ChatGPT chatbar if enabled
if (/chatgpt|openai/.test(site) && !config.autoFocusChatbarDisabled) {
await Promise.race([
new Promise(resolve => {
(function checkSecondChatbarBtn() { // since it causes de-focus
const chatbarBtns = document.querySelector('inputSelector')?.parentNode.parentNode.getElementsByTagName('button')
chatbarBtns?.length >= 2 ? resolve(true) : setTimeout(checkSecondChatbarBtn, 200)
})();
}), new Promise(resolve => setTimeout(resolve, 3000)) // timeout after 3s
])
document.querySelector(inputSelector)?.focus()
}
// Init UI flag
const isGPT4oUI = document.documentElement.className.includes(' ')
// Save FULL-WINDOW + FULL SCREEN states
config.fullWindow = /chatgpt|openai/.test(site) ? isFullWindow() : config.fullWindow
config.fullScreen = chatgpt.isFullScreen()
// Stylize ALERTS
if (!document.getElementById('chatgpt-alert-override-style')) {
const chatgptAlertStyle = document.createElement('style')
chatgptAlertStyle.id = 'chatgpt-alert-override-style'
chatgptAlertStyle.innerText = (
( chatgpt.isDarkMode() ? '.chatgpt-modal > div { border: 1px solid white }' : '' )
+ '.chatgpt-modal button {'
+ 'font-size: 0.77rem ; text-transform: uppercase ;'
+ 'border-radius: 0 !important ; padding: 5px !important ; min-width: 102px }'
+ '.chatgpt-modal button:hover { transform: scale(1.055) }'
+ '.modal-buttons { margin-left: -13px !important }'
)
document.head.append(chatgptAlertStyle)
}
// Create/stylize TOOLTIP div
const tooltipDiv = document.createElement('div')
tooltipDiv.classList.add('toggle-tooltip')
const tooltipStyle = document.createElement('style')
tooltipStyle.innerText = '.toggle-tooltip {'
+ 'background-color: rgba(0, 0, 0, 0.71) ; padding: 5px ; border-radius: 6px ; border: 1px solid #d9d9e3 ;' // bubble style
+ 'font-size: 0.85rem ; color: white ;' // font style
+ 'position: absolute ; bottom: 50px ;' // v-position
+ 'box-shadow: 4px 6px 16px 0 rgb(0 0 0 / 38%) ;' // drop shadow
+ 'opacity: 0 ; transition: opacity 0.1s ; z-index: 9999 ;' // visibility
+ '-webkit-user-select: none ; -moz-user-select: none ; -ms-user-select: none ; user-select: none }' // disable select
document.head.append(tooltipStyle)
// Create/apply general style TWEAKS
const tweaksStyle = document.createElement('style'),
tcbStyle = inputSelector + '{ max-height: 68vh !important }', // heighten chatbox
hhStyle = headerSelector + '{ display: none !important }' // hide header
+ ( /chatgpt|openai/.test(site) ? 'main { padding-top: 12px }' : '' ), // increase top-padding
hfStyle = footerSelector + '{ color: transparent !important ;' // hide footer text
+ ' padding: .1rem 0 0 !important }' // reduce v-padding
updateTweaksStyle() ; document.head.append(tweaksStyle)
// Create WIDESCREEN style
const wideScreenStyle = document.createElement('style')
wideScreenStyle.id = 'wideScreen-mode' // for syncMode()
const wcbStyle = ( // Wider Chatbox for updateWidescreenStyle()
/chatgpt|openai/.test(site) ? 'main form { max-width: 96% !important }'
: site == 'poe' ? '[class*=footerInner] { width: 100% }' : '' )
updateWidescreenStyle()
// Create FULL-WINDOW style
const fullWindowStyle = document.createElement('style')
fullWindowStyle.id = 'fullWindow-mode' // for syncMode()
fullWindowStyle.innerText = (
sidebarSelector + '{ display: none }' // hide sidebar
+ sidepadSelector + '{ padding-left: 0 }' ) // remove side padding
// Create/insert chatbar BUTTONS
const buttonTypes = ['fullScreen', 'fullWindow', 'wideScreen', 'newChat'],
bOffset = site == 'poe' ? -1.5 : -13, rOffset = site == 'poe' ? -6 : -4
let btnColor = setBtnColor()
for (let i = 0 ; i < buttonTypes.length ; i++) {
(buttonType => { // enclose in IIFE to separately capture button type for async listeners
const buttonName = buttonType + 'Btn'
window[buttonName] = document.createElement('div') // create button
window[buttonName].id = buttonType + '-button' // for toggleTooltip()
updateBtnSVG(buttonType) // insert icon
window[buttonName].style.cssText = 'position: relative ; top: 0 ;'
+ `right: ${ rOffset + i * bOffset }px` // position left of prev button
window[buttonName].style.cursor = 'pointer' // add finger cursor
if (isGPT4oUI || site == 'poe') window[buttonName].style.position = 'relative' // override static pos
if (/chatgpt|openai/.test(site)) { // assign classes + tweak styles
sendBtnIsLoaded().then(() => {
window[buttonName].setAttribute('class', chatgpt.getSendBtn().classList)
window[buttonName].style.backgroundColor = 'transparent' // remove dark mode overlay
window[buttonName].style.borderColor = 'transparent' // remove dark mode overlay
})
} else if (site == 'poe') // lift buttons slightly
window[buttonName].style.marginBottom = ( buttonType == 'newChat' ? '0.45' : '0.2' ) + 'rem'
// Add click/hover listeners
window[buttonName].onclick = () => {
if (buttonType == 'newChat') {
if (/chatgpt|openai/.test(site)) chatgpt.startNewChat()
else if (site == 'poe') document.querySelector('header a[class*="button"]')?.click()
} else toggleMode(buttonType)
}
window[buttonName].onmouseover = toggleTooltip
window[buttonName].onmouseout = toggleTooltip
})(buttonTypes[i])
} insertBtns()
// Monitor NODE CHANGES to auto-toggle once + maintain button visibility + update colors
let isTempChat = false, prevSessionChecked = false
const nodeObserver = new MutationObserver(([mutation]) => {
// Check loaded keys to restore previous session's state
if (!prevSessionChecked) {
if (config.wideScreen) toggleMode('wideScreen', 'ON')
if (config.fullWindow) { toggleMode('fullWindow', 'ON')
if (/chatgpt|openai/.test(site)) { // sidebar observer doesn't trigger
syncFullerWindows(true) // so sync Fuller Windows...
if (!config.notifDisabled) // ... + notify
notify(( msgs.mode_fullWindow || 'Full-window' ) + ' ON')
}}
if (config.tcbDisabled) updateTweaksStyle() ; prevSessionChecked = true
}
insertBtns() // again or they constantly disappear
// Update button colors on ChatGPT scheme or temp chat toggle
if (/chatgpt|openai/.test(site)) {
let chatbarBGdiv = document.querySelector('textarea')
for (let i = 0 ; i < ( isGPT4oUI ? 3 : 1 ) ; i++) { chatbarBGdiv = chatbarBGdiv.parentNode }
if (chatbarBGdiv) {
const chatbarBGisBlack = chatbarBGdiv.classList.contains('bg-black');
if ((mutation.type === 'attributes' && mutation.attributeName === 'class') // potential scheme toggled
|| (chatbarBGisBlack && !isTempChat) || (!chatbarBGisBlack && isTempChat)) { // temp chat toggled
btnColor = setBtnColor() // init new color
chatbarBGdiv.style.overflow = 'visible' // allow tooltips to overflow pre-GPT4o UI
const buttons = ['fullScreen', 'fullWindow', 'wideScreen', 'newChat']
buttons.forEach(btn => updateBtnSVG(btn)) ; isTempChat = !isTempChat
}}}
})
nodeObserver.observe(document.documentElement, { attributes: true }) // <html> for page scheme toggles
nodeObserver.observe(document.querySelector('main'), { attributes: true, subtree: true }); // <main> for chatbar changes
// Monitor SIDEBAR to update full-window setting
if (/chatgpt|openai/.test(site)) {
const sidebarObserver = new MutationObserver(() => {
const fullWindowState = isFullWindow()
if ((config.fullWindow && !fullWindowState) || (!config.fullWindow && fullWindowState))
if (!config.modeSynced) syncMode('fullWindow')
})
setTimeout(() => // delay half-sec before observing to avoid repeated toggles from nodeObserver
sidebarObserver.observe(document.body, {
subtree: true, childList: false, attributes: true }), 500)
}
// Add RESIZE LISTENER to update full screen setting/button + disable F11 flag
window.onresize = () => {
const fullScreenState = chatgpt.isFullScreen()
if (config.fullScreen && !fullScreenState) { syncMode('fullScreen') ; config.f11 = false } // exiting full screen
else if (!config.fullScreen && fullScreenState) syncMode('fullScreen') // entering full screen
}
// Add KEY LISTENER to enable flag on F11 + stop generating text on ESC
window.onkeydown = event => {
if ((event.key == 'F11' || event.keyCode == 122) && !config.fullScreen) config.f11 = true
else if ((event.key == 'Escape' || event.keyCode == 27) && !chatgpt.isIdle()) chatgpt.stop()
}
})()