ACWing One Theme

make acwing coding UI look more like leetcode

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

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

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 komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

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         ACWing One Theme
// @name:zh-CN  ACWing One Theme
// @namespace    https://whalien.space
// @author       whalien
// @version      0.2
// @description  make acwing coding UI look more like leetcode
// @description:zh-CN 让acwing编程界面看起来更像leetcode
// @icon         https://cdn.acwing.com/static/web/img/favicon.ico
// @match        https://www.acwing.com/problem/content/*
// @run-at document-end
// @grant        GM_addStyle
// @grant        GM_log
// @license      WTFPL
// ==/UserScript==

const customCSS = `
/*---------- global settings ----------*/
.file-explorer-main-field-item.file-explorer-main-field-item-desktop {
  display: none;
}

.base_body {
  padding-top: 72px !important;
}

.base_body > .container {
  width: 98%;
}

.container > .panel.panel-default > .panel-body {
  height: calc(100vh - 72px - 20px);
  padding: 10px 15px;
}

.container > .panel > .panel-body > .row {
  height: 100%;
  margin-top: 8px;
}

.base_body .row .problem-content-container {
  max-height: calc(100% - 100px);
  overflow-y: auto;
}

.container > .panel .panel-body .problem-content-title {
  font-size: 24px;
  margin: 5px 0 10px 0;
}

.base_body .row .code-editor-container {
  height: calc(100% - 110px);
  max-height: 100%;
  overflow-y: auto;
  width: calc(50% - 24px);
}
/*---------- end of global settings ----------*/

/*---------- navigation settings ----------*/
.container > .panel .nav.nav-tabs .problem-content-sub-btn{
  font-size: 1.5rem;
}

.container > .panel .nav.nav-tabs .problem-content-sub-btn .glyphicon {
  top: 2px !important;
}
/*----------- end of navigation settings ----------*/

/*----------- remove br before code editor ----------*/
.container > .panel .panel-body .nav-tabs.nav + br {
  display: none;
}

/*----------- code editor settings toolset ----------*/
.base_body .code-editor-container #code_tool_bar {
  height: 48px;
}

.base_body #code_tool_bar #open_ac_saber_btn{
  top: 9px !important;
}

.base_body #code_tool_bar .btn {
  padding-top: 0;
}

.base_body #code_tool_bar .btn .editor_tool_btn {
  padding-right: 10px;
}

.base_body #code_tool_bar .code_editor_option_language {
  margin-top: 3px !important;
}
/*----------- end of code editor settings toolset ----------*/

/*----------- submit controls ----------*/
#code_editor + div {
  position: fixed;
  bottom: 2px;
  right: 200px;
  z-index: 10000000;
}

/*
#code_editor + div .btn {
  padding: 4px 8px;
}
*/

#data-augmentation-div {
  padding-top: 27px !important;
  padding-right: 12px !important;
  color: white !important;
}
/*----------- end of submit controls ----------*/

/*----------- evaluation block ----------*/
#submit-code-status-block {
  margin-top: 25px !important;
}

#run-code-status-block {
  margin-top: 25px !important;
}
/*----------- end of evaluation block ----------*/

/*----------- dragable wedge ----------*/
.base_body .dragable-wedge {
  float: left;
/*  display: inline-block; */
  width: 10px;
  height: calc(100% - 94px);
}

.base_body .dragable-wedge:hover {
  background-color: rgb(0, 122, 255);
  cursor: col-resize;
}
/*----------- end of dragable wedge ----------*/
`

const throttle = (fn, delay) => {
    let timer = null
    return (...args) => {
        if(timer) return
        timer = setTimeout(() => {
            clearTimeout(timer)
            timer = null
        }, delay)
        fn(...args)
    }
}

function adjustLayout() {
    const problemContainer = document.querySelector('.panel-body .row')

    // make probleDiv take half the width
    const problemDiv = document.querySelector('.panel-body .row .col-sm-9.col-xs-12')
    problemDiv.className = 'problem-content-container col-sm-6 col-xs-12'
    // make infoDiv take the same width as problemDiv
    const infoDiv = document.querySelector('.panel-body .row .col-sm-3.hidden-xs')
    infoDiv.className=''
    problemDiv.appendChild(infoDiv)

    // move code editor to the same row as problem content
    const fragment = document.createDocumentFragment()
    const codeEditorDiv = document.createElement('div')
    codeEditorDiv.className = 'code-editor-container col-sm-5'
    const codeEditorFrag = document.querySelectorAll('.panel-body > .row ~ div')
    codeEditorFrag.forEach((editorFrag) => {
        codeEditorDiv.appendChild(editorFrag)
    })
    fragment.appendChild(codeEditorDiv)
    problemContainer.appendChild(fragment)

    // add dragable resizer
    const dragableDiv = document.createElement('div')
    dragableDiv.className = 'dragable-wedge'
    problemContainer.insertBefore(dragableDiv, codeEditorDiv)

    // get the last container width and set
    const lastProblemWidth = localStorage.getItem('problemWidth')
    const lastCodeEditorWidth = localStorage.getItem('codeEditorWidth')
    if(lastProblemWidth!==null && lastCodeEditorWidth!==null) {
        problemDiv.style.width = lastProblemWidth
        codeEditorDiv.style.width = lastCodeEditorWidth
    }
}

let lastX = -1
function enableDragAndDrop() {
    const problemContent = document.querySelector('.base_body .problem-content-container')
    const codeEditor = document.querySelector('.base_body .code-editor-container')
    const resizer = document.querySelector('.base_body .dragable-wedge')
    const dragEventHandler = (e) => {
        const dx = lastX == -1 ? 0:e.clientX - lastX
        lastX = e.clientX
        if(dx > 100 || dx == 0) return

        let problemContentWidth = problemContent.getBoundingClientRect().width + dx
        let codeEditorWidth = codeEditor.getBoundingClientRect().width - dx
        if(problemContentWidth < 0 || codeEditorWidth < 0) {
            return
        }

        problemContentWidth = `${problemContentWidth}px`
        codeEditorWidth = `${codeEditorWidth}px`
        problemContent.style.width = problemContentWidth
        codeEditor.style.width = codeEditorWidth
        localStorage.setItem('problemWidth', problemContentWidth)
        localStorage.setItem('codeEditorWidth', codeEditorWidth)
    }
    resizer.addEventListener('drag', throttle(dragEventHandler, 60))
}

function bindSubmitScrollBehavior() {
    const codeEditorContainer = document.querySelector('.base_body .code-editor-container')
    const submitBtn = document.querySelector('#submit_code_btn')
    const runCodeBtn = document.querySelector('#run_code_btn')
    // FIXME(whalien): figure out why we cannot delegate click event to the outer div
    submitBtn.addEventListener('click', (e) => {
        setTimeout(()=> {
            codeEditorContainer.scrollTo({
                left: 0,
                top: codeEditorContainer.scrollHeight,
                behavior: 'smooth'
            })
        }, 1000)
    })
    runCodeBtn.addEventListener('click', (e) => {
        setTimeout(()=> {
            codeEditorContainer.scrollTo({
                left: 0,
                top: codeEditorContainer.scrollHeight,
                behavior: 'smooth'
            })
        }, 1000)
    });
}

(function() {
    'use strict';
    adjustLayout()

    GM_addStyle(customCSS)

    enableDragAndDrop()

    bindSubmitScrollBehavior()
})();