Codeforces Modern Design

A modern UI redesign for Codeforces platform

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Codeforces Modern Design
// @name:en      Codeforces Modern Design
// @namespace    https://github.com/funcdfs
// @version      1.2
// @description  A modern UI redesign for Codeforces platform
// @description:en  A modern UI redesign for Codeforces platform
// @description:zh-CN  Codeforces 平台的现代化界面重设计
// @author       funcdfs
// @match        https://atcoder.jp/contests/*
// @match        https://codeforces.com/*/problem/*
// @match        https://codeforces.com/contest/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=codeforces.com
// @grant        none
// @license MIT
// ==/UserScript==

(function () {
    'use strict';
    const codeforces_css = () => {
        const styleTag = document.createElement('style');
        const cssRules = `
pre {
    font-family:  source code pro;
}
div.ttypography tbody td {
    text-align: left;
    border-top: 0px solid #ccc;
}
body {
    background-color: #e7e9ed0f;
}
.roundbox-lt,
.roundbox-rt,
.roundbox-lb,
.roundbox-rb {
    display: none;
}
.roundbox {
    padding-bottom: 10px;
    border-radius: 10px;
}
.sidebox.roundbox {
    margin-top: 10px;
}
.menu-box {
    margin-top: 0px !important;
    -webkit-transition: none !important;
    -moz-transition: none !important;
    -ms-transition: none !important;
    -o-transition: none !important;
    transition: none !important;
}
.menu-box:hover {
    -webkit-box-shadow: none !important;
    -moz-box-shadow: none !important;
    box-shadow: none !important;
}
/** Custom sidebar */
.roundbox {
    margin-top: 10px;
    border: none;
    -webkit-transition: all 0.3s linear 0s;
    -moz-transition: all 0.3s linear 0s;
    -ms-transition: all 0.3s linear 0s;
    -o-transition: all 0.3s linear 0s;
    transition: all 0.3s linear 0s;
}
.roundbox:hover {
    -webkit-box-shadow: 0 1px 15px 0 rgba(0, 0, 0, 0.1);
    -moz-box-shadow: 0 1px 15px 0 rgba(0, 0, 0, 0.1);
    box-shadow: 0 1px 15px 0 rgba(0, 0, 0, 0.1);
}
.roundbox .titled {
    padding: 10px;
    border-bottom-color: #e4e6eb;
}
.sidebox div {
    border-bottom-color: #e4e6eb !important;
}

/** Sidebar avatar custom */
.personal-sidebar .for-avatar {
    float: none !important;
    display: block;
    font-size: 18px;
    padding: 10px;
}

.personal-sidebar .for-avatar .avatar img {
    border-radius: 50px;
    width: 90px;
    height: 90px;
    object-fit: cover;
}

/** Sidebar remove property links*/
.personal-sidebar .propertyLinks {
    display: none;
}

.personal-sidebar .nav-links {
    border-top-style: solid;
    border-top-width: 1px;
    border-top-color: #e4e6eb;
    padding-top: 10px;
}

.personal-sidebar .nav-links li {
    list-style-type: none !important;
    padding: 10px;
    font-size: 13px;
    border-radius: 5px;
    -webkit-transition: all 0.2s linear 0s;
    -moz-transition: all 0.2s linear 0s;
    -ms-transition: all 0.2s linear 0s;
    -o-transition: all 0.2s linear 0s;
    transition: all 0.2s linear 0s;
}

.personal-sidebar .nav-links li a,
.personal-sidebar .nav-links li a:visited {
    color: #050505;
}

.personal-sidebar .nav-links li:after {
    content: '→';
    float: right;
    color: #050505;
}

.personal-sidebar .nav-links li:hover {
    background-color: rgba(0, 0, 0, 0.05);
}

.personal-sidebar .nav-links li a {
    text-decoration: none !important;
}

.roundbox .bottom-links {
    padding: 10px;
    background-color: #fff;
    border-top-color: #e4e6eb !important;
    border-bottom-left-radius: 10px !important;
    border-bottom-right-radius: 10px !important;
}

.roundbox .rtable .dark {
    background-color: #fff;
}
/** Topic custom */
.topic {
    margin-top: 10px;
    padding: 20px;
    background-color: #fff;
    border-radius: 10px;
    -webkit-transition: all 0.3s linear 0s;
    -moz-transition: all 0.3s linear 0s;
    -ms-transition: all 0.3s linear 0s;
    -o-transition: all 0.3s linear 0s;
    transition: all 0.3s linear 0s;
}

.topic:hover {
    -webkit-box-shadow: 0px 1px 15px 0px rgba(0, 0, 0, 0.1);
    -moz-box-shadow: 0px 1px 15px 0px rgba(0, 0, 0, 0.1);
    box-shadow: 0px 1px 15px 0px rgba(0, 0, 0, 0.1);
}

.topic .roundbox {
    border-style: solid;
    border-color: #e4e6eb;
}

.topic .meta a {
    text-decoration: none;
}

.meta {
    padding-bottom: 0px !important;
}

.topic .content {
    border-left-color: #e4e6eb;
}
.roundbox .rtable td,
.roundbox .rtable th {
    border-bottom: 1px solid #e4e6eb;
    border-left: none;
    padding: 7px;
}

/** Header custom */
#header {
    padding: 20px;
    margin-top: -14px;
    background-color: #fff;
}

.menu-box {
    padding: 10px;
    border-radius: 0;
    border-top: none;
    border-left: none;
    border-right: none;
    border-bottom-left-radius: 20px;
    border-bottom-right-radius: 20px;
    border-bottom-color: #e4e6eb;
}

/** Footer custom */
#footer {
    background-color: #fff;
    width: 100%;
    height: 100%;
    border-top-left-radius: 20px;
    border-top-right-radius: 20px;
    border-top-color: #e4e6eb;
}

/** Contest data table */
.datatable .lt,
.datatable .rt,
.datatable .lb,
.datatable .rb,
.datatable .ilt,
.datatable .irt {
    display: none;
}

.datatable table {
    margin-top: 10px;
    border-style: solid;
    border-color: #e4e6eb;
    border-width: 1px;
}

.datatable table .dark {
    background-color: #fff;
}

.datatable table td {
    padding-top: 5px;
    padding-bottom: 5px;
    padding-left: 10px;
    padding-right: 10px;
}

.datatable {
    padding: 20px !important;
    width: inherit;
    padding-bottom: 40px !important;
    background-color: #fff !important;
    border-radius: 10px;
    -webkit-transition: all 0.3s linear 0s;
    -moz-transition: all 0.3s linear 0s;
    -ms-transition: all 0.3s linear 0s;
    -o-transition: all 0.3s linear 0s;
    transition: all 0.3s linear 0s;
}

.datatable:hover {
    -webkit-box-shadow: 0px 1px 15px 0px rgba(0, 0, 0, 0.1);
    -moz-box-shadow: 0px 1px 15px 0px rgba(0, 0, 0, 0.1);
    box-shadow: 0px 1px 15px 0px rgba(0, 0, 0, 0.1);
}

.contests-table::first-line {
    font-size: 20px;
    font-weight: bold !important;
}


.datatable {
    margin-top: 10px !important;
}

/** Custom input */
input[type="file"] {
    padding: 2px 2px!important;
    border: none !important;
}

input,
button {
    outline: none;
    height: auto !important;
    padding: 5px 30px 5px 30px !important;
    border-radius: 10px;
    border-width: 1.5px;
    border-color: #3b5998;
    font-weight: normal;
    -webkit-transition: all 0.3s linear 0s;
    -moz-transition: all 0.3s linear 0s;
    -ms-transition: all 0.3s linear 0s;
    -o-transition: all 0.3s linear 0s;
    transition: all 0.3s linear 0s;
}

input:hover,
button:hover {
    color: rgba(0, 0, 0, 0.7);
    background-color: #e4e6eb;
}

label[for=searchByProblemCheckbox] {
    margin-top: 20px !important;
    color: rgba(0, 0, 0, 0.5);
}

.notice {
    margin-top: 10px !important;
}

.highlighted-row td,
.highlighted-row th {
    background-color: rgba(221, 238, 255, 0.47) !important;
}

input[name=sourceFile] {
    border-style: dashed;
    border-width: 2px;
    border-color: #e4e6eb;
    border-radius: 10px;
    padding: 5px;
    width: 100%;
}

.submit-form {
    margin-top: 20px;
    background-color: #fff;
    padding: 20px 0 20px 0;
    border-radius: 10px;
    -webkit-transition: all 0.3s linear 0s;
    -moz-transition: all 0.3s linear 0s;
    -ms-transition: all 0.3s linear 0s;
    -o-transition: all 0.3s linear 0s;
    transition: all 0.3s linear 0s;
}

.submit-form:hover {
    -webkit-box-shadow: 0px 1px 15px 0px rgba(0, 0, 0, 0.1);
    -moz-box-shadow: 0px 1px 15px 0px rgba(0, 0, 0, 0.1);
    box-shadow: 0px 1px 15px 0px rgba(0, 0, 0, 0.1);
}

.source-popup pre {
    padding: 10px;
    border-style: solid;
    border-width: 2px;
    border-color: #e4e6eb;
}

hr {
    border: 0;
    height: 2px;
    background-image: linear-gradient(to right, rgba(228, 230, 235, 0.1), rgba(228, 230, 235, 1), rgba(228, 230, 235, 0.1));
}

.popup-input-div div,
.popup-output-div div,
.popup-answer-div div,
.popup-checker-div div {
    margin-top: 10px;
    margin-bottom: 5px;
}

.table-form {
    padding: 10px;
}
.diff-notifier {
    display: none !important;
}
/*main*/
.problemindexholder {
    box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;
    margin-top: 10px;
    background-color: #fff;
    padding: 30px;
    border-radius: 10px;
    -webkit-transition: all 0.3s linear 0s;
    -moz-transition: all 0.3s linear 0s;
    -ms-transition: all 0.3s linear 0s;
    -o-transition: all 0.3s linear 0s;
    transition: all 0.3s linear 0s;
}

.sample-test {
    margin-top: 10px;
}

.sample-test .input .title,
.sample-test .output .title {
    font-size: 15px;
}

.sample-test pre {
    padding-top: 10px !important;
    padding-bottom: 10px !important;
    padding-left: 5px !important;
    padding-right: 5px !important;
}

.placeholder {
    margin-bottom: 10px !important;
}

a[href^="/passwordRecovery"] {
    display: block;
    margin-top: 20px !important;
}

.backLava {
    border-radius: 10px;
}

#body {
    max-width: 1220px;
    min-width: 980px;
}

::selection {
    background-color: #c4b5fd!important;
    color: #000!important;
}

::-webkit-scrollbar-thumb {
    background: #323536!important;
}
::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}
div.ttypography a:hover {
    color: #9e88f5 !important;
    background: #cfecdc;
}
div.ttypography li,
div.ttypography p {
    font-size: 1.1em;
    line-height: 1.4em;
}
/** Footer custom */
#footer {
    /** background-color: #fff;
    width: 100%;
    height: 100%;
    border-top-left-radius: 20px;
    border-top-right-radius: 20px;
    border-top-color: #e4e6eb;
    **/
    display: none !important;
}
pre {
    tab-size: 4;
}
.sidebar-menu ul {
    font-size: 1.4rem;
}
body {
    zoom: 111% !important;
}
/** move pos, if you want the pos, just delete below string **/
#header {
    position: absolute !important;
    top: 20px;
    z-index: 1;
    right: 20px;
    /* 将元素右对齐 */
    width: 220px;
    background: #00000000;
}
.menu-box {
    background: #00000000;
    width: 70%;
}
.property-title,
#header > div:nth-child(1) {
    display: none !important;
}
/** info remove to bottom */
.time-limit {
    position: fixed !important;
    right: 30px;
    bottom: 70px;
    z-index: 9;
}
.memory-limit {
    position: fixed !important;
    right: 30px;
    bottom: 50px;
    z-index: 9;

}
.input-file {
    position: fixed !important;
    right: 30px;
    bottom: 30px;
    z-index: 9;
}
.output-file {
    position: fixed !important;
    right: 30px;
    bottom: 10px;
    z-index: 9;
}
`;
        styleTag.appendChild(document.createTextNode(cssRules));
        document.head.appendChild(styleTag);
    };
    const codeforces_luogu = () => {
        function getProblemId(str) {
            let pos = str.indexOf("contest/") + "contest/".length;
            let contestNum = "";
            while (str[pos] >= '0' && str[pos] <= '9') {
                contestNum += str[pos];
                pos++;
            }
            return contestNum;
        }
        function getProblemChar(str) {
            let pos = str.indexOf("problem/") + "problem/".length;
            let problemLetter = str.substr(pos);
            return problemLetter;
        }
        // jump to luogu.com 跳转到洛谷 delete luogu
        let str = window.location.href
        let problemId = getProblemId(str);
        let problemChar = getProblemChar(str);
        let luogulink = document.createElement('li');
        luogulink.setAttribute('style', 'color: green !important;');
        luogulink.innerHTML = `<a href="https://www.luogu.com.cn/problem/CF${problemId}${problemChar}" target="_blank"> 洛谷 </a>`;
        luogulink.classList.add('luogulink')
        document.querySelector("#sidebar > div.roundbox.sidebox.sidebar-menu.borderTopRound > ul").appendChild(luogulink)
    };
    const codeforces_friend_status = () => {
        // friends-status-button 好友提交历史记录
        let uuuuuuuuurl = window.location;
        let cccontestId = uuuuuuuuurl.toString().split("/").filter((x) => {
            if (typeof x !== 'string') { return; }
            const num = Number(x);
            if (Number.isInteger(num)) { return num; }
        })[0];
        let s = uuuuuuuuurl.toString().split("/");
        let iiid = s[s.length - 1];
        let friendBtn = document.createElement('li');
        friendBtn.innerHTML = `<a href="https://codeforces.com/contest/${cccontestId}/status/${iiid}?friends=on" target="_blank">Friends Status</a>`;
        friendBtn.classList.add('friendBtn')
        document.querySelector(".second-level-menu-list").appendChild(friendBtn);
    };
    const codeforces_timeLimits = () => {
        // time limits part 时间限制等 放到一个位置
        /* const timeLimits = document.querySelector(".time-limit");
        const memoryLimits = document.querySelector(".memory-limit");
        const inputLimits = document.querySelector(".input-file");
        const outputLimits = document.querySelector(".output-file");
        let informationSpace = document.querySelector();
        informationSpace.parentNode.insertBefore(informationSpace, info); */
        //informationSpace.appendChild(timeLimits);
        //informationSpace.appendChild(memoryLimits);
        //informationSpace.appendChild(inputLimits);
        //informationSpace.appendChild(outputLimits);
    };
    const KEY_PREFIX = 'funcdfs';
    const atcoder_navigation = () => {
        const contest = location.href.match(/^https:\/\/atcoder\.jp\/contests\/([^\/?]+)/)[1];
        const key = KEY_PREFIX + 'atcoder-' + contest;
        if (location.href.match(/^https:\/\/atcoder\.jp\/contests\/([^\/]+)\/tasks\/?$/)) {
            const problems = [];
            const rows = document.querySelectorAll('tbody>tr');
            for (let i = 0; i < rows.length; i++) {
                const links = rows[i].querySelectorAll('a');
                const href = links[0].getAttribute('href');
                const text = links[0].textContent + ' - ' + links[1].textContent;
                problems.push({
                    href: href,
                    text: text
                });
            }
            localStorage[key] = JSON.stringify(problems);
        }
        if (key in localStorage) {
            let problems = JSON.parse(localStorage[key]);
            const problemsBar = document.createElement('ul');
            problemsBar.className = 'nav nav-tabs';
            for (let i = 0; i < problems.length; i++) {
                const link = document.createElement('a');
                link.setAttribute('style', 'margin-left: 10px; margin-right: 10px; white-space: nowrap');
                link.setAttribute('href', problems[i].href);
                link.textContent = problems[i].text;
                const span = document.createElement('span');
                span.textContent = ' ';
                span.appendChild(link);
                problemsBar.appendChild(span);
            }
            document.getElementById('contest-nav-tabs').appendChild(problemsBar);
        }
    };
    const codeforces_navigation = () => {
        const contest = location.href.match(/^https:\/\/codeforces\.com\/contest\/([^\/?]+)/)[1];
        const key = KEY_PREFIX + 'codeforces-' + contest;
        if (location.href.match(/^https:\/\/codeforces\.com\/contest\/([^\/]+)\/?$/)) {
            const problems = [];
            const rows = document.querySelectorAll('.problems>tbody>tr');
            for (let i = 1; i < rows.length; i++) {
                const links = rows[i].querySelectorAll('a');
                const href = links[0].getAttribute('href');
                const text = links[0].textContent.trim() + '. ' + links[1].textContent;
                problems.push({
                    href: href,
                    text: text
                });
            }
            localStorage[key] = JSON.stringify(problems);
        }

        if (key in localStorage) {
            let problems = JSON.parse(localStorage[key]);
            const problemsBar = document.createElement('ul');
            problemsBar.setAttribute('style', 'margin-left: 15px; margin-right: 280px; padding-top: 30px');
            for (let i = 0; i < problems.length; i++) {
                const link = document.createElement('a');
                link.setAttribute('style', 'margin-right: 20px; white-space: nowrap');
                link.setAttribute('href', problems[i].href);
                link.textContent = problems[i].text;
                const span = document.createElement('span');
                span.textContent = ' ';
                span.appendChild(link);
                problemsBar.appendChild(span);
            }

            const content = document.getElementById('pageContent');
            content.parentNode.insertBefore(problemsBar, content);
        }
    };
    if (location.href.match(/^https:\/\/atcoder\.jp\/contests\//)) {
        atcoder_navigation();
    } else {
        if (location.href.match(/^https:\/\/codeforces\.com\/contest\//)) {
            codeforces_navigation();
        }
        codeforces_css();
        codeforces_luogu();
        codeforces_friend_status();
        codeforces_timeLimits();
    }
})();