Fix what the review confirmed: anchoring, overlap, honesty, one voice
Fourteen findings from an adversarial review pass, applied together because most share two roots — geometry written against assumptions the renderer does not hold, and a design language spelled out longhand until it drifted. Correctness. The leader line pointed at empty space: CSS2DObject centres a label on its anchor by default, and margin only nudges the centred box — the overlay now anchors the left edge (center 0, 0.5) so the hairline meets the star. The info panel and not-found panel returned to top-4 at sm, under a search field that is 26rem wide and centred, covering the back button on every viewport from 640 to 1088px; they now wait for xl. The search empty state asserted "nothing matches" while the catalogues were still loading — and forever if they failed — so it now waits for the index. "Matches 8" was the page size wearing the costume of a count; the header now reports the real total, with the cap stated when it bites. The nameplate un-hides at lg instead of sm, clear of the rail and the object card. theme-color matches the void again. Accessibility. Tabbing to search changed one hairline's hue; the wrapper now carries the old ring as a visible focus indicator. Structure. hud-surface names the panel recipe that had been inlined at seven sites and had already forked into /85 and /92; the backdrop blur it carried is gone from every near-opaque panel — the canvas beneath redraws every frame, so each blur was re-sampled continuously for an effect the fill hid — and survives only as blur-sm on the genuinely translucent search shell. type-label and type-eyebrow name the two label voices, retiring 0.14em and the stray hover:bg-accent/10. The Measured/Derived rows both cards pasted twice each live once in ReadoutSectionsComponent; the reticle and chevron each draw from a single geometry, the reticle's stroke held in screen pixels so one mark serves every size. The acquire wipe plays once per search, not once per keystroke, because both outcomes now share one panel. hud-banner, which styled nothing since the rule was deleted, is a data-testid — the convention its own file already used. 527 unit tests, 6/6 end-to-end, production build, and a driven screenshot: every label now hangs off its star with the hairline touching the point. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WaySiNst4HhDXBHnMy8p5G
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
import { ChangeDetectionStrategy, Component, input } from '@angular/core';
|
||||
|
||||
/**
|
||||
* The route-rail chevron — "back to" when pointing left, "on to" when pointing right. One
|
||||
* geometry for every rail button, where each previously inlined its own copy of the svg.
|
||||
* Size and colour come from the classes on the host; the svg fills it.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-chevron-icon',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: { class: 'block', 'aria-hidden': 'true' },
|
||||
template: `
|
||||
<svg class="h-full w-full" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path [attr.d]="direction() === 'left' ? 'M15 6l-6 6 6 6' : 'M9 6l6 6-6 6'" />
|
||||
</svg>
|
||||
`
|
||||
})
|
||||
export class ChevronIconComponent {
|
||||
readonly direction = input<'left' | 'right'>('left');
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ChangeDetectionStrategy, Component, input } from '@angular/core';
|
||||
|
||||
/**
|
||||
* The circle-and-ticks lock mark the instrument brands itself with. The search field, the
|
||||
* nameplate and the viewport reticle all render this one geometry — it used to be drawn three
|
||||
* times, once with hand-rescaled coordinates, and the copies could drift apart.
|
||||
*
|
||||
* Size and colour come from the classes on the host (`h-4 w-4 text-accent/70` etc.); the svg
|
||||
* fills it. `vector-effect: non-scaling-stroke` keeps the stroke a screen-pixel width however
|
||||
* far the 24-unit viewBox is scaled, so `strokeWidth` means the same at every size.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-reticle-icon',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: { class: 'block', 'aria-hidden': 'true' },
|
||||
template: `
|
||||
<svg class="h-full w-full" viewBox="0 0 24 24" fill="none" stroke="currentColor" [attr.stroke-width]="strokeWidth()" stroke-linecap="round">
|
||||
<circle cx="12" cy="12" r="5" vector-effect="non-scaling-stroke" />
|
||||
<path d="M12 2v3M12 19v3M2 12h3M19 12h3" vector-effect="non-scaling-stroke" />
|
||||
</svg>
|
||||
`
|
||||
})
|
||||
export class ReticleIconComponent {
|
||||
readonly strokeWidth = input(1.5);
|
||||
}
|
||||
Reference in New Issue
Block a user