first commit

This commit is contained in:
2025-09-14 23:05:30 -04:00
commit 2866d74b32
122 changed files with 95474 additions and 0 deletions
@@ -0,0 +1,5 @@
<div #sentinel class="w-full h-10 flex items-center justify-center">
<div class="text-slate-400 text-sm" aria-live="polite">
<!-- The parent can show a spinner near the bottom; this anchor is the sentinel only. -->
</div>
</div>
@@ -0,0 +1,42 @@
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, OnDestroy, Output, ViewChild } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-infinite-anchor',
standalone: true,
templateUrl: './infinite-anchor.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule]
})
export class InfiniteAnchorComponent implements AfterViewInit, OnDestroy {
@ViewChild('sentinel', { static: true }) sentinelRef!: ElementRef<HTMLDivElement>;
@Input() disabled = false;
@Input() busy = false;
@Input() rootMargin = '300px 0px 300px 0px';
@Input() threshold: number | number[] = 0.01;
@Output() loadMore = new EventEmitter<void>();
private observer?: IntersectionObserver;
ngAfterViewInit(): void {
this.observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (entry.isIntersecting && !this.disabled && !this.busy) {
this.loadMore.emit();
}
}
}, {
root: null,
rootMargin: this.rootMargin,
threshold: this.threshold,
});
this.observer.observe(this.sentinelRef.nativeElement);
}
ngOnDestroy(): void {
this.observer?.disconnect();
}
}