import { Component, computed, inject } from '@angular/core'; import { Router, RouterOutlet, isActive } from '@angular/router'; import type { CharacterResponse } from '../../core/api/game-api.models'; import { CombatStore } from '../../features/combat/combat.store'; import { WorldStore } from '../../features/world/world.store'; import { ContextPanelComponent } from '../context-panel/context-panel.component'; import { GameFooterComponent } from '../game-footer/game-footer.component'; import { SideNavigationComponent } from '../side-navigation/side-navigation.component'; import { TopBarComponent } from '../top-bar/top-bar.component'; @Component({ selector: 'app-app-shell', imports: [ RouterOutlet, TopBarComponent, SideNavigationComponent, GameFooterComponent, ContextPanelComponent, ], templateUrl: './app-shell.component.html', styleUrl: './app-shell.component.scss', }) export class AppShellComponent { private readonly router = inject(Router); protected readonly worldStore = inject(WorldStore); private readonly combatStore = inject(CombatStore); // The fight has its own log rail and wants the width, and the area info // belongs to the world view anyway, so the rail is dropped during combat. private readonly inCombat = isActive('/combat', this.router); // Outside a fight the HUD shows WorldStore's regen-ticked HP. Mid-fight, // regen is paused server-side and the only HP that moves is the combat's -- // the world snapshot is stale, so it must not drive the bar. protected readonly topBarCharacter = computed(() => { const character = this.worldStore.displayedCharacter(); const combat = this.inCombat() ? this.combatStore.combat() : null; if (!character || !combat) { return character; } return { ...character, currentHp: combat.player.currentHp, maxHp: combat.player.maxHp, hpRegenSince: null, }; }); // The location view brings its own, far richer context sidebar. Showing the // shell's generic area panel next to it would say the same thing twice and // squeeze the artwork the screen is built around. private readonly atLocation = isActive('/location', this.router); // The inventory is itself three columns wide — doll, bag, selected item — // and the area panel would push the bag down to a couple of cells a row. private readonly atInventory = isActive('/inventory', this.router); protected readonly showContextPanel = () => !this.inCombat() && !this.atLocation() && !this.atInventory(); }