Fix: React to external URL changes and cap tag-row height in library
Clicking the Reactbin home link (or any navigation to / that removes ?page=) now resets the displayed page by subscribing to queryParamMap for post-init URL changes. Cards with many tags no longer push the pagination bar down since the tag row is clamped to one line. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,12 +8,10 @@ import { ImageService } from '../services/image.service';
|
|||||||
import { routes } from '../app.routes';
|
import { routes } from '../app.routes';
|
||||||
|
|
||||||
function makeActivatedRoute(queryParams: Record<string, string> = {}) {
|
function makeActivatedRoute(queryParams: Record<string, string> = {}) {
|
||||||
|
const paramMap = { get: (key: string) => queryParams[key] ?? null };
|
||||||
return {
|
return {
|
||||||
snapshot: {
|
snapshot: { queryParamMap: paramMap },
|
||||||
queryParamMap: {
|
queryParamMap: of(paramMap),
|
||||||
get: (key: string) => queryParams[key] ?? null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Router, RouterLink, ActivatedRoute } from '@angular/router';
|
import { Router, RouterLink, ActivatedRoute } from '@angular/router';
|
||||||
import { Subject, debounceTime, distinctUntilChanged, share, timer } from 'rxjs';
|
import { Subject, debounceTime, distinctUntilChanged, share, skip, timer } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { takeUntil } from 'rxjs/operators';
|
||||||
import { ImageRecord, ImageService } from '../services/image.service';
|
import { ImageRecord, ImageService } from '../services/image.service';
|
||||||
import { TagService } from '../services/tag.service';
|
import { TagService } from '../services/tag.service';
|
||||||
@@ -21,7 +21,7 @@ const PLACEHOLDER_SVG = `data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/s
|
|||||||
template: `
|
template: `
|
||||||
<div class="library">
|
<div class="library">
|
||||||
<header>
|
<header>
|
||||||
<h1>Reactbin</h1>
|
<h1><a class="home-link" (click)="router.navigate(['/'])">Reactbin</a></h1>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<a routerLink="/tags" class="tags-link">Browse tags</a>
|
<a routerLink="/tags" class="tags-link">Browse tags</a>
|
||||||
<button class="upload-btn" (click)="router.navigate(['/upload'])">Upload</button>
|
<button class="upload-btn" (click)="router.navigate(['/upload'])">Upload</button>
|
||||||
@@ -118,7 +118,8 @@ const PLACEHOLDER_SVG = `data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/s
|
|||||||
.image-card:hover { transform: translateY(-2px); box-shadow: 0 4px 16px rgba(0,0,0,0.4); }
|
.image-card:hover { transform: translateY(-2px); box-shadow: 0 4px 16px rgba(0,0,0,0.4); }
|
||||||
.image-card img { width: 100%; height: 160px; object-fit: cover; display: block; }
|
.image-card img { width: 100%; height: 160px; object-fit: cover; display: block; }
|
||||||
.card-skeleton { height: 200px; }
|
.card-skeleton { height: 200px; }
|
||||||
.tag-row { padding: 6px; display: flex; flex-wrap: wrap; gap: 4px; }
|
.tag-row { padding: 6px; display: flex; flex-wrap: wrap; gap: 4px; overflow: hidden; max-height: 2rem; }
|
||||||
|
.home-link { color: inherit; text-decoration: none; cursor: pointer; }
|
||||||
.empty-state { text-align: center; padding: 60px 0; color: var(--text-muted); }
|
.empty-state { text-align: center; padding: 60px 0; color: var(--text-muted); }
|
||||||
.empty-icon { display: block; font-size: 2rem; margin-bottom: 12px; }
|
.empty-icon { display: block; font-size: 2rem; margin-bottom: 12px; }
|
||||||
.upload-link { display: inline-block; margin-top: 16px; color: var(--accent); text-decoration: none; font-weight: 600; }
|
.upload-link { display: inline-block; margin-top: 16px; color: var(--accent); text-decoration: none; font-weight: 600; }
|
||||||
@@ -166,6 +167,21 @@ export class LibraryComponent implements OnInit {
|
|||||||
this.currentPage = Math.max(1, parseInt(pageParam, 10) || 1);
|
this.currentPage = Math.max(1, parseInt(pageParam, 10) || 1);
|
||||||
}
|
}
|
||||||
this.load();
|
this.load();
|
||||||
|
this.route.queryParamMap.pipe(skip(1)).subscribe((params) => {
|
||||||
|
const newPage = params.get('page') ? Math.max(1, parseInt(params.get('page')!, 10) || 1) : 1;
|
||||||
|
const newTagsParam = params.get('tags');
|
||||||
|
const newTags = newTagsParam
|
||||||
|
? newTagsParam.split(',').map((t) => t.trim()).filter((t) => t.length > 0)
|
||||||
|
: [];
|
||||||
|
const pageChanged = newPage !== this.currentPage;
|
||||||
|
const tagsChanged = JSON.stringify(newTags) !== JSON.stringify(this.activeFilters);
|
||||||
|
if (pageChanged || tagsChanged) {
|
||||||
|
this.currentPage = newPage;
|
||||||
|
this.activeFilters = newTags;
|
||||||
|
this.images = [];
|
||||||
|
this.load();
|
||||||
|
}
|
||||||
|
});
|
||||||
this.filterChange$.pipe(debounceTime(300), distinctUntilChanged()).subscribe((q) => {
|
this.filterChange$.pipe(debounceTime(300), distinctUntilChanged()).subscribe((q) => {
|
||||||
if (q) {
|
if (q) {
|
||||||
this.tagService.list(q, 10).subscribe((r) => {
|
this.tagService.list(q, 10).subscribe((r) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user