From db6d21899da139933c687b2d74bbab5228e6822d Mon Sep 17 00:00:00 2001 From: fleizean <66090171+fleizean@users.noreply.github.com> Date: Mon, 19 Oct 2026 19:40:02 +0300 Subject: [PATCH] fix(blog): show a window of page links instead of every page Co-Authored-By: Claude Opus 5.5 (1M context) --- .../features/blog/blog-list/blog-list.html | 28 +++++++++++++++---- .../app/features/blog/blog-list/blog-list.ts | 23 +++++++++++++-- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/frontend/src/app/features/blog/blog-list/blog-list.html b/src/frontend/src/app/features/blog/blog-list/blog-list.html index d0c3087..ea5b752 100644 --- a/src/frontend/src/app/features/blog/blog-list/blog-list.html +++ b/src/frontend/src/app/features/blog/blog-list/blog-list.html @@ -84,14 +84,32 @@

No articles ye @if (totalPages() > 1) { diff --git a/src/frontend/src/app/features/blog/blog-list/blog-list.ts b/src/frontend/src/app/features/blog/blog-list/blog-list.ts index 9292eb2..f047047 100644 --- a/src/frontend/src/app/features/blog/blog-list/blog-list.ts +++ b/src/frontend/src/app/features/blog/blog-list/blog-list.ts @@ -3,7 +3,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { DatePipe } from '@angular/common'; import { ActivatedRoute, RouterLink } from '@angular/router'; import { Subject, catchError, distinctUntilChanged, map, of, startWith, switchMap, tap } from 'rxjs'; -import { LucideAngularModule, BookOpen, AlertCircle } from 'lucide-angular'; +import { LucideAngularModule, BookOpen, AlertCircle, ChevronLeft, ChevronRight } from 'lucide-angular'; import { ApiService } from '../../../core/services/api'; import { SeoService } from '../../../core/services/seo.service'; import { BlogPostSnippet } from '../../../core/models/blog.models'; @@ -13,7 +13,24 @@ import { stripMarkdown } from '../../../core/utils/markdown.utils'; type PageState = 'loading' | 'loaded' | 'error'; type Loaded = { page: PaginatedResult } | { failure: unknown }; +type PageLink = { kind: 'page'; page: number } | { kind: 'gap'; key: string }; + const PAGE_SIZE = 10; +const SIBLINGS = 1; + +function pageWindow(current: number, total: number): PageLink[] { + let start = Math.max(2, current - SIBLINGS); + let end = Math.min(total - 1, current + SIBLINGS); + if (start === 3) start = 2; + if (end === total - 2) end = total - 1; + + const links: PageLink[] = [{ kind: 'page', page: 1 }]; + if (start > 2) links.push({ kind: 'gap', key: 'gap-start' }); + for (let page = start; page <= end; page++) links.push({ kind: 'page', page }); + if (end < total - 1) links.push({ kind: 'gap', key: 'gap-end' }); + if (total > 1) links.push({ kind: 'page', page: total }); + return links; +} @Component({ selector: 'app-blog-list', @@ -29,6 +46,8 @@ export class BlogListComponent { readonly BookOpenIcon = BookOpen; readonly AlertIcon = AlertCircle; + readonly PrevIcon = ChevronLeft; + readonly NextIcon = ChevronRight; readonly skeletonRows = [1, 2, 3]; readonly stripMarkdown = stripMarkdown; @@ -36,7 +55,7 @@ export class BlogListComponent { state = signal('loading'); currentPage = signal(1); totalPages = signal(0); - pages = computed(() => Array.from({ length: this.totalPages() }, (_, index) => index + 1)); + pages = computed(() => pageWindow(this.currentPage(), this.totalPages())); private reload$ = new Subject();