fix scroll position
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
import {ChangeDetectionStrategy, Component, OnInit, inject} from '@angular/core';
|
import {ChangeDetectionStrategy, Component, OnInit} from '@angular/core';
|
||||||
import {fader} from './animations';
|
import {fader} from './animations';
|
||||||
import {ScrollService} from './services/scroll.service';
|
|
||||||
import {register} from 'swiper/element/bundle';
|
import {register} from 'swiper/element/bundle';
|
||||||
import {RouterOutlet} from '@angular/router';
|
import {RouterOutlet} from '@angular/router';
|
||||||
import {NavigationComponent} from './widget-modules/components/application-frame/navigation/navigation.component';
|
import {NavigationComponent} from './widget-modules/components/application-frame/navigation/navigation.component';
|
||||||
@@ -14,8 +13,6 @@ import {NavigationComponent} from './widget-modules/components/application-frame
|
|||||||
imports: [RouterOutlet, NavigationComponent],
|
imports: [RouterOutlet, NavigationComponent],
|
||||||
})
|
})
|
||||||
export class AppComponent implements OnInit {
|
export class AppComponent implements OnInit {
|
||||||
private scrollService = inject(ScrollService);
|
|
||||||
|
|
||||||
public constructor() {
|
public constructor() {
|
||||||
register();
|
register();
|
||||||
}
|
}
|
||||||
@@ -24,8 +21,4 @@ export class AppComponent implements OnInit {
|
|||||||
setTimeout(() => document.querySelector('#load-bg')?.classList.add('hidden'), 1000);
|
setTimeout(() => document.querySelector('#load-bg')?.classList.add('hidden'), 1000);
|
||||||
setTimeout(() => document.querySelector('#load-bg')?.remove(), 5000);
|
setTimeout(() => document.querySelector('#load-bg')?.remove(), 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public onScoll($event: {srcElement: {scrollTop: number}}): void {
|
|
||||||
this.scrollService.saveScrollPosition($event.srcElement.scrollTop);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,13 +11,20 @@ export class SongDataService {
|
|||||||
private dbService = inject(DbService);
|
private dbService = inject(DbService);
|
||||||
|
|
||||||
private collection = 'songs';
|
private collection = 'songs';
|
||||||
public list$: Observable<Song[]> = this.dbService.col$<Song>(this.collection).pipe(
|
private loadedList$: Observable<Song[]> = this.dbService.col$<Song>(this.collection).pipe(
|
||||||
|
shareReplay({
|
||||||
|
bufferSize: 1,
|
||||||
|
refCount: false, // keep the listener alive after first subscription to avoid reloading on navigation
|
||||||
|
})
|
||||||
|
);
|
||||||
|
public list$: Observable<Song[]> = this.loadedList$.pipe(
|
||||||
startWith([] as Song[]), // immediate empty emit keeps UI responsive while first snapshot arrives
|
startWith([] as Song[]), // immediate empty emit keeps UI responsive while first snapshot arrives
|
||||||
shareReplay({
|
shareReplay({
|
||||||
bufferSize: 1,
|
bufferSize: 1,
|
||||||
refCount: false, // keep the listener alive after first subscription to avoid reloading on navigation
|
refCount: false, // keep the listener alive after first subscription to avoid reloading on navigation
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
public listLoaded$ = (): Observable<Song[]> => this.loadedList$;
|
||||||
|
|
||||||
public read$ = (songId: string): Observable<Song | null> => this.dbService.doc$(this.collection + '/' + songId);
|
public read$ = (songId: string): Observable<Song | null> => this.dbService.doc$(this.collection + '/' + songId);
|
||||||
public update$ = async (songId: string, data: Partial<Song>): Promise<void> => await this.dbService.doc(this.collection + '/' + songId).update(data);
|
public update$ = async (songId: string, data: Partial<Song>): Promise<void> => await this.dbService.doc(this.collection + '/' + songId).update(data);
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ export class SongListResolver {
|
|||||||
private songService = inject(SongService);
|
private songService = inject(SongService);
|
||||||
|
|
||||||
public resolve(): Observable<Song[]> {
|
public resolve(): Observable<Song[]> {
|
||||||
return this.songService.list$().pipe(take(1));
|
return this.songService.listLoaded$().pipe(take(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export class SongService {
|
|||||||
public static LEGAL_TYPE: SongLegalType[] = ['open', 'allowed'];
|
public static LEGAL_TYPE: SongLegalType[] = ['open', 'allowed'];
|
||||||
|
|
||||||
public list$ = (): Observable<Song[]> => this.songDataService.list$; //.pipe(tap(_ => (this.list = _)));
|
public list$ = (): Observable<Song[]> => this.songDataService.list$; //.pipe(tap(_ => (this.list = _)));
|
||||||
|
public listLoaded$ = (): Observable<Song[]> => this.songDataService.listLoaded$();
|
||||||
public read$ = (songId: string): Observable<Song | null> => this.songDataService.read$(songId);
|
public read$ = (songId: string): Observable<Song | null> => this.songDataService.read$(songId);
|
||||||
public read = (songId: string): Promise<Song | null> => firstValueFrom(this.read$(songId));
|
public read = (songId: string): Promise<Song | null> => firstValueFrom(this.read$(songId));
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import {ChangeDetectionStrategy, Component, OnDestroy, OnInit, inject} from '@angular/core';
|
import {ChangeDetectionStrategy, Component, inject} from '@angular/core';
|
||||||
import {SongService} from '../services/song.service';
|
|
||||||
import {Song} from '../services/song';
|
import {Song} from '../services/song';
|
||||||
import {map} from 'rxjs/operators';
|
import {map} from 'rxjs/operators';
|
||||||
import {combineLatest, Observable} from 'rxjs';
|
import {combineLatest, Observable} from 'rxjs';
|
||||||
import {fade} from '../../../animations';
|
import {fade} from '../../../animations';
|
||||||
import {RouterLink} from '@angular/router';
|
import {ActivatedRoute, RouterLink} from '@angular/router';
|
||||||
import {filterSong} from '../../../services/filter.helper';
|
import {filterSong} from '../../../services/filter.helper';
|
||||||
import {FilterValues} from './filter/filter-values';
|
import {FilterValues} from './filter/filter-values';
|
||||||
import {ScrollService} from '../../../services/scroll.service';
|
|
||||||
import {faBalanceScaleRight, faCheck, faPencilRuler} from '@fortawesome/free-solid-svg-icons';
|
import {faBalanceScaleRight, faCheck, faPencilRuler} from '@fortawesome/free-solid-svg-icons';
|
||||||
import {TextRenderingService} from '../services/text-rendering.service';
|
import {TextRenderingService} from '../services/text-rendering.service';
|
||||||
import {FilterStoreService} from '../../../services/filter-store.service';
|
import {FilterStoreService} from '../../../services/filter-store.service';
|
||||||
@@ -30,16 +28,15 @@ interface SongListItem extends Song {
|
|||||||
animations: [fade],
|
animations: [fade],
|
||||||
imports: [ListHeaderComponent, FilterComponent, CardComponent, RouterLink, RoleDirective, FaIconComponent, AsyncPipe],
|
imports: [ListHeaderComponent, FilterComponent, CardComponent, RouterLink, RoleDirective, FaIconComponent, AsyncPipe],
|
||||||
})
|
})
|
||||||
export class SongListComponent implements OnInit, OnDestroy {
|
export class SongListComponent {
|
||||||
private songService = inject(SongService);
|
private route = inject(ActivatedRoute);
|
||||||
private scrollService = inject(ScrollService);
|
|
||||||
private textRenderingService = inject(TextRenderingService);
|
private textRenderingService = inject(TextRenderingService);
|
||||||
private filterStore = inject(FilterStoreService);
|
private filterStore = inject(FilterStoreService);
|
||||||
|
|
||||||
public anyFilterActive = false;
|
public anyFilterActive = false;
|
||||||
public songs$: Observable<SongListItem[]> = combineLatest([
|
public songs$: Observable<SongListItem[]> = combineLatest([
|
||||||
this.filterStore.songFilter$,
|
this.filterStore.songFilter$,
|
||||||
this.songService.list$().pipe(map(songs => [...songs].sort((a, b) => a.number - b.number))),
|
this.route.data.pipe(map(data => (data['songs'] as Song[]).slice().sort((a, b) => a.number - b.number))),
|
||||||
]).pipe(
|
]).pipe(
|
||||||
map(([filter, songs]) => {
|
map(([filter, songs]) => {
|
||||||
this.anyFilterActive = this.checkIfFilterActive(filter);
|
this.anyFilterActive = this.checkIfFilterActive(filter);
|
||||||
@@ -56,15 +53,6 @@ export class SongListComponent implements OnInit, OnDestroy {
|
|||||||
public faDraft = faPencilRuler;
|
public faDraft = faPencilRuler;
|
||||||
public faFinal = faCheck;
|
public faFinal = faCheck;
|
||||||
|
|
||||||
public ngOnInit(): void {
|
|
||||||
setTimeout(() => this.scrollService.restoreScrollPositionFor('songlist'), 100);
|
|
||||||
setTimeout(() => this.scrollService.restoreScrollPositionFor('songlist'), 300);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ngOnDestroy(): void {
|
|
||||||
this.scrollService.storeScrollPositionFor('songlist');
|
|
||||||
}
|
|
||||||
|
|
||||||
public trackBy = (index: number, show: SongListItem) => show.id;
|
public trackBy = (index: number, show: SongListItem) => show.id;
|
||||||
|
|
||||||
private filter(song: Song, filter: FilterValues): boolean {
|
private filter(song: Song, filter: FilterValues): boolean {
|
||||||
|
|||||||
@@ -5,12 +5,16 @@ import {SongListComponent} from './song-list/song-list.component';
|
|||||||
import {EditComponent} from './song/edit/edit.component';
|
import {EditComponent} from './song/edit/edit.component';
|
||||||
import {NewComponent} from './song/new/new.component';
|
import {NewComponent} from './song/new/new.component';
|
||||||
import {EditSongGuard} from './song/edit/edit-song.guard';
|
import {EditSongGuard} from './song/edit/edit-song.guard';
|
||||||
|
import {SongListResolver} from './services/song-list.resolver';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: SongListComponent,
|
component: SongListComponent,
|
||||||
pathMatch: 'full',
|
pathMatch: 'full',
|
||||||
|
resolve: {
|
||||||
|
songs: SongListResolver,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'new',
|
path: 'new',
|
||||||
|
|||||||
@@ -37,8 +37,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: auto;
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@@ -46,9 +45,15 @@ body {
|
|||||||
font-family: Roboto, "Helvetica Neue", sans-serif;
|
font-family: Roboto, "Helvetica Neue", sans-serif;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
body::before {
|
||||||
|
content: '';
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
background: linear-gradient(39deg, var(--bg-deep), var(--bg-mid), var(--bg-soft));
|
background: linear-gradient(39deg, var(--bg-deep), var(--bg-mid), var(--bg-soft));
|
||||||
overflow: auto;
|
z-index: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
@@ -103,10 +108,6 @@ body .cdk-overlay-transparent-backdrop.cdk-overlay-backdrop-showing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body {
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: Roboto, "Helvetica Neue", sans-serif;
|
font-family: Roboto, "Helvetica Neue", sans-serif;
|
||||||
|
|||||||
Reference in New Issue
Block a user