diff --git a/ai_animation/index.html b/ai_animation/index.html index 72e1cba..3bbc6c4 100644 --- a/ai_animation/index.html +++ b/ai_animation/index.html @@ -39,10 +39,29 @@
Diplomatic actions unfolding...
- - diff --git a/ai_animation/src/debug/debugMenu.ts b/ai_animation/src/debug/debugMenu.ts new file mode 100644 index 0000000..a83c0af --- /dev/null +++ b/ai_animation/src/debug/debugMenu.ts @@ -0,0 +1,173 @@ +/** + * Debug Menu Management + * Handles the collapsible debug menu and organization of debug tools + */ + +export class DebugMenu { + private toggleBtn: HTMLButtonElement; + private panel: HTMLElement; + private closeBtn: HTMLButtonElement; + private isExpanded: boolean = false; + + constructor() { + this.toggleBtn = document.getElementById('debug-toggle-btn') as HTMLButtonElement; + this.panel = document.getElementById('debug-panel') as HTMLElement; + this.closeBtn = document.getElementById('debug-close-btn') as HTMLButtonElement; + + if (!this.toggleBtn || !this.panel || !this.closeBtn) { + throw new Error('Debug menu elements not found in DOM'); + } + + this.initEventListeners(); + } + + private initEventListeners(): void { + // Toggle button click + this.toggleBtn.addEventListener('click', () => { + this.toggle(); + }); + + // Close button click + this.closeBtn.addEventListener('click', () => { + this.collapse(); + }); + + // Close on escape key + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && this.isExpanded) { + this.collapse(); + } + }); + + // Close when clicking outside the menu + document.addEventListener('click', (e) => { + const target = e.target as Node; + const debugMenu = document.getElementById('debug-menu'); + if (this.isExpanded && debugMenu && !debugMenu.contains(target)) { + this.collapse(); + } + }); + } + + /** + * Shows the debug menu + */ + public show(): void { + const debugMenu = document.getElementById('debug-menu'); + if (debugMenu) { + debugMenu.style.display = 'block'; + } + } + + /** + * Hides the debug menu completely + */ + public hide(): void { + const debugMenu = document.getElementById('debug-menu'); + if (debugMenu) { + debugMenu.style.display = 'none'; + } + this.collapse(); + } + + /** + * Toggles the debug panel expansion + */ + public toggle(): void { + if (this.isExpanded) { + this.collapse(); + } else { + this.expand(); + } + } + + /** + * Expands the debug panel + */ + public expand(): void { + this.panel.classList.remove('debug-panel-collapsed'); + this.panel.classList.add('debug-panel-expanded'); + this.isExpanded = true; + this.toggleBtn.textContent = '🔧 Debug ▲'; + } + + /** + * Collapses the debug panel + */ + public collapse(): void { + this.panel.classList.remove('debug-panel-expanded'); + this.panel.classList.add('debug-panel-collapsed'); + this.isExpanded = false; + this.toggleBtn.textContent = '🔧 Debug'; + } + + /** + * Adds a new debug tool section to the menu + * @param title - The title of the debug section + * @param content - HTML content for the debug tool + * @param beforeSection - Optional: insert before this section (by title) + */ + public addDebugTool(title: string, content: string, beforeSection?: string): void { + const debugContent = this.panel.querySelector('.debug-content'); + if (!debugContent) return; + + // Create new section + const section = document.createElement('div'); + section.className = 'debug-section'; + section.innerHTML = ` +

${title}

+ ${content} + `; + + if (beforeSection) { + // Find the section to insert before + const sections = debugContent.querySelectorAll('.debug-section h4'); + for (const h4 of sections) { + if (h4.textContent === beforeSection) { + const targetSection = h4.parentElement; + if (targetSection) { + debugContent.insertBefore(section, targetSection); + return; + } + } + } + } + + // If no specific position, insert before "Future Tools" section or at the end + const futureToolsSection = Array.from(debugContent.querySelectorAll('.debug-section h4')) + .find(h4 => h4.textContent === 'Future Tools')?.parentElement; + + if (futureToolsSection) { + debugContent.insertBefore(section, futureToolsSection); + } else { + debugContent.appendChild(section); + } + } + + /** + * Removes a debug tool section + * @param title - The title of the section to remove + */ + public removeDebugTool(title: string): void { + const debugContent = this.panel.querySelector('.debug-content'); + if (!debugContent) return; + + const sections = debugContent.querySelectorAll('.debug-section h4'); + for (const h4 of sections) { + if (h4.textContent === title) { + const section = h4.parentElement; + if (section) { + section.remove(); + break; + } + } + } + } + + /** + * Gets the current expansion state + */ + public get expanded(): boolean { + return this.isExpanded; + } +} \ No newline at end of file diff --git a/ai_animation/src/domElements.ts b/ai_animation/src/domElements.ts index 2875893..d61a2c3 100644 --- a/ai_animation/src/domElements.ts +++ b/ai_animation/src/domElements.ts @@ -74,8 +74,18 @@ if (null === leaderboard) throw new Error("Element with ID 'leaderboard' not fou export const standingsBtn = document.getElementById('standings-btn'); if (null === standingsBtn) throw new Error("Element with ID 'standings-btn' not found"); -export const debugProvincePanel = document.getElementById('debug-province-panel'); -if (null === debugProvincePanel) throw new Error("Element with ID 'debug-province-panel' not found"); +// Debug menu elements +export const debugMenu = document.getElementById('debug-menu'); +if (null === debugMenu) throw new Error("Element with ID 'debug-menu' not found"); + +export const debugToggleBtn = document.getElementById('debug-toggle-btn') as HTMLButtonElement; +if (null === debugToggleBtn) throw new Error("Element with ID 'debug-toggle-btn' not found"); + +export const debugPanel = document.getElementById('debug-panel'); +if (null === debugPanel) throw new Error("Element with ID 'debug-panel' not found"); + +export const debugCloseBtn = document.getElementById('debug-close-btn') as HTMLButtonElement; +if (null === debugCloseBtn) throw new Error("Element with ID 'debug-close-btn' not found"); export const provinceInput = document.getElementById('province-input') as HTMLInputElement; if (null === provinceInput) throw new Error("Element with ID 'province-input' not found"); diff --git a/ai_animation/src/main.ts b/ai_animation/src/main.ts index b9a907b..8f0a61e 100644 --- a/ai_animation/src/main.ts +++ b/ai_animation/src/main.ts @@ -12,8 +12,9 @@ import { Tween, Group, Easing } from "@tweenjs/tween.js"; import { initRotatingDisplay, updateRotatingDisplay } from "./components/rotatingDisplay"; import { closeTwoPowerConversation, showTwoPowerConversation } from "./components/twoPowerConversation"; import { PowerENUM } from "./types/map"; -import { debugProvincePanel, provinceInput, highlightProvinceBtn } from "./domElements"; +import { debugMenu, provinceInput, highlightProvinceBtn } from "./domElements"; import { highlightProvince, getAvailableProvinces } from "./debug/provinceHighlight"; +import { DebugMenu } from "./debug/debugMenu"; //TODO: Create a function that finds a suitable unit location within a given polygon, for placing units better // Currently the location for label, unit, and SC are all the same manually picked location @@ -21,6 +22,8 @@ import { highlightProvince, getAvailableProvinces } from "./debug/provinceHighli const isDebugMode = config.isDebugMode; const isStreamingMode = import.meta.env.VITE_STREAMING_MODE +let debugMenuInstance: DebugMenu | null = null; + // --- INITIALIZE SCENE --- function initScene() { gameState.createThreeScene() @@ -50,9 +53,10 @@ function initScene() { gameState.loadGameFile(0); } - // Show debug province panel if in debug mode + // Initialize debug menu if in debug mode if (isDebugMode) { - debugProvincePanel.style.display = 'block'; + debugMenuInstance = new DebugMenu(); + debugMenuInstance.show(); } if (isStreamingMode) { setTimeout(() => { @@ -295,8 +299,10 @@ speedSelector.addEventListener('change', e => { } }); -// Debug province highlighting event handlers -if (isDebugMode) { +// Initialize debug province highlighting functionality +function initDebugProvinceHighlighting() { + if (!isDebugMode) return; + highlightProvinceBtn.addEventListener('click', () => { const provinceName = provinceInput.value.trim(); if (provinceName) { @@ -332,6 +338,11 @@ if (isDebugMode) { }); } +// Initialize debug functionality after the scene is loaded +if (isDebugMode) { + initDebugProvinceHighlighting(); +} + // --- BOOTSTRAP ON PAGE LOAD --- window.addEventListener('load', initScene); diff --git a/ai_animation/src/style.css b/ai_animation/src/style.css index 6d5bf15..d3d6c8b 100644 --- a/ai_animation/src/style.css +++ b/ai_animation/src/style.css @@ -756,30 +756,149 @@ } /* ----------------- - Debug Province Panel + Debug Menu ----------------- */ - #debug-province-panel { - position: absolute; + #debug-menu { + position: fixed; top: 80px; right: 10px; - background: radial-gradient(ellipse at center, #f7ecd1 0%, #dbc08c 100%); - border: 3px solid #4f3b16; - border-radius: 8px; - padding: 15px; - box-shadow: 0 0 10px rgba(0,0,0,0.4); - z-index: 100; + z-index: 200; font-family: "Book Antiqua", Palatino, serif; } + #debug-toggle-btn { + padding: 10px 15px; + background-color: #8d5a2b; + color: #f0e6d2; + border: 2px solid #2e1c10; + border-radius: 6px; + cursor: pointer; + font-family: "Book Antiqua", Palatino, serif; + font-size: 14px; + box-shadow: 0 2px 8px rgba(0,0,0,0.3); + transition: all 0.2s ease; + } + + #debug-toggle-btn:hover { + background-color: #a4703a; + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(0,0,0,0.4); + } + + #debug-panel { + position: absolute; + top: 50px; + right: 0; + width: 350px; + background: radial-gradient(ellipse at center, #f7ecd1 0%, #dbc08c 100%); + border: 3px solid #4f3b16; + border-radius: 8px; + box-shadow: 0 4px 20px rgba(0,0,0,0.5); + transition: all 0.3s ease; + overflow: hidden; + } + + .debug-panel-collapsed { + max-height: 0; + opacity: 0; + transform: translateY(-10px); + pointer-events: none; + } + + .debug-panel-expanded { + max-height: 600px; + opacity: 1; + transform: translateY(0); + pointer-events: auto; + } + + .debug-header { + background: linear-gradient(90deg, #5a3e2b 0%, #382519 100%); + color: #f0e6d2; + padding: 12px 15px; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 2px solid #4f3b16; + } + + .debug-header h3 { + margin: 0; + font-size: 16px; + letter-spacing: 1px; + text-shadow: 1px 1px 2px #000; + } + + #debug-close-btn { + background: transparent; + color: #f0e6d2; + border: none; + font-size: 20px; + cursor: pointer; + padding: 0; + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 50%; + transition: all 0.2s ease; + } + + #debug-close-btn:hover { + background-color: rgba(255, 255, 255, 0.1); + color: #ff9e54; + } + + .debug-content { + padding: 15px; + max-height: 500px; + overflow-y: auto; + } + + .debug-section { + margin-bottom: 20px; + padding-bottom: 15px; + border-bottom: 1px solid #c9b887; + } + + .debug-section:last-child { + border-bottom: none; + margin-bottom: 0; + } + + .debug-section h4 { + margin: 0 0 10px 0; + color: #2f260b; + font-size: 14px; + font-weight: bold; + text-transform: uppercase; + letter-spacing: 1px; + } + + .debug-tool { + display: flex; + gap: 8px; + align-items: center; + flex-wrap: wrap; + } + + .debug-placeholder { + color: #666; + font-style: italic; + margin: 5px 0; + font-size: 12px; + } + #province-input { - padding: 8px 12px; + padding: 6px 10px; border: 2px solid #4f3b16; border-radius: 4px; background-color: #faf0d8; color: #2f260b; font-family: "Book Antiqua", Palatino, serif; width: 200px; - margin-right: 10px; + font-size: 12px; } #province-input:focus { @@ -789,15 +908,38 @@ } #highlight-province-btn { - padding: 8px 12px; + padding: 6px 12px; background-color: #8d5a2b; color: #f0e6d2; border: 2px solid #2e1c10; border-radius: 4px; cursor: pointer; font-family: "Book Antiqua", Palatino, serif; + font-size: 12px; + white-space: nowrap; } #highlight-province-btn:hover { background-color: #a4703a; } + + /* Responsive adjustments for debug menu */ + @media (max-width: 768px) { + #debug-menu { + right: 5px; + } + + #debug-panel { + width: 300px; + } + + .debug-tool { + flex-direction: column; + align-items: stretch; + } + + #province-input { + width: 100%; + margin-bottom: 5px; + } + }