fix: harden world travel presentation

This commit is contained in:
Bastian Wagner
2026-08-19 08:51:26 +02:00
parent 1e2bfe6e4b
commit 1a30eb3491
15 changed files with 238 additions and 37 deletions

View File

@@ -7,11 +7,12 @@
<p class="context-panel__selection">Ausgewähltes Ziel: {{ selected.targetLocation.name }}</p>
}
<img
class="context-panel__artwork"
[src]="location.artworkPath"
[alt]="'Ortsansicht: ' + location.name"
/>
<picture class="context-panel__artwork">
@if (runtimeArtworkPath(location.artworkPath); as runtimeArtwork) {
<source [srcset]="runtimeArtwork" type="image/jpeg" />
}
<img [src]="location.artworkPath" [alt]="'Ortsansicht: ' + location.name" />
</picture>
<p class="context-panel__description">{{ location.description }}</p>
<dl class="context-panel__facts">

View File

@@ -42,8 +42,13 @@
.context-panel__artwork {
display: block;
inline-size: 100%;
aspect-ratio: 16 / 9;
margin-block-end: var(--ar-space-3);
}
.context-panel__artwork img {
display: block;
inline-size: 100%;
aspect-ratio: 16 / 9;
border: 1px solid var(--ar-border);
object-fit: cover;
}

View File

@@ -0,0 +1,45 @@
import { signal } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { WorldStore } from '../../features/world/world.store';
import { ContextPanelComponent } from './context-panel.component';
describe('ContextPanelComponent', () => {
it('uses a runtime location derivative while preserving the API artwork path as image fallback', async () => {
await TestBed.configureTestingModule({
imports: [ContextPanelComponent],
providers: [
{
provide: WorldStore,
useValue: {
currentLocation: signal({
id: 'south-gate-id',
key: 'south-gate',
name: 'Südtor von Graufurt',
description: 'Der letzte sichere Schritt vor den Aschenfeldern.',
regionKey: 'ashen-fields',
minRecommendedLevel: 1,
maxRecommendedLevel: 1,
dangerLevel: 0,
isSafe: true,
huntingEnabled: false,
artworkPath: '/images/backgrounds/Suedtor.png',
connections: [],
}),
selectedConnection: signal(null),
},
},
],
}).compileComponents();
const fixture = TestBed.createComponent(ContextPanelComponent);
fixture.detectChanges();
const element = fixture.nativeElement as HTMLElement;
expect(element.querySelector<HTMLSourceElement>('source')?.srcset).toContain(
'/images/backgrounds/runtime/Suedtor-960.jpg',
);
expect(element.querySelector<HTMLImageElement>('img')?.getAttribute('src')).toBe(
'/images/backgrounds/Suedtor.png',
);
});
});

View File

@@ -1,6 +1,11 @@
import { Component, inject } from '@angular/core';
import { WorldStore } from '../../features/world/world.store';
const runtimeArtworkPaths: Readonly<Record<string, string>> = {
'/images/backgrounds/Suedtor.png': '/images/backgrounds/runtime/Suedtor-960.jpg',
'/images/backgrounds/Aschestrasse.png': '/images/backgrounds/runtime/Aschestrasse-960.jpg',
};
@Component({
selector: 'app-context-panel',
templateUrl: './context-panel.component.html',
@@ -8,4 +13,8 @@ import { WorldStore } from '../../features/world/world.store';
})
export class ContextPanelComponent {
protected readonly worldStore = inject(WorldStore);
protected runtimeArtworkPath(artworkPath: string): string | undefined {
return runtimeArtworkPaths[artworkPath];
}
}