Theme-AtCoder

AtCoderのWAやTLEの表示をテーマ別に装飾する拡張機能(ハロウィン、春など)

2026/03/28のページです。最新版はこちら

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Theme-AtCoder
// @namespace    https://github.com/mimimi105/theme_atcoder_extension
// @version      2.0.1
// @description  AtCoderのWAやTLEの表示をテーマ別に装飾する拡張機能(ハロウィン、春など)
// @author       mimimi105
// @match        https://atcoder.jp/*
// @grant        none
// @license      MIT
// ==/UserScript==

!function(){"use strict";const halloweenTheme={name:"halloween",displayName:"ハロウィン",period:{start:{month:10,day:1},end:{month:11,day:7}},styles:"\n        /* WAとTLEのハロウィン装飾 */\n        .theme-wa {\n            background: linear-gradient(45deg, #ff6b35, #f7931e) !important;\n            color: #fff !important;\n            border: 3px solid #ce6317 !important;\n            border-radius: 15px !important;\n            padding: 6px 10px !important;\n            font-weight: bold !important;\n            font-family: 'Noto Sans', 'Noto Color Emoji', sans-serif !important;\n            text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important;\n            box-shadow: 0 0 20px rgba(255, 107, 53, 0.6) !important;\n            animation: halloweenGlow 2s ease-in-out infinite alternate !important;\n            position: relative !important;\n        }\n\n        .theme-tle {\n            background: linear-gradient(45deg, #8b0000, #ff4500) !important;\n            color: #fff !important;\n            border: 3px solid #ad0000 !important;\n            border-radius: 15px !important;\n            padding: 6px 10px !important;\n            font-weight: bold !important;\n            font-family: 'Noto Sans', 'Noto Color Emoji', sans-serif !important;\n            text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important;\n            box-shadow: 0 0 20px rgba(255, 69, 0, 0.6) !important;\n            animation: halloweenGlow 2s ease-in-out infinite alternate !important;\n            position: relative !important;\n        }\n\n        .theme-mle {\n            background: linear-gradient(45deg, #4b0082, #8a2be2) !important;\n            color: #fff !important;\n            border: 3px solid #2f0047 !important;\n            border-radius: 15px !important;\n            padding: 6px 10px !important;\n            font-weight: bold !important;\n            font-family: 'Noto Sans', 'Noto Color Emoji', sans-serif !important;\n            text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important;\n            box-shadow: 0 0 20px rgba(138, 43, 226, 0.6) !important;\n            animation: halloweenGlow 2s ease-in-out infinite alternate !important;\n            position: relative !important;\n        }\n\n        .theme-re {\n            background: linear-gradient(45deg, #dc143c, #ff6347) !important;\n            color: #fff !important;\n            border: 3px solid #8b0000 !important;\n            border-radius: 15px !important;\n            padding: 6px 10px !important;\n            font-weight: bold !important;\n            font-family: 'Noto Sans', 'Noto Color Emoji', sans-serif !important;\n            text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important;\n            box-shadow: 0 0 20px rgba(220, 20, 60, 0.6) !important;\n            animation: halloweenGlow 2s ease-in-out infinite alternate !important;\n            position: relative !important;\n        }\n\n        .theme-ce {\n            background: linear-gradient(45deg, #2f4f4f, #708090) !important;\n            color: #fff !important;\n            border: 3px solid #393939 !important;\n            border-radius: 15px !important;\n            padding: 6px 10px !important;\n            font-weight: bold !important;\n            font-family: 'Noto Sans', 'Noto Color Emoji', sans-serif !important;\n            text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important;\n            box-shadow: 0 0 20px rgba(112, 128, 144, 0.6) !important;\n            animation: halloweenGlow 2s ease-in-out infinite alternate !important;\n            position: relative !important;\n        }\n\n        .theme-ac {\n            background: linear-gradient(45deg, #228b22, #32cd32) !important;\n            color: #fff !important;\n            border: 3px solid #008b00 !important;\n            border-radius: 15px !important;\n            padding: 6px 10px !important;\n            font-weight: bold !important;\n            font-family: 'Noto Sans', 'Noto Color Emoji', sans-serif !important;\n            text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important;\n            box-shadow: 0 0 20px rgba(34, 139, 34, 0.6) !important;\n            animation: halloweenGlow 2s ease-in-out infinite alternate !important;\n            position: relative !important;\n        }\n\n        /* かぼちゃマーク */\n        .theme-pumpkin::before {\n            content: \"🎃\" !important;\n            font-size: 1.2em !important;\n            margin-right: 8px !important;\n            animation: pumpkinBounce 1.5s ease-in-out infinite !important;\n        }\n\n        /* AC用の成功マーク */\n        .theme-ac::before {\n            content: \"🍭\" !important;\n            font-size: 1.2em !important;\n            margin-right: 8px !important;\n            animation: candyBounce 1.5s ease-in-out infinite !important;\n        }\n\n        /* アニメーション効果 */\n        @keyframes halloweenGlow {\n            0% { box-shadow: 0 0 20px rgba(255, 107, 53, 0.6); }\n            100% { box-shadow: 0 0 30px rgba(255, 107, 53, 0.9), 0 0 40px rgba(255, 107, 53, 0.4); }\n        }\n\n        @keyframes pumpkinBounce {\n            0%, 100% { transform: translateY(0px) rotate(0deg); }\n            50% { transform: translateY(-3px) rotate(5deg); }\n        }\n\n        @keyframes candyBounce {\n            0%, 100% { transform: translateY(0px) rotate(0deg); }\n            50% { transform: translateY(-3px) rotate(10deg); }\n        }\n\n        /* スパイダーウェブ装飾 */\n        .theme-wa::after, .theme-tle::after, .theme-mle::after, .theme-re::after, .theme-ce::after {\n            content: \"🕷️\" !important;\n            position: absolute !important;\n            top: -5px !important;\n            right: -5px !important;\n            font-size: 0.8em !important;\n            animation: spiderWeb 3s ease-in-out infinite !important;\n        }\n\n        /* AC用の成功装飾 */\n        .theme-ac::after {\n            content: \"👻\" !important;\n            position: absolute !important;\n            top: -5px !important;\n            right: -5px !important;\n            font-size: 0.8em !important;\n            animation: ghostFloat 2s ease-in-out infinite !important;\n        }\n\n        @keyframes ghostFloat {\n            0%, 100% { opacity: 0.8; transform: translateY(0px) rotate(0deg); }\n            50% { opacity: 1; transform: translateY(-3px) rotate(5deg); }\n        }\n\n        @keyframes spiderWeb {\n            0%, 100% { opacity: 0.7; transform: rotate(0deg); }\n            50% { opacity: 1; transform: rotate(180deg); }\n        }\n\n        /* ハロウィン装飾された要素の親tr要素の高さ調整 */\n        tr:has(.theme-wa), tr:has(.theme-tle), tr:has(.theme-mle), tr:has(.theme-re), tr:has(.theme-ce), tr:has(.theme-ac) {\n            height: 33px !important;\n            min-height: 33px !important;\n        }\n\n        /* td要素内でハロウィン装飾されたステータスを垂直中央寄せ */\n        tr:has(.theme-wa) td, tr:has(.theme-tle) td, tr:has(.theme-mle) td, tr:has(.theme-re) td, tr:has(.theme-ce) td, tr:has(.theme-ac) td {\n            vertical-align: middle !important;\n            display: table-cell !important;\n        }\n\n        /* ハロウィン装飾の小要素のはみ出し防止 */\n        .theme-wa, .theme-tle, .theme-mle, .theme-re, .theme-ce, .theme-ac {\n            overflow: visible !important;\n            position: relative !important;\n            vertical-align: middle !important;\n            display: inline-block !important;\n        }\n\n        /* かぼちゃマークのサイズ調整 */\n        .theme-pumpkin::before {\n            font-size: 1.1em !important;\n            margin-right: 6px !important;\n        }\n\n        /* クモのサイズ調整 */\n        .theme-wa::after, .theme-tle::after, .theme-mle::after, .theme-re::after, .theme-ce::after {\n            font-size: 0.7em !important;\n            top: -5px !important;\n            right: -5px !important;\n        }\n    ",statusClasses:{WA:["theme-wa","theme-pumpkin"],TLE:["theme-tle","theme-pumpkin"],MLE:["theme-mle","theme-pumpkin"],RE:["theme-re","theme-pumpkin"],CE:["theme-ce","theme-pumpkin"],AC:["theme-ac"]}},springTheme={name:"spring",displayName:"春(桜)",period:{start:{month:3,day:20},end:{month:4,day:30}},styles:"\n        /* 春/桜テーマのスタイル */\n        .theme-wa {\n            background: linear-gradient(180deg, #ffeb99 0%, #ffb347 50%, #ff9933 100%) !important;\n            color: #fff !important;\n            border: 3px solid rgba(255, 250, 230, 0.8) !important;\n            border-radius: 20px !important;\n            padding: 6px 10px !important;\n            font-weight: bold !important;\n            font-family: 'Noto Sans', 'Noto Color Emoji', sans-serif !important;\n            text-shadow: 0 0 3px rgba(150, 110, 60, 0.25), 0 0 6px rgba(150, 110, 60, 0.15), 2px 2px 4px rgba(255, 153, 51, 0.3) !important;\n            box-shadow: 0 0 15px rgba(255, 179, 71, 0.25), 0 0 8px rgba(255, 255, 255, 0.5) inset, 0 1px 4px rgba(255, 250, 230, 0.3) !important;\n            animation: orangeGlow 3s ease-in-out infinite alternate !important;\n            position: relative !important;\n        }\n\n        .theme-tle {\n            background: linear-gradient(180deg, #fff5f5 0%, #ffd5cd 40%, #ffb3ba 100%) !important;\n            color: #fff !important;\n            border: 3px solid rgba(255, 240, 240, 0.8) !important;\n            border-radius: 20px !important;\n            padding: 6px 10px !important;\n            font-weight: bold !important;\n            font-family: 'Noto Sans', 'Noto Color Emoji', sans-serif !important;\n            text-shadow: 0 0 3px rgba(150, 100, 100, 0.25), 0 0 6px rgba(150, 100, 100, 0.15), 2px 2px 4px rgba(255, 179, 186, 0.3) !important;\n            box-shadow: 0 0 15px rgba(255, 179, 186, 0.25), 0 0 8px rgba(255, 255, 255, 0.5) inset, 0 1px 4px rgba(255, 240, 240, 0.3) !important;\n            animation: peachGlow 3s ease-in-out infinite alternate !important;\n            position: relative !important;\n        }\n\n        .theme-mle {\n            background: linear-gradient(180deg, #f5e6ff 0%, #e0ccff 40%, #d9b3ff 100%) !important;\n            color: #fff !important;\n            border: 3px solid rgba(245, 240, 255, 0.8) !important;\n            border-radius: 20px !important;\n            padding: 6px 10px !important;\n            font-weight: bold !important;\n            font-family: 'Noto Sans', 'Noto Color Emoji', sans-serif !important;\n            text-shadow: 0 0 3px rgba(90, 80, 120, 0.3), 0 0 6px rgba(90, 80, 120, 0.2), 2px 2px 4px rgba(217, 179, 255, 0.3) !important;\n            box-shadow: 0 0 15px rgba(217, 179, 255, 0.25), 0 0 8px rgba(255, 255, 255, 0.5) inset, 0 1px 4px rgba(245, 240, 255, 0.3) !important;\n            animation: lavenderGlow 3s ease-in-out infinite alternate !important;\n            position: relative !important;\n        }\n\n        .theme-re {\n            background: linear-gradient(135deg, #ffb3ba, #ff8fa3) !important;\n            color: #fff !important;\n            border: 3px solid rgba(255, 240, 245, 0.8) !important;\n            border-radius: 20px !important;\n            padding: 6px 10px !important;\n            font-weight: bold !important;\n            font-family: 'Noto Sans', 'Noto Color Emoji', sans-serif !important;\n            text-shadow: 0 0 3px rgba(140, 90, 100, 0.3), 0 0 6px rgba(140, 90, 100, 0.2), 2px 2px 4px rgba(255, 143, 163, 0.3) !important;\n            box-shadow: 0 0 15px rgba(255, 143, 163, 0.25), 0 0 8px rgba(255, 255, 255, 0.5) inset, 0 1px 4px rgba(255, 240, 245, 0.3) !important;\n            animation: roseGlow 3s ease-in-out infinite alternate !important;\n            position: relative !important;\n        }\n\n        .theme-ce {\n            background: linear-gradient(180deg, #f5ede3 0%, #d4c4b0 50%, #c9b79c 100%) !important;\n            color: #fff !important;\n            border: 3px solid rgba(245, 240, 230, 0.8) !important;\n            border-radius: 20px !important;\n            padding: 6px 10px !important;\n            font-weight: bold !important;\n            font-family: 'Noto Sans', 'Noto Color Emoji', sans-serif !important;\n            text-shadow: 0 0 3px rgba(100, 85, 70, 0.25), 0 0 6px rgba(100, 85, 70, 0.15), 2px 2px 4px rgba(139, 115, 85, 0.3) !important;\n            box-shadow: 0 0 15px rgba(201, 183, 156, 0.25), 0 0 8px rgba(255, 255, 255, 0.5) inset, 0 1px 4px rgba(245, 237, 227, 0.3) !important;\n            animation: woodGlow 3s ease-in-out infinite alternate !important;\n            position: relative !important;\n        }\n\n        .theme-ac {\n            background: linear-gradient(180deg, #e8ff4d 0%, #7be495 50%, #3dd9c6 100%) !important;\n            color: #fff !important;\n            border: 3px solid rgba(224, 247, 250, 0.8) !important;\n            border-radius: 20px !important;\n            padding: 6px 10px !important;\n            font-weight: bold !important;\n            font-family: 'Noto Sans', 'Noto Color Emoji', sans-serif !important;\n            text-shadow: 0 0 3px rgba(60, 100, 90, 0.25), 0 0 6px rgba(60, 100, 90, 0.15), 2px 2px 4px rgba(61, 217, 198, 0.3) !important;\n            box-shadow: 0 0 15px rgba(61, 217, 198, 0.25), 0 0 8px rgba(255, 255, 255, 0.5) inset, 0 1px 4px rgba(224, 247, 250, 0.3) !important;\n            animation: springGlow 3s ease-in-out infinite alternate !important;\n            position: relative !important;\n        }\n\n        /* オレンジマーク(WA用) */\n        .theme-orange::before {\n            content: \"🌸\" !important;\n            font-size: 1.2em !important;\n            margin-right: 8px !important;\n            animation: sakuraFloat 2s ease-in-out infinite !important;\n        }\n\n        /* 桜マーク */\n        .theme-sakura::before {\n            content: \"🌸\" !important;\n            font-size: 1.2em !important;\n            margin-right: 8px !important;\n            animation: sakuraFloat 2s ease-in-out infinite !important;\n        }\n\n        /* AC用の成功マーク */\n        .theme-ac::before {\n            content: \"🌸\" !important;\n            font-size: 1.2em !important;\n            margin-right: 8px !important;\n            animation: sakuraFloat 2s ease-in-out infinite !important;\n        }\n\n        /* アニメーション効果 */\n        @keyframes sakuraGlow {\n            0% {\n                box-shadow: 0 0 20px rgba(255, 182, 193, 0.5);\n            }\n            100% {\n                box-shadow: 0 0 30px rgba(255, 192, 203, 0.8), 0 0 40px rgba(255, 182, 193, 0.4);\n            }\n        }\n\n        @keyframes springGlow {\n            0% {\n                box-shadow: 0 0 20px rgba(61, 217, 198, 0.5);\n            }\n            100% {\n                box-shadow: 0 0 30px rgba(61, 217, 198, 0.8), 0 0 40px rgba(123, 228, 149, 0.4);\n            }\n        }\n\n        @keyframes peachGlow {\n            0% {\n                box-shadow: 0 0 15px rgba(255, 179, 186, 0.25), 0 0 8px rgba(255, 255, 255, 0.5) inset, 0 1px 4px rgba(255, 240, 240, 0.3);\n            }\n            100% {\n                box-shadow: 0 0 20px rgba(255, 179, 186, 0.35), 0 0 10px rgba(255, 255, 255, 0.6) inset, 0 1px 6px rgba(255, 213, 205, 0.4);\n            }\n        }\n\n        @keyframes orangeGlow {\n            0% {\n                box-shadow: 0 0 15px rgba(255, 179, 71, 0.25), 0 0 8px rgba(255, 255, 255, 0.5) inset, 0 1px 4px rgba(255, 250, 230, 0.3);\n            }\n            100% {\n                box-shadow: 0 0 20px rgba(255, 179, 71, 0.35), 0 0 10px rgba(255, 255, 255, 0.6) inset, 0 1px 6px rgba(255, 235, 153, 0.4);\n            }\n        }\n\n        @keyframes lavenderGlow {\n            0% {\n                box-shadow: 0 0 15px rgba(217, 179, 255, 0.25), 0 0 8px rgba(255, 255, 255, 0.5) inset, 0 1px 4px rgba(245, 240, 255, 0.3);\n            }\n            100% {\n                box-shadow: 0 0 20px rgba(217, 179, 255, 0.35), 0 0 10px rgba(255, 255, 255, 0.6) inset, 0 1px 6px rgba(224, 204, 255, 0.4);\n            }\n        }\n\n        @keyframes woodGlow {\n            0% {\n                box-shadow: 0 0 15px rgba(201, 183, 156, 0.25), 0 0 8px rgba(255, 255, 255, 0.5) inset, 0 1px 4px rgba(245, 237, 227, 0.3);\n            }\n            100% {\n                box-shadow: 0 0 20px rgba(201, 183, 156, 0.35), 0 0 10px rgba(255, 255, 255, 0.6) inset, 0 1px 6px rgba(212, 196, 176, 0.4);\n            }\n        }\n\n        @keyframes roseGlow {\n            0% {\n                box-shadow: 0 0 15px rgba(255, 143, 163, 0.25), 0 0 8px rgba(255, 255, 255, 0.5) inset, 0 1px 4px rgba(255, 240, 245, 0.3);\n            }\n            100% {\n                box-shadow: 0 0 20px rgba(255, 143, 163, 0.35), 0 0 10px rgba(255, 255, 255, 0.6) inset, 0 1px 6px rgba(255, 179, 186, 0.4);\n            }\n        }\n\n        @keyframes sakuraFloat {\n            0%, 100% {\n                transform: translateY(0px) rotate(-3deg);\n                opacity: 1;\n            }\n            50% {\n                transform: translateY(-5px) rotate(3deg);\n                opacity: 0.8;\n            }\n        }\n\n        @keyframes petalFall {\n            0% {\n                opacity: 1;\n                transform: translateY(0px) rotate(0deg);\n            }\n            100% {\n                opacity: 0.3;\n                transform: translateY(5px) rotate(180deg);\n            }\n        }\n\n        /* WA用オレンジ装飾 */\n        .theme-wa::after {\n            content: \"🍊\" !important;\n            position: absolute !important;\n            top: -5px !important;\n            right: -5px !important;\n            font-size: 0.8em !important;\n            animation: ghostFloat 2s ease-in-out infinite !important;\n        }\n\n        /* TLE、RE用花びら装飾 */\n        .theme-tle::after, .theme-re::after {\n            content: \"🌺\" !important;\n            position: absolute !important;\n            top: -5px !important;\n            right: -5px !important;\n            font-size: 0.8em !important;\n            animation: ghostFloat 2s ease-in-out infinite !important;\n        }\n\n        /* CE用木装飾 */\n        .theme-ce::after {\n            content: \"🪵\" !important;\n            position: absolute !important;\n            top: -5px !important;\n            right: -5px !important;\n            font-size: 0.8em !important;\n            animation: ghostFloat 2s ease-in-out infinite !important;\n        }\n\n        /* MLE用ラベンダー装飾 */\n        .theme-mle::after {\n            content: \"🪻\" !important;\n            position: absolute !important;\n            top: -5px !important;\n            right: -5px !important;\n            font-size: 0.8em !important;\n            animation: ghostFloat 2s ease-in-out infinite !important;\n        }\n\n        /* AC用の成功装飾 */\n        .theme-ac::after {\n            content: \"🦋\" !important;\n            position: absolute !important;\n            top: -5px !important;\n            right: -5px !important;\n            font-size: 0.8em !important;\n            animation: butterflyFloat 3s ease-in-out infinite !important;\n        }\n\n        @keyframes ghostFloat {\n            0%, 100% {\n                opacity: 0.8;\n                transform: translateY(0px) rotate(0deg);\n            }\n            50% {\n                opacity: 1;\n                transform: translateY(-2px) rotate(5deg);\n            }\n        }\n\n        @keyframes butterflyFloat {\n            0%, 100% {\n                opacity: 0.9;\n                transform: translate(0px, 0px) rotate(0deg);\n            }\n            25% {\n                opacity: 1;\n                transform: translate(-3px, -2px) rotate(-10deg);\n            }\n            50% {\n                opacity: 0.9;\n                transform: translate(0px, -4px) rotate(0deg);\n            }\n            75% {\n                opacity: 1;\n                transform: translate(3px, -2px) rotate(10deg);\n            }\n        }\n\n        /* 春装飾された要素の親tr要素の高さ調整 */\n        tr:has(.theme-wa), tr:has(.theme-tle), tr:has(.theme-mle), tr:has(.theme-re), tr:has(.theme-ce), tr:has(.theme-ac) {\n            height: 33px !important;\n            min-height: 33px !important;\n        }\n\n        /* td要素内で春装飾されたステータスを垂直中央寄せ */\n        tr:has(.theme-wa) td, tr:has(.theme-tle) td, tr:has(.theme-mle) td, tr:has(.theme-re) td, tr:has(.theme-ce) td, tr:has(.theme-ac) td {\n            vertical-align: middle !important;\n            display: table-cell !important;\n        }\n\n        /* 春装飾の小要素のはみ出し防止 */\n        .theme-wa, .theme-tle, .theme-mle, .theme-re, .theme-ce, .theme-ac {\n            overflow: visible !important;\n            position: relative !important;\n            vertical-align: middle !important;\n            display: inline-block !important;\n        }\n\n        /* 桜マークのサイズ調整 */\n        .theme-sakura::before {\n            font-size: 1.1em !important;\n            margin-right: 6px !important;\n        }\n\n        /* 花びらのサイズ調整 */\n        .theme-wa::after, .theme-tle::after, .theme-mle::after, .theme-re::after, .theme-ce::after {\n            font-size: 0.7em !important;\n            top: -5px !important;\n            right: -5px !important;\n        }\n    ",statusClasses:{WA:["theme-wa","theme-orange"],TLE:["theme-tle","theme-sakura"],MLE:["theme-mle","theme-sakura"],RE:["theme-re","theme-sakura"],CE:["theme-ce","theme-sakura"],AC:["theme-ac"]}},THEME_OPTIONS_AUTO="auto",THEME_OPTIONS_HALLOWEEN="halloween",THEME_OPTIONS_OFF="off";class Config{constructor(){this.loadConfig()}loadConfig(){try{const saved=localStorage.getItem("atcoder_theme_config");this.config=saved?JSON.parse(saved):{mode:THEME_OPTIONS_AUTO,selectedTheme:THEME_OPTIONS_HALLOWEEN}}catch(e){console.error("Failed to load config:",e),this.config={mode:THEME_OPTIONS_AUTO,selectedTheme:THEME_OPTIONS_HALLOWEEN}}}saveConfig(){try{localStorage.setItem("atcoder_theme_config",JSON.stringify(this.config))}catch(e){console.error("Failed to save config:",e)}}getMode(){return this.config.mode||THEME_OPTIONS_AUTO}setMode(mode){this.config.mode=mode,this.saveConfig()}getSelectedTheme(){return this.config.selectedTheme||THEME_OPTIONS_HALLOWEEN}setSelectedTheme(theme){this.config.selectedTheme=theme,this.saveConfig()}}class ThemeManager{constructor(){this.config=new Config,this.themes={halloween:halloweenTheme,spring:springTheme},this.currentTheme=null}isInPeriod(period){const now=new Date,currentMonth=now.getMonth()+1,currentDay=now.getDate(),start=period.start,end=period.end;return start.month>end.month?currentMonth>start.month||currentMonth===start.month&&currentDay>=start.day||currentMonth<end.month||currentMonth===end.month&&currentDay<=end.day:!(currentMonth<start.month||currentMonth>end.month)&&(!(currentMonth===start.month&&currentDay<start.day)&&!(currentMonth===end.month&&currentDay>end.day))}getAutoTheme(){for(const[key,theme]of Object.entries(this.themes))if(theme.period&&this.isInPeriod(theme.period))return theme;return this.themes.halloween}getCurrentTheme(){const mode=this.config.getMode();if(mode===THEME_OPTIONS_OFF)return null;if(mode===THEME_OPTIONS_AUTO)return this.getAutoTheme();const selectedTheme=this.config.getSelectedTheme();return this.themes[selectedTheme]||this.themes.halloween}applyTheme(){const theme=this.getCurrentTheme();if(theme===this.currentTheme)return;const oldStyle=document.getElementById("atcoder-theme-styles");if(oldStyle&&oldStyle.remove(),this.currentTheme=theme,!document.getElementById("google-fonts-noto")){const link=document.createElement("link");link.id="google-fonts-noto",link.rel="stylesheet",link.href="https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap",document.head.appendChild(link)}if(!theme)return;const style=document.createElement("style");return style.id="atcoder-theme-styles",style.textContent=theme.styles,document.head.appendChild(style),theme}createTestTable(){const existing=document.getElementById("test-status-table");existing&&existing.remove();let targetTable=document.querySelector("table.table");if(!targetTable){const container=document.createElement("div");container.id="test-status-table",container.style.cssText="margin: 20px; padding: 20px; background: #f5f5f5;",targetTable=document.createElement("table"),targetTable.className="table table-bordered table-striped",targetTable.style.cssText="width: 100%; background: white;",container.appendChild(targetTable),document.body.insertBefore(container,document.body.firstChild)}const tbody=targetTable.querySelector("tbody")||targetTable;["WA","TLE","MLE","RE","CE","AC"].forEach((status,index)=>{const tr=document.createElement("tr"),td1=document.createElement("td");td1.textContent="2024-03-23 12:00:00",tr.appendChild(td1);const td2=document.createElement("td");td2.textContent=`テスト問題 ${index+1}`,tr.appendChild(td2);const td3=document.createElement("td");td3.textContent="test_user",tr.appendChild(td3);const td4=document.createElement("td");td4.textContent="C++ (GCC 9.2.1)",tr.appendChild(td4);const td5=document.createElement("td");td5.textContent="AC"===status?"100":"0",tr.appendChild(td5);const td6=document.createElement("td");td6.textContent="1234 Byte",tr.appendChild(td6);const td7=document.createElement("td"),statusSpan=document.createElement("span");statusSpan.className="AC"===status?"label label-success":"label label-warning",statusSpan.textContent=status,td7.appendChild(statusSpan),tr.appendChild(td7);const td8=document.createElement("td");td8.textContent="TLE"===status?"2000 ms":"123 ms",tr.appendChild(td8);const td9=document.createElement("td");td9.textContent="MLE"===status?"2048 KB":"512 KB",tr.appendChild(td9),tbody.appendChild(tr)}),console.log("✅ テストケースを作成しました")}createSettingsPanel(){const existing=document.getElementById("atcoder-theme-settings");existing&&existing.remove();const panel=document.createElement("div");panel.id="atcoder-theme-settings";panel.innerHTML='\n            <style>\n                #atcoder-theme-settings {\n                    position: fixed !important;\n                    top: 10px !important;\n                    right: 10px !important;\n                    background: white !important;\n                    border: 1px solid #ccc !important;\n                    border-radius: 4px !important;\n                    padding: 10px !important;\n                    box-shadow: 0 4px 12px rgba(0,0,0,0.3) !important;\n                    z-index: 10000 !important;\n                    font-family: \'Noto Sans\', \'Noto Color Emoji\', system-ui, -apple-system, sans-serif !important;\n                    min-width: 200px !important;\n                    display: none !important;\n                }\n                #atcoder-theme-settings.visible {\n                    display: block !important;\n                }\n                #atcoder-theme-settings * {\n                    all: revert !important;\n                }\n                #atcoder-theme-settings label {\n                    display: block !important;\n                    margin: 0 0 5px 0 !important;\n                    padding: 0 !important;\n                    font-size: 12px !important;\n                    font-weight: normal !important;\n                    color: #333 !important;\n                    line-height: normal !important;\n                }\n                #atcoder-theme-settings select {\n                    display: block !important;\n                    width: 100% !important;\n                    margin: 0 !important;\n                    padding: 4px 8px !important;\n                    font-size: 14px !important;\n                    line-height: normal !important;\n                    color: #333 !important;\n                    background: white !important;\n                    border: 1px solid #ccc !important;\n                    box-sizing: border-box !important;\n                }\n                #create-test-btn {\n                    display: block !important;\n                    width: 100% !important;\n                    margin-top: 10px !important;\n                    padding: 8px !important;\n                    background: #4CAF50 !important;\n                    color: white !important;\n                    border: none !important;\n                    border-radius: 4px !important;\n                    cursor: pointer !important;\n                    font-size: 12px !important;\n                    font-weight: bold !important;\n                    line-height: normal !important;\n                }\n                #create-test-btn:hover {\n                    background: #45a049 !important;\n                }\n            </style>\n            <label for="theme-selector">テーマ設定:</label>\n            <select id="theme-selector">\n                <option value="auto">自動(期間で切替)</option>\n                <option value="halloween">ハロウィン</option>\n                <option value="spring">春(桜)</option>\n                <option value="off">オフ</option>\n            </select>\n            \n        ',document.body.appendChild(panel);const selector=document.getElementById("theme-selector");selector.value=this.config.getMode(),selector.addEventListener("change",e=>{const mode=e.target.value;this.config.setMode(mode),mode!==THEME_OPTIONS_AUTO&&mode!==THEME_OPTIONS_OFF&&this.config.setSelectedTheme(mode),this.applyTheme(),window.location.reload()}),document.addEventListener("click",e=>{panel.contains(e.target)||this.hideSettingsPanel()})}showSettingsPanel(x,y){console.log("showSettingsPanel呼び出し:",x,y);const panel=document.getElementById("atcoder-theme-settings");if(!panel)return void console.error("設定パネルが見つかりません");let left=x,top=y;left+220>window.innerWidth&&(left=window.innerWidth-220-10),top+100>window.innerHeight&&(top=window.innerHeight-100-10),panel.style.setProperty("left",`${left}px`,"important"),panel.style.setProperty("top",`${top}px`,"important"),panel.style.setProperty("right","auto","important"),panel.classList.add("visible"),console.log("パネル表示:",left,top)}hideSettingsPanel(){const panel=document.getElementById("atcoder-theme-settings");panel&&panel.classList.remove("visible")}}class Decorator{constructor(themeManager){this.themeManager=themeManager}applyDecoration(){const theme=this.themeManager.getCurrentTheme();document.querySelectorAll('[class*="theme-"]').forEach(element=>{Array.from(element.classList).forEach(cls=>{cls.startsWith("theme-")&&element.classList.remove(cls)})});document.querySelectorAll("span.label.label-warning, span.label.label-success").forEach(element=>{const text=element.textContent.trim().toUpperCase();if(theme&&theme.statusClasses&&theme.statusClasses[text]){const classes=theme.statusClasses[text];element.classList.add(...classes)}element.hasAttribute("data-context-menu-added")||(element.addEventListener("contextmenu",event=>{console.log("右クリックイベント発火:",event.target.textContent),event.preventDefault(),event.stopPropagation(),this.themeManager.showSettingsPanel(event.clientX,event.clientY)}),element.setAttribute("data-context-menu-added","true"),console.log("右クリックリスナー追加:",text))})}observePageChanges(){new MutationObserver(mutations=>{let shouldUpdate=!1;mutations.forEach(mutation=>{"childList"===mutation.type&&mutation.addedNodes.length>0&&(shouldUpdate=!0)}),shouldUpdate&&setTimeout(()=>this.applyDecoration(),100)}).observe(document.body,{childList:!0,subtree:!0})}}!function(){function init(){const themeManager=new ThemeManager,decorator=new Decorator(themeManager);window.atcoderDecorator=decorator,themeManager.applyTheme(),decorator.applyDecoration(),decorator.observePageChanges(),themeManager.createSettingsPanel(),window.addEventListener("load",function(){setTimeout(()=>decorator.applyDecoration(),500)})}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",init):init()}()}();