AtCoderのWAやTLEの表示をテーマ別に装飾する拡張機能(ハロウィン、春など)
// ==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&¤tDay>=start.day||currentMonth<end.month||currentMonth===end.month&¤tDay<=end.day:!(currentMonth<start.month||currentMonth>end.month)&&(!(currentMonth===start.month&¤tDay<start.day)&&!(currentMonth===end.month&¤tDay>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()}()}();