Halloween-AtCoder

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

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==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();
    }

})();