63 lines
2.5 KiB
TypeScript
63 lines
2.5 KiB
TypeScript
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<CharacterResponse | null>(() => {
|
|
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();
|
|
}
|