import { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core'; import { ViewLevel } from '../../shared/state/navigation.store'; export interface HudReadout { readonly label: string; readonly value: string; } interface LadderStep { readonly level: ViewLevel; readonly label: string; /** Above the active step, on it, or below it — which is what the step is styled from. */ readonly state: 'above' | 'current' | 'below'; /** Whether this step is somewhere the view can be sent right now. */ readonly reachable: boolean; } /** Outermost first — the order the ladder is drawn in, and the order levels nest. */ const LADDER: readonly { level: ViewLevel; label: string }[] = [ { level: 'galactic', label: 'Milky Way' }, { level: 'galaxy', label: 'Solar Neighbourhood' }, { level: 'system', label: 'System' } ]; /** * The map's heads-up display: the scale ladder down the left, the readout panel across the * bottom, a centre reticle on whatever the camera is holding, and the frame brackets around * the whole viewport. * * Purely presentational — every value arrives as an input and the only thing it emits is a * request to move to another scale. The scene owns the camera and decides what that means. * * Reachable levels render as buttons and the current one renders as a static marker rather than * a button that does nothing. The galactic and neighbourhood scales are always reachable, in * both directions: they are one continuous space and the Sun is always in it. The system scale * is not, since there is no system to go to until a star has been picked. */ @Component({ selector: 'app-starmap-hud', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'pointer-events-none absolute inset-0 block select-none' }, template: `
@if (showReticle()) {
}

{{ eyebrow() }}

{{ title() }}

@if (subtitle()) {

{{ subtitle() }}

} @if (readouts().length) {
@for (readout of readouts(); track readout.label) {
{{ readout.label }}
{{ readout.value }}
}
} @if (note()) {

{{ note() }}

}

Range

{{ range() }}

` }) export class StarmapHudComponent { readonly level = input.required(); /** Headline for the readout panel — the selected star, or the name of the current scale. */ readonly title = input(''); readonly subtitle = input(''); readonly eyebrow = input(''); readonly readouts = input([]); /** Standing caveat for the current view, e.g. that galactic structure is a model. */ readonly note = input(''); /** Camera range, pre-formatted by the scene, which is the only thing that knows the units. */ readonly range = input(''); readonly showReticle = input(true); readonly levelSelected = output(); readonly ladder = computed(() => { const activeIndex = LADDER.findIndex((step) => step.level === this.level()); return LADDER.map((step, index) => ({ ...step, state: index < activeIndex ? 'above' : index === activeIndex ? 'current' : 'below', // Every scale is somewhere the camera can be sent except the current one and the system // level, which needs a star picked first — there is no "the system" without a selection. reachable: index !== activeIndex && step.level !== 'system' })); }); }