Theme-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         Theme-AtCoder
// @namespace    https://github.com/mimimi105/theme_atcoder_extension
// @version      2.0.5
// @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 theme of Object.values(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)})}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: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%) !important;\n                    border: none !important;\n                    border-radius: 12px !important;\n                    padding: 14px !important;\n                    box-shadow: 0 8px 32px rgba(0,0,0,0.12), 0 2px 8px rgba(0,0,0,0.08) !important;\n                    z-index: 10000 !important;\n                    font-family: 'Noto Sans', 'Noto Color Emoji', system-ui, -apple-system, sans-serif !important;\n                    min-width: 240px !important;\n                    display: none !important;\n                    backdrop-filter: blur(10px) !important;\n                }\n                #atcoder-theme-settings.visible {\n                    display: block !important;\n                    animation: slideIn 0.2s ease-out !important;\n                }\n                @keyframes slideIn {\n                    from {\n                        opacity: 0;\n                        transform: translateY(-10px);\n                    }\n                    to {\n                        opacity: 1;\n                        transform: translateY(0);\n                    }\n                }\n                #atcoder-theme-settings * {\n                    all: revert !important;\n                }\n                #atcoder-theme-settings label {\n                    display: block !important;\n                    margin: 0 0 8px 0 !important;\n                    padding: 0 !important;\n                    font-size: 13px !important;\n                    font-weight: 600 !important;\n                    color: #2c3e50 !important;\n                    line-height: normal !important;\n                    letter-spacing: 0.3px !important;\n                }\n                #atcoder-theme-settings select {\n                    display: block !important;\n                    width: 100% !important;\n                    margin: 0 !important;\n                    padding: 10px 12px !important;\n                    font-size: 14px !important;\n                    font-family: 'Noto Sans', 'Noto Color Emoji', system-ui, -apple-system, sans-serif !important;\n                    line-height: normal !important;\n                    color: #2c3e50 !important;\n                    background: white !important;\n                    border: 2px solid #e1e8ed !important;\n                    border-radius: 8px !important;\n                    box-sizing: border-box !important;\n                    cursor: pointer !important;\n                    transition: all 0.2s ease !important;\n                    appearance: none !important;\n                    -webkit-appearance: none !important;\n                    -moz-appearance: none !important;\n                    background-image: url(\"data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232c3e50' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e\") !important;\n                    background-repeat: no-repeat !important;\n                    background-position: right 8px center !important;\n                    background-size: 20px !important;\n                    padding-right: 36px !important;\n                }\n                #atcoder-theme-settings select:hover {\n                    border-color: #3498db !important;\n                    box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1) !important;\n                }\n                #atcoder-theme-settings select:focus {\n                    outline: none !important;\n                    border-color: #3498db !important;\n                    box-shadow: 0 0 0 4px rgba(52, 152, 219, 0.15) !important;\n                }\n                #create-test-btn {\n                    display: block !important;\n                    width: 100% !important;\n                    margin-top: 12px !important;\n                    padding: 10px !important;\n                    background: linear-gradient(135deg, #4CAF50 0%, #45a049 100%) !important;\n                    color: white !important;\n                    border: none !important;\n                    border-radius: 8px !important;\n                    cursor: pointer !important;\n                    font-size: 13px !important;\n                    font-weight: 600 !important;\n                    font-family: 'Noto Sans', 'Noto Color Emoji', system-ui, -apple-system, sans-serif !important;\n                    line-height: normal !important;\n                    transition: all 0.2s ease !important;\n                    box-shadow: 0 2px 8px rgba(76, 175, 80, 0.3) !important;\n                }\n                #create-test-btn:hover {\n                    background: linear-gradient(135deg, #45a049 0%, #3d8b40 100%) !important;\n                    box-shadow: 0 4px 12px rgba(76, 175, 80, 0.4) !important;\n                    transform: translateY(-1px) !important;\n                }\n                #create-test-btn:active {\n                    transform: translateY(0) !important;\n                    box-shadow: 0 2px 4px rgba(76, 175, 80, 0.3) !important;\n                }\n                #atcoder-theme-settings .select2.select2-container.select2-container--bootstrap {\n                    display: none !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){const panel=document.getElementById("atcoder-theme-settings");if(!panel)return;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")}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=>{event.preventDefault(),event.stopPropagation(),this.themeManager.showSettingsPanel(event.clientX,event.clientY)}),element.setAttribute("data-context-menu-added","true"))})}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()}()}();