feat: minimal signals + RemoteData template with a users feature

Extracted from atomic-design-poc: RemoteData<E,T> (bare union + fromResource,
no combinators) + a trimmed <app-async> switch, no Elm-style store — state is
resource() plus one plain signal. Minimal DDD layering per context
(domain/infrastructure/application/ui) combined with atomic design inside
ui/ (atoms/molecules/organisms/templates/pages), mirroring the POC's
conventions at template scale.

One worked feature (users/): a list with a click-through to a detail view
(its own independent resource() fetch) and a Back action. Tests are
BDD-style (describe/it, one assertion per it) and black-box (assert
rendered DOM/emitted events only) - 100% branch/line coverage. README.md
documents what's deliberately omitted vs. the POC and the concrete growth
path back to it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
eho
2026-07-31 23:27:09 +02:00
co-authored by Claude Sonnet 5
parent 209df1ae5a
commit 927404afd7
29 changed files with 778 additions and 418 deletions
@@ -0,0 +1,32 @@
import { Component, input, output } from '@angular/core';
import { SpinnerComponent } from '@shared/ui/atoms/spinner.component';
import type { RemoteData } from '@shared/application/remote-data';
@Component({
selector: 'app-async',
imports: [SpinnerComponent],
template: `
@switch (data().tag) {
@case ('Loading') {
<app-spinner />
}
@case ('Empty') {
<p>{{ emptyText() }}</p>
}
@case ('Failure') {
<p role="alert">{{ errorText() }}</p>
<button type="button" (click)="retry.emit()">{{ retryText() }}</button>
}
@case ('Success') {
<ng-content />
}
}
`,
})
export class AsyncComponent<T> {
data = input.required<RemoteData<unknown, T>>();
emptyText = input('No data.');
errorText = input('Something went wrong.');
retryText = input('Retry');
retry = output<void>();
}