import { LitElement, html, css } from "lit"; import { narrativeManager } from "../managers/NarrativeManager.js"; export class DialogueOverlay extends LitElement { static get styles() { return css` :host { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); width: 80%; max-width: 800px; z-index: 100; pointer-events: auto; font-family: "Courier New", monospace; } .dialogue-box { background: rgba(10, 10, 20, 0.95); border: 2px solid #00ffff; box-shadow: 0 0 20px rgba(0, 255, 255, 0.2); padding: 20px; display: flex; gap: 20px; animation: slideUp 0.3s ease-out; } .portrait { width: 100px; height: 100px; background: #222; border: 1px solid #555; flex-shrink: 0; } .portrait img { width: 100%; height: 100%; object-fit: cover; } .content { flex-grow: 1; display: flex; flex-direction: column; } .speaker { color: #00ffff; font-weight: bold; font-size: 1.2rem; margin-bottom: 5px; } .text { color: white; font-size: 1.1rem; line-height: 1.5; min-height: 3em; } .choices { margin-top: 15px; display: flex; gap: 10px; } button { background: #333; color: white; border: 1px solid #555; padding: 8px 16px; cursor: pointer; font-family: inherit; text-transform: uppercase; } button:hover { background: #444; border-color: #00ffff; } .next-indicator { align-self: flex-end; font-size: 0.8rem; color: #888; margin-top: 10px; animation: blink 1s infinite; } @keyframes slideUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } @keyframes blink { 50% { opacity: 0; } } /* Tutorial Style Override */ .type-tutorial { border-color: #00ff00; } .type-tutorial .speaker { color: #00ff00; } `; } static get properties() { return { activeNode: { type: Object }, isVisible: { type: Boolean }, }; } constructor() { super(); this.activeNode = null; this.isVisible = false; } connectedCallback() { super.connectedCallback(); // Subscribe to Manager Updates narrativeManager.addEventListener( "narrative-update", this._onUpdate.bind(this) ); narrativeManager.addEventListener("narrative-end", this._onEnd.bind(this)); // Allow clicking/spacebar to advance window.addEventListener("keydown", this._handleInput.bind(this)); } disconnectedCallback() { super.disconnectedCallback(); window.removeEventListener("keydown", this._handleInput.bind(this)); } _onUpdate(e) { this.activeNode = e.detail.node; this.isVisible = e.detail.active; } _onEnd() { this.isVisible = false; this.activeNode = null; } _handleInput(e) { if (!this.isVisible) return; if (e.code === "Space" || e.code === "Enter") { // Only advance if no choices if (!this.activeNode.choices) { narrativeManager.next(); } } } render() { if (!this.isVisible || !this.activeNode) return html``; return html`