signature: add systems map, command palette and motion primitives

Ship the Signature UX as standalone, SSR-safe pieces: bilingual copy, a dual SVG/list systems map, a Map-backed command palette in the shell, opt-in reveal and metric primitives, and a leak-free decorative canvas.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-25 17:37:25 +02:00
parent 9ea2885c7b
commit 7813499ee3
25 changed files with 2902 additions and 73 deletions

View File

@@ -0,0 +1,214 @@
import { ChangeDetectionStrategy, Component, computed, inject, input, signal } from '@angular/core';
import { Router, RouterLink } from '@angular/router';
import { SIGNATURE_COPY } from '../../core/content/signature-copy';
import { type AppLocale } from '../../core/i18n/locale';
import { LocaleService } from '../../core/i18n/locale.service';
import { NavigationService } from '../../core/navigation/navigation.service';
import { routePath } from '../../core/routing/route-paths';
import {
connectedNodeIds,
SYSTEMS_MAP_EDGES,
SYSTEMS_MAP_NODE_KINDS,
SYSTEMS_MAP_NODES,
type SystemsMapNode,
type SystemsMapNodeId,
} from './systems-map.model';
let systemsMapInstanceId = 0;
export interface SystemsMapNodeView {
readonly id: SystemsMapNodeId;
readonly kind: SystemsMapNode['kind'];
readonly routeId: SystemsMapNode['routeId'];
readonly x: number;
readonly y: number;
readonly label: string;
readonly summary: string;
readonly href: string;
readonly link: unknown[];
readonly relationship: string;
readonly accessibleName: string;
}
export interface SystemsMapEdgeView {
readonly from: SystemsMapNodeId;
readonly to: SystemsMapNodeId;
readonly x1: number;
readonly y1: number;
readonly x2: number;
readonly y2: number;
}
@Component({
selector: 'app-systems-map',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [RouterLink],
templateUrl: './systems-map.html',
styleUrl: './systems-map.scss',
})
export class SystemsMap {
readonly heading = input('');
readonly intro = input('');
readonly headingLevel = input<2 | 3>(2);
private readonly navigation = inject(NavigationService);
private readonly localeService = inject(LocaleService);
private readonly router = inject(Router);
private readonly instanceId = systemsMapInstanceId++;
protected readonly headingId = `systems-map-heading-${this.instanceId}`;
protected readonly svgTitleId = `systems-map-svg-title-${this.instanceId}`;
protected readonly svgDescId = `systems-map-svg-desc-${this.instanceId}`;
protected readonly listHeadingId = `systems-map-list-${this.instanceId}`;
protected readonly legendHeadingId = `systems-map-legend-${this.instanceId}`;
protected readonly activeNodeId = signal<SystemsMapNodeId | null>(null);
protected readonly copy = computed(() => SIGNATURE_COPY[this.localeService.locale()].systemsMap);
protected readonly headingText = computed(() => {
const override = this.heading().trim();
return override.length > 0 ? override : this.copy().heading;
});
protected readonly introText = computed(() => {
const override = this.intro().trim();
return override.length > 0 ? override : this.copy().intro;
});
protected readonly nodes = computed(() => {
const locale = this.localeService.locale();
const copy = this.copy();
return SYSTEMS_MAP_NODES.map((node) => this.toNodeView(node, locale, copy.relationshipLabel));
});
protected readonly edges = computed((): readonly SystemsMapEdgeView[] => {
const byId = new Map(SYSTEMS_MAP_NODES.map((node) => [node.id, node]));
return SYSTEMS_MAP_EDGES.map((edge) => {
const from = byId.get(edge.from);
const to = byId.get(edge.to);
return {
from: edge.from,
to: edge.to,
x1: from?.x ?? 0,
y1: from?.y ?? 0,
x2: to?.x ?? 0,
y2: to?.y ?? 0,
};
});
});
protected readonly legendItems = computed(() => {
const legend = this.copy().legend;
return SYSTEMS_MAP_NODE_KINDS.map((kind) => ({
kind,
label: legend[kind],
}));
});
protected readonly activeReadout = computed(() => {
const activeId = this.activeNodeId();
if (!activeId) {
return '';
}
const node = this.nodes().find((entry) => entry.id === activeId);
return node ? `${node.label}: ${node.relationship}` : '';
});
protected onNodeActivate(event: MouseEvent, node: SystemsMapNodeView): void {
if (event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
return;
}
event.preventDefault();
void this.router.navigate(this.navigation.link(node.routeId));
}
protected onNodeEnter(id: SystemsMapNodeId): void {
this.activeNodeId.set(id);
}
protected onNodeLeave(id: SystemsMapNodeId): void {
if (this.activeNodeId() === id) {
this.activeNodeId.set(null);
}
}
protected isConnectedNode(id: SystemsMapNodeId): boolean {
const active = this.activeNodeId();
if (!active) {
return false;
}
return active === id || this.neighborSet(active).has(id);
}
protected isDimmedNode(id: SystemsMapNodeId): boolean {
const active = this.activeNodeId();
if (!active) {
return false;
}
return active !== id && !this.neighborSet(active).has(id);
}
protected isConnectedEdge(edge: SystemsMapEdgeView): boolean {
const active = this.activeNodeId();
if (!active) {
return false;
}
return edge.from === active || edge.to === active;
}
protected isDimmedEdge(edge: SystemsMapEdgeView): boolean {
const active = this.activeNodeId();
if (!active) {
return false;
}
return edge.from !== active && edge.to !== active;
}
private toNodeView(
node: SystemsMapNode,
locale: AppLocale,
relationshipLabel: string,
): SystemsMapNodeView {
const connected = new Set(connectedNodeIds(node.id));
const connectedLabels = SYSTEMS_MAP_NODES.filter((entry) => connected.has(entry.id)).map(
(entry) => entry.label[locale],
);
const relationship = relationshipLabel.replace('{targets}', connectedLabels.join(', '));
const label = node.label[locale];
const summary = node.summary[locale];
return {
id: node.id,
kind: node.kind,
routeId: node.routeId,
x: node.x,
y: node.y,
label,
summary,
href: routePath(node.routeId, locale),
link: this.navigation.link(node.routeId),
relationship,
accessibleName: `${label}. ${summary} ${relationship}`,
};
}
private neighborSet(id: SystemsMapNodeId): ReadonlySet<SystemsMapNodeId> {
return new Set(connectedNodeIds(id));
}
}