- @if (!xtreamStore.selectedItem()) { + @if (!xtreamStore.selectedItem() && !xtreamStore.isLoadingDetails()) {

- - -
- - -
- - -
- -
- @if (posterUrl) { - Poster + +
+ - } @else { -
No Poster
- } +
+ + +
+ + + + +
+ +
+ + + + + +
+ +
+ + +
+ +
+
+ } @else { + +
- -
-

{{ title }}

+ +
- -
- + +
+ +
+ @if (posterUrl) { + Poster + } @else { +
No Poster
+ }
- - @if (description) { -

- {{ description }} -

- } + +
+

{{ title }}

- -
- + +
+ +
+ + + @if (description) { +

+ {{ description }} +

+ } + + +
+ +
+ + +
+ +
+ + +
- - -
- -
- - -
-
- + } + \ No newline at end of file diff --git a/libs/ui/components/src/lib/content-hero/content-hero.component.scss b/libs/ui/components/src/lib/content-hero/content-hero.component.scss index fbe107b5d..d1fe1cb28 100644 --- a/libs/ui/components/src/lib/content-hero/content-hero.component.scss +++ b/libs/ui/components/src/lib/content-hero/content-hero.component.scss @@ -471,3 +471,30 @@ .hero__content { animation: fadeInUp 0.6s ease-out 0.2s both; } + +// Skeleton Loader Overrides +ngx-skeleton-loader { + display: block; + width: 100%; + + // Ensure the loader inside poster takes up the correct aspect ratio space + ::ng-deep .loader { + display: block; + height: 100%; + } +} + +:host-context(.dark-theme) { + ngx-skeleton-loader { + ::ng-deep .loader { + background-color: rgba(255, 255, 255, 0.1); + } + } +} + +.poster { + // ... existing styles ... + // Ensure poster container has height/ratio for skeleton + min-height: 330px; // Fallback + aspect-ratio: 2 / 3; +} diff --git a/libs/ui/components/src/lib/content-hero/content-hero.component.ts b/libs/ui/components/src/lib/content-hero/content-hero.component.ts index 36bad6e15..2dcfff209 100644 --- a/libs/ui/components/src/lib/content-hero/content-hero.component.ts +++ b/libs/ui/components/src/lib/content-hero/content-hero.component.ts @@ -2,11 +2,17 @@ import { CommonModule } from '@angular/common'; import { Component, EventEmitter, Input, Output } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; +import { NgxSkeletonLoaderComponent } from 'ngx-skeleton-loader'; @Component({ selector: 'app-content-hero', standalone: true, - imports: [CommonModule, MatIconModule, MatButtonModule], + imports: [ + CommonModule, + MatIconModule, + MatButtonModule, + NgxSkeletonLoaderComponent, + ], templateUrl: './content-hero.component.html', styleUrls: ['./content-hero.component.scss'], }) @@ -15,6 +21,7 @@ export class ContentHeroComponent { @Input() description: string | undefined; @Input() posterUrl: string | undefined; @Input() backdropUrl: string | undefined; + @Input() isLoading = false; @Output() backClicked = new EventEmitter(); diff --git a/libs/ui/components/src/lib/recent-playlists/recent-playlists.component.ts b/libs/ui/components/src/lib/recent-playlists/recent-playlists.component.ts index b291f3b87..73e16ce99 100644 --- a/libs/ui/components/src/lib/recent-playlists/recent-playlists.component.ts +++ b/libs/ui/components/src/lib/recent-playlists/recent-playlists.component.ts @@ -222,11 +222,14 @@ export class RecentPlaylistsComponent { onConfirm: async () => { try { // Delete all content and categories for this playlist - // This returns the xtreamIds of favorites and recently viewed items - const { favoritedXtreamIds, recentlyViewedXtreamIds } = - await this.databaseService.deleteXtreamPlaylistContent( - item._id - ); + // This returns the xtreamIds of favorites, recently viewed items, and hidden categories + const { + favoritedXtreamIds, + recentlyViewedXtreamIds, + hiddenCategories, + } = await this.databaseService.deleteXtreamPlaylistContent( + item._id + ); const updateDate = Date.now(); @@ -250,6 +253,7 @@ export class RecentPlaylistsComponent { JSON.stringify({ favoritedXtreamIds, recentlyViewedXtreamIds, + hiddenCategories, }) );