| class CombatSequence extends HTMLElement { |
| constructor() { |
| super(); |
| this.attachShadow({ mode: 'open' }); |
| } |
|
|
| connectedCallback() { |
| this.render(); |
| } |
|
|
| static get observedAttributes() { |
| return ['sequence-id', 'accuracy', 'hits', 'shots', 'suspicion']; |
| } |
|
|
| attributeChangedCallback(name, oldValue, newValue) { |
| if (oldValue !== newValue) { |
| this.render(); |
| } |
| } |
|
|
| render() { |
| this.shadowRoot.innerHTML = ` |
| <style> |
| :host { |
| display: block; |
| background-color: #1f2937; |
| border-radius: 0.5rem; |
| padding: 1rem; |
| margin-bottom: 1rem; |
| transition: all 0.2s ease; |
| } |
| |
| :host(:hover) { |
| transform: translateY(-2px); |
| box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.3); |
| } |
| |
| .header { |
| display: flex; |
| justify-content: space-between; |
| align-items: flex-start; |
| margin-bottom: 0.75rem; |
| } |
| |
| .title { |
| font-weight: 600; |
| font-size: 1.125rem; |
| } |
| |
| .id { |
| font-size: 0.75rem; |
| color: #9ca3af; |
| } |
| |
| .accuracy { |
| padding: 0.25rem 0.5rem; |
| border-radius: 0.25rem; |
| font-size: 0.75rem; |
| font-weight: 500; |
| } |
| |
| .high-accuracy { |
| background-color: #ef4444; |
| } |
| |
| .normal-accuracy { |
| background-color: #3b82f6; |
| } |
| |
| .stats { |
| display: flex; |
| justify-content: space-between; |
| font-size: 0.75rem; |
| margin-bottom: 0.25rem; |
| } |
| |
| .meter-container { |
| margin-bottom: 0.5rem; |
| } |
| |
| .meter { |
| height: 0.25rem; |
| border-radius: 0.125rem; |
| background-color: #374151; |
| overflow: hidden; |
| } |
| |
| .meter-fill { |
| height: 100%; |
| background: linear-gradient(90deg, #3b82f6, #ef4444); |
| } |
| |
| .suspicion-label { |
| display: flex; |
| justify-content: space-between; |
| font-size: 0.75rem; |
| } |
| |
| .suspicion-meter { |
| height: 0.25rem; |
| border-radius: 0.125rem; |
| background-color: #374151; |
| overflow: hidden; |
| } |
| |
| .suspicion-fill { |
| height: 100%; |
| background: linear-gradient(90deg, #10b981, #ef4444); |
| } |
| </style> |
| |
| <div class="header"> |
| <div> |
| <div class="title">Combat Sequence</div> |
| <div class="id">${this.getAttribute('sequence-id') || 'Unknown'}</div> |
| </div> |
| <div class="accuracy ${this.getAccuracyClass()}"> |
| ${Math.round((parseFloat(this.getAttribute('accuracy')) || 0) * 100)}% |
| </div> |
| </div> |
| |
| <div class="meter-container"> |
| <div class="stats"> |
| <span>${this.getAttribute('hits') || 0} hits</span> |
| <span>${this.getAttribute('shots') || 0} shots</span> |
| </div> |
| <div class="meter"> |
| <div class="meter-fill" style="width: ${(parseFloat(this.getAttribute('accuracy')) || 0) * 100}%"></div> |
| </div> |
| </div> |
| |
| <div> |
| <div class="suspicion-label"> |
| <span>Suspicion level</span> |
| <span>${this.getAttribute('suspicion') || 0}/100</span> |
| </div> |
| <div class="suspicion-meter"> |
| <div class="suspicion-fill" style="width: ${this.getAttribute('suspicion') || 0}%"></div> |
| </div> |
| </div> |
| `; |
| } |
|
|
| getAccuracyClass() { |
| const accuracy = parseFloat(this.getAttribute('accuracy')) || 0; |
| return accuracy > 0.6 ? 'high-accuracy' : 'normal-accuracy'; |
| } |
| } |
|
|
| customElements.define('combat-sequence', CombatSequence); |