fix: style; feat: AGENTS.md

This commit is contained in:
2026-05-14 12:52:11 +02:00
parent 3efece9e29
commit 3d81db7d53
6 changed files with 230 additions and 76 deletions
-2
View File
@@ -1,7 +1,6 @@
import type { ApplicationConfig } from '@angular/core';
import { provideZoneChangeDetection } from '@angular/core';
import { provideRouter, withInMemoryScrolling } from '@angular/router';
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
import { routes } from './app.routes';
@@ -15,6 +14,5 @@ export const appConfig: ApplicationConfig = {
scrollPositionRestoration: 'top',
}),
),
provideClientHydration(withEventReplay()),
],
};
+2 -3
View File
@@ -57,13 +57,12 @@
<div class="portrait-media" [class.portrait-media-switching]="isPortraitSwitching">
<img
class="hero-feature-image"
[ngSrc]="currentPortraitHighlight.image"
[src]="currentPortraitHighlight.image"
[attr.srcset]="currentPortraitHighlight.imageSrcset"
[attr.sizes]="currentPortraitHighlight.imageSizes"
[width]="currentPortraitHighlight.imageWidth"
[height]="currentPortraitHighlight.imageHeight"
disableOptimizedSrcset
priority
fetchpriority="high"
decoding="async"
[alt]="currentPortraitHighlight.text + ' ' + content().home.portraitAltSuffix"
/>
+24
View File
@@ -33,6 +33,7 @@ describe('HomeComponent', (): void => {
scheduleNameGradientUpdate(): void;
scheduleProjectEntryRevealUpdate(): void;
scheduleAboutSectionScrollAnimationUpdate(): void;
shouldEnableScrollEffects(): boolean;
toggleBio(): void;
showNextPortraitHighlight(): void;
scrollToAboutSection(): void;
@@ -428,6 +429,29 @@ describe('HomeComponent', (): void => {
// ── RAF debouncing (performance) ───────────────────────────────────────────
describe('Performance', (): void => {
it('should keep scroll effects enabled on small viewports when motion is allowed', (): void => {
spyOnProperty(window, 'innerWidth').and.returnValue(390);
spyOn(window, 'matchMedia').and.callFake(
(query: string): MediaQueryList =>
({
matches: query === '(prefers-reduced-motion: reduce)' ? false : true,
}) as MediaQueryList,
);
expect(comp.shouldEnableScrollEffects()).toBeTrue();
});
it('should disable scroll effects when reduced motion is requested', (): void => {
spyOn(window, 'matchMedia').and.callFake(
(query: string): MediaQueryList =>
({
matches: query === '(prefers-reduced-motion: reduce)',
}) as MediaQueryList,
);
expect(comp.shouldEnableScrollEffects()).toBeFalse();
});
it('should create and run initial change detection within 200 ms', (): void => {
const start = performance.now();
const f = TestBed.createComponent(HomeComponent);
+1 -3
View File
@@ -220,13 +220,11 @@ export class HomeComponent implements OnInit, AfterViewInit, OnDestroy {
private shouldEnableScrollEffects(): boolean {
if (typeof window === 'undefined') return false;
const isSmallViewport: boolean = window.innerWidth <= 700;
const prefersReducedMotion: boolean = window.matchMedia(
'(prefers-reduced-motion: reduce)',
).matches;
const isCoarsePointer: boolean = window.matchMedia('(pointer: coarse)').matches;
return !isSmallViewport && !prefersReducedMotion && !isCoarsePointer;
return !prefersReducedMotion;
}
private initNameGradientScrollAnimation(): void {
+10 -22
View File
@@ -1010,14 +1010,6 @@ hr {
scroll-behavior: auto;
}
body {
background:
radial-gradient(circle at top left, rgba(217, 162, 140, 0.18), transparent 28%),
radial-gradient(circle at bottom right, rgba(127, 78, 63, 0.24), transparent 32%),
linear-gradient(180deg, rgba(9, 9, 12, 0.72), rgba(8, 8, 11, 0.96)),
url('assets/optimized/background.webp') center top / cover no-repeat;
}
.page-shell,
.footer-inner {
width: min(calc(100% - 2rem), var(--page-max-width));
@@ -1162,20 +1154,6 @@ hr {
backdrop-filter: none;
}
.project-entry,
.about-scroll-anim-enabled .story-copy,
.about-scroll-anim-enabled .story-detail {
opacity: 1;
transform: none;
will-change: auto;
}
.project-entry {
transition:
border-color var(--transition-fast),
background var(--transition-fast);
}
.projects-section,
.story-section,
.legal-section {
@@ -1184,6 +1162,16 @@ hr {
}
}
@media (max-width: 700px) and (hover: none) and (pointer: coarse) {
body {
background:
radial-gradient(circle at top left, rgba(217, 162, 140, 0.18), transparent 28%),
radial-gradient(circle at bottom right, rgba(127, 78, 63, 0.24), transparent 32%),
linear-gradient(180deg, rgba(9, 9, 12, 0.72), rgba(8, 8, 11, 0.96)),
url('assets/optimized/background.webp') center / cover fixed no-repeat;
}
}
@media (hover: none) and (pointer: coarse) {
.action-link:hover,
.detail-toggle:hover,