Files
star-map/src/app/features/body-detail/body-detail.model.ts
T
Claude 7b0f32f71a Assemble a body's readouts once, not once per panel
Follow-up to review on #3. The card and the detail page each built their own Measured/Derived
split, kind label and provenance sentence — the drift buildBodyViewModel exists to prevent,
re-forked one layer up, and the drift would have been in which side of the measured/derived line
a quantity falls on, which is the distinction those panels exist to draw. One bodyReadouts(body)
now returns both blocks and the sentence, and both templates iterate it. The two surfaces render
identical rows as a result, and the card gains the inclination the detail page already showed.

Also from that review:

- KIND_LABELS was duplicated between the two panels; it now lives beside bodyReadouts. The third
  copy the review pointed at is a different union (search results are star/body/exoplanet, and
  label a body "Body"), so it stays where it is.
- CardRow was HudReadout renamed. Both are now Readout, which HudReadout extends with its
  derived flag.
- The enterable-systems count was a 21-line lazy memo over arrays that are already in hand; it is
  one expression where those arrays are assigned.
- buildBodyViewModel now carries hostStarId, so the detail scene stops rescanning both catalogues
  for something the builder had already resolved.
- heliocentricPeriodDays was called twice for the same body.
- The superscript helper was a split/map/join; it is a replace.
- info-panel had five computed() each wrapping one pure call with a non-null assertion, beside a
  template that inlined the same kind of call directly. They are gone with the shared readouts.
- Dropped a tautological test that compared a pure function to itself. Replaced with one that
  asserts the host star id the builder now carries.
- Removed the orphaned doc comment left behind when formatParsecs/formatAu moved out.

And one the review raised as out of scope but is worth taking: formatRadiusKm grouped thousands
above its decimal threshold and not below it, so 69,911 km sat beside a bare 6371 km. Both are
grouped now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WaySiNst4HhDXBHnMy8p5G
2026-08-06 03:52:11 +00:00

48 lines
2.0 KiB
TypeScript

import { PlanetAppearance } from '../../shared/astro/planet-appearance';
import { OrbitalElements } from '../../shared/models/body.model';
export type BodyDetailKind = 'planet' | 'moon' | 'dwarf' | 'exoplanet';
/**
* Flattened view model combining the fields `InfoPanelComponent` displays, regardless of
* whether the selected body came from `bodies.json` (solar-system `BodyRecord`) or
* `exoplanets.json` (`ExoplanetRecord`) — the two sources report different subsets of data.
*/
export interface BodyDetailViewModel {
id: string;
name: string;
kind: BodyDetailKind;
hostStarName: string;
/**
* The host star's catalogue id, so a caller that has the view model does not have to rescan the
* catalogues to find what building it already resolved. Undefined for an exoplanet whose host
* never cross-referenced to the star catalogue.
*/
hostStarId?: number;
radiusKm?: number;
massEarth?: number;
discoveryYear?: number;
orbit: Partial<OrbitalElements>;
/**
* What this world is inferred to look like, and the quantities that inference rests on. Always
* present — every body has measurements enough to place it somewhere — but its individual
* fields are nullable, since a body whose host star is not in the catalogue has no derived
* temperature.
*/
appearance: PlanetAppearance;
/** True when a real photograph is being shown rather than the derived surface. */
hasPhotography: boolean;
/**
* Sidereal orbital period. Measured where the archive published one; otherwise derived from the
* semi-major axis for heliocentric orbits, where the central mass is known exactly. Undefined
* when neither applies — see `heliocentricPeriodDays`.
*/
orbitalPeriodDays?: number;
/**
* Which of those two the period is, so the surfaces can file it under the right heading. A
* derived period presented as an observation is the same category of error as presenting a
* derived surface as a photograph.
*/
orbitalPeriodSource?: 'measured' | 'derived';
}