Halloween-AtCoder

AtCoderのWAやTLEの表示をハロウィン仕様に変え、かぼちゃマークで装飾する拡張機能

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Halloween-AtCoder
// @namespace    https://github.com/minoru-kinugasa-105/halloween_atcoder_extension
// @version      1.0
// @description  AtCoderのWAやTLEの表示をハロウィン仕様に変え、かぼちゃマークで装飾する拡張機能
// @author       minoru-kinugasa-105
// @match        https://atcoder.jp/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    // ハロウィン仕様のCSSスタイルを追加
    function addHalloweenStyles() {
        const style = document.createElement('style');
        style.textContent = `
            /* WAとTLEのハロウィン装飾 */
            .halloween-wa {
                background: linear-gradient(45deg, #ff6b35, #f7931e) !important;
                color: #fff !important;
                border: 3px solid #ce6317 !important;
                border-radius: 15px !important;
                padding: 6px 10px !important;
                font-weight: bold !important;
                text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important;
                box-shadow: 0 0 20px rgba(255, 107, 53, 0.6) !important;
                animation: halloweenGlow 2s ease-in-out infinite alternate !important;
                position: relative !important;
            }

            .halloween-tle {
                background: linear-gradient(45deg, #8b0000, #ff4500) !important;
                color: #fff !important;
                border: 3px solid #ad0000 !important;
                border-radius: 15px !important;
                padding: 6px 10px !important;
                font-weight: bold !important;
                text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important;
                box-shadow: 0 0 20px rgba(255, 69, 0, 0.6) !important;
                animation: halloweenGlow 2s ease-in-out infinite alternate !important;
                position: relative !important;
            }

            .halloween-mle {
                background: linear-gradient(45deg, #4b0082, #8a2be2) !important;
                color: #fff !important;
                border: 3px solid #2f0047 !important;
                border-radius: 15px !important;
                padding: 6px 10px !important;
                font-weight: bold !important;
                text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important;
                box-shadow: 0 0 20px rgba(138, 43, 226, 0.6) !important;
                animation: halloweenGlow 2s ease-in-out infinite alternate !important;
                position: relative !important;
            }

            .halloween-re {
                background: linear-gradient(45deg, #dc143c, #ff6347) !important;
                color: #fff !important;
                border: 3px solid #8b0000 !important;
                border-radius: 15px !important;
                padding: 6px 10px !important;
                font-weight: bold !important;
                text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important;
                box-shadow: 0 0 20px rgba(220, 20, 60, 0.6) !important;
                animation: halloweenGlow 2s ease-in-out infinite alternate !important;
                position: relative !important;
            }

            .halloween-ce {
                background: linear-gradient(45deg, #2f4f4f, #708090) !important;
                color: #fff !important;
                border: 3px solid #393939 !important;
                border-radius: 15px !important;
                padding: 6px 10px !important;
                font-weight: bold !important;
                text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important;
                box-shadow: 0 0 20px rgba(112, 128, 144, 0.6) !important;
                animation: halloweenGlow 2s ease-in-out infinite alternate !important;
                position: relative !important;
            }

            .halloween-ac {
                background: linear-gradient(45deg, #228b22, #32cd32) !important;
                color: #fff !important;
                border: 3px solid #008b00 !important;
                border-radius: 15px !important;
                padding: 6px 10px !important;
                font-weight: bold !important;
                text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important;
                box-shadow: 0 0 20px rgba(34, 139, 34, 0.6) !important;
                animation: halloweenGlow 2s ease-in-out infinite alternate !important;
                position: relative !important;
            }

            /* かぼちゃマーク */
            .halloween-pumpkin::before {
                content: "🎃" !important;
                font-size: 1.2em !important;
                margin-right: 8px !important;
                animation: pumpkinBounce 1.5s ease-in-out infinite !important;
            }

            /* AC用の成功マーク */
            .halloween-ac::before {
                content: "🍭" !important;
                font-size: 1.2em !important;
                margin-right: 8px !important;
                animation: candyBounce 1.5s ease-in-out infinite !important;
            }

            /* アニメーション効果 */
            @keyframes halloweenGlow {
                0% { box-shadow: 0 0 20px rgba(255, 107, 53, 0.6); }
                100% { box-shadow: 0 0 30px rgba(255, 107, 53, 0.9), 0 0 40px rgba(255, 107, 53, 0.4); }
            }

            @keyframes pumpkinBounce {
                0%, 100% { transform: translateY(0px) rotate(0deg); }
                50% { transform: translateY(-3px) rotate(5deg); }
            }

            @keyframes candyBounce {
                0%, 100% { transform: translateY(0px) rotate(0deg); }
                50% { transform: translateY(-3px) rotate(10deg); }
            }

            /* ホバー効果(ガクガクを防ぐため削除) */

            /* スパイダーウェブ装飾 */
            .halloween-wa::after, .halloween-tle::after, .halloween-mle::after, .halloween-re::after, .halloween-ce::after {
                content: "🕷️" !important;
                position: absolute !important;
                top: -5px !important;
                right: -5px !important;
                font-size: 0.8em !important;
                animation: spiderWeb 3s ease-in-out infinite !important;
            }

            /* AC用の成功装飾 */
            .halloween-ac::after {
                content: "👻" !important;
                position: absolute !important;
                top: -5px !important;
                right: -5px !important;
                font-size: 0.8em !important;
                animation: ghostFloat 2s ease-in-out infinite !important;
            }

            @keyframes ghostFloat {
                0%, 100% { opacity: 0.8; transform: translateY(0px) rotate(0deg); }
                50% { opacity: 1; transform: translateY(-3px) rotate(5deg); }
            }

            @keyframes spiderWeb {
                0%, 100% { opacity: 0.7; transform: rotate(0deg); }
                50% { opacity: 1; transform: rotate(180deg); }
            }

            /* ハロウィン装飾された要素の親tr要素の高さ調整 */
            tr:has(.halloween-wa), tr:has(.halloween-tle), tr:has(.halloween-mle), tr:has(.halloween-re), tr:has(.halloween-ce), tr:has(.halloween-ac) {
                height: 33px !important;
                min-height: 33px !important;
            }

            /* td要素内でハロウィン装飾されたステータスを垂直中央寄せ */
            tr:has(.halloween-wa) td, tr:has(.halloween-tle) td, tr:has(.halloween-mle) td, tr:has(.halloween-re) td, tr:has(.halloween-ce) td, tr:has(.halloween-ac) td {
                vertical-align: middle !important;
                display: table-cell !important;
            }

            /* ハロウィン装飾の小要素のはみ出し防止 */
            .halloween-wa, .halloween-tle, .halloween-mle, .halloween-re, .halloween-ce, .halloween-ac {
                overflow: visible !important;
                position: relative !important;
                vertical-align: middle !important;
                display: inline-block !important;
            }

            /* かぼちゃマークのサイズ調整 */
            .halloween-pumpkin::before {
                font-size: 1.1em !important;
                margin-right: 6px !important;
            }

            /* クモのサイズ調整 */
            .halloween-wa::after, .halloween-tle::after, .halloween-mle::after, .halloween-re::after, .halloween-ce::after {
                font-size: 0.7em !important;
                top: -5px !important;
                right: -5px !important;
            }
        `;
        document.head.appendChild(style);
    }

    // ジャッジ結果の要素のみを検出して装飾を適用
    function applyHalloweenDecoration() {
        // まず、既に装飾済みの要素を除外
        const decoratedElements = document.querySelectorAll('.halloween-wa, .halloween-tle, .halloween-mle, .halloween-re, .halloween-ce, .halloween-ac');
        decoratedElements.forEach(element => {
            element.classList.remove('halloween-wa', 'halloween-tle', 'halloween-mle', 'halloween-re', 'halloween-ce', 'halloween-ac', 'halloween-pumpkin');
        });

        // ジャッジ結果のステータス要素のみを検索
        const statusElements = document.querySelectorAll('span.label.label-warning, span.label.label-success');

        statusElements.forEach(element => {
            const text = element.textContent.trim().toUpperCase();

            // ステータスラベルのみを対象にする
            if (text === 'WA') {
                element.classList.add('halloween-wa', 'halloween-pumpkin');
            } else if (text === 'TLE') {
                element.classList.add('halloween-tle', 'halloween-pumpkin');
            } else if (text === 'MLE') {
                element.classList.add('halloween-mle', 'halloween-pumpkin');
            } else if (text === 'RE') {
                element.classList.add('halloween-re', 'halloween-pumpkin');
            } else if (text === 'CE') {
                element.classList.add('halloween-ce', 'halloween-pumpkin');
            } else if (text === 'AC') {
                element.classList.add('halloween-ac');
            }
        });
    }

    // ページの変更を監視して動的に装飾を適用
    function observePageChanges() {
        const observer = new MutationObserver(function (mutations) {
            let shouldUpdate = false;
            mutations.forEach(function (mutation) {
                if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                    shouldUpdate = true;
                }
            });

            if (shouldUpdate) {
                setTimeout(applyHalloweenDecoration, 100);
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    }

    // 初期化
    function init() {
        addHalloweenStyles();
        applyHalloweenDecoration();
        observePageChanges();

        // ページロード完了後に再実行
        window.addEventListener('load', function () {
            setTimeout(applyHalloweenDecoration, 500);
        });
    }

    // DOMが準備できたら実行
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

})();