@if (isLoading()) {
@for (row of skeletonRows(); track row) {
diff --git a/libs/portal/shared/ui/src/lib/components/search-layout/search-layout.component.scss b/libs/portal/shared/ui/src/lib/components/search-layout/search-layout.component.scss
index 9d6b7b8ef..77a0de733 100644
--- a/libs/portal/shared/ui/src/lib/components/search-layout/search-layout.component.scss
+++ b/libs/portal/shared/ui/src/lib/components/search-layout/search-layout.component.scss
@@ -151,7 +151,7 @@
// Results grid mixin for consumers
::ng-deep .results-grid {
- @include grid.content-grid(140px, 20px);
+ @include grid.content-grid;
padding-bottom: 1rem;
}
diff --git a/libs/portal/shared/ui/src/lib/components/unified-collection/unified-collection-page.component.scss b/libs/portal/shared/ui/src/lib/components/unified-collection/unified-collection-page.component.scss
index 7133a4cc4..9898557b4 100644
--- a/libs/portal/shared/ui/src/lib/components/unified-collection/unified-collection-page.component.scss
+++ b/libs/portal/shared/ui/src/lib/components/unified-collection/unified-collection-page.component.scss
@@ -16,8 +16,11 @@
flex: 1;
overflow: hidden;
display: grid;
- grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
- gap: 16px;
+ grid-template-columns: repeat(
+ auto-fill,
+ minmax(var(--cover-grid-min-width, 148px), 1fr)
+ );
+ gap: var(--cover-gap, 16px);
padding: 16px;
align-content: start;
}
diff --git a/libs/portal/shared/ui/src/lib/components/unified-collection/unified-grid-tab.component.html b/libs/portal/shared/ui/src/lib/components/unified-collection/unified-grid-tab.component.html
index be6ee50a7..73b9928ef 100644
--- a/libs/portal/shared/ui/src/lib/components/unified-collection/unified-grid-tab.component.html
+++ b/libs/portal/shared/ui/src/lib/components/unified-collection/unified-grid-tab.component.html
@@ -23,6 +23,7 @@
[posterUrl]="item.posterUrl ?? ''"
[title]="item.name"
[type]="item.contentType"
+ [showTypeBadge]="false"
[date]="item.addedAt ?? item.viewedAt"
[showRemoveButton]="true"
[removeTooltip]="
diff --git a/libs/portal/shared/ui/src/lib/components/unified-collection/unified-grid-tab.component.scss b/libs/portal/shared/ui/src/lib/components/unified-collection/unified-grid-tab.component.scss
index 7cbd36c2c..f4c45795d 100644
--- a/libs/portal/shared/ui/src/lib/components/unified-collection/unified-grid-tab.component.scss
+++ b/libs/portal/shared/ui/src/lib/components/unified-collection/unified-grid-tab.component.scss
@@ -37,8 +37,11 @@
overflow-y: auto;
overflow-x: hidden;
display: grid;
- grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
- gap: 16px;
+ grid-template-columns: repeat(
+ auto-fill,
+ minmax(var(--cover-grid-min-width, 148px), 1fr)
+ );
+ gap: var(--cover-gap, 16px);
padding: 16px;
align-content: start;
}
diff --git a/libs/portal/stalker/feature/src/lib/stalker-search/stalker-search.component.scss b/libs/portal/stalker/feature/src/lib/stalker-search/stalker-search.component.scss
index 193cfc9f9..b97890404 100644
--- a/libs/portal/stalker/feature/src/lib/stalker-search/stalker-search.component.scss
+++ b/libs/portal/stalker/feature/src/lib/stalker-search/stalker-search.component.scss
@@ -15,6 +15,6 @@
}
.results-grid {
- @include grid.content-grid(140px, 20px);
+ @include grid.content-grid;
padding-bottom: 1rem;
}
diff --git a/libs/portal/xtream/feature/src/lib/recently-added/recently-added.component.scss b/libs/portal/xtream/feature/src/lib/recently-added/recently-added.component.scss
index 4788b767f..1ea7b22f6 100644
--- a/libs/portal/xtream/feature/src/lib/recently-added/recently-added.component.scss
+++ b/libs/portal/xtream/feature/src/lib/recently-added/recently-added.component.scss
@@ -27,8 +27,8 @@
// Projected card sizing lives on the caller — the rail shell can't reach
// projected children through emulated encapsulation.
.recently-added-page__rail app-content-card {
- flex: 0 0 160px;
- width: 160px;
+ flex: 0 0 var(--cover-rail-width, 160px);
+ width: var(--cover-rail-width, 160px);
scroll-snap-align: start;
}
@@ -57,8 +57,8 @@
}
.recently-added-page__skeleton-card {
- flex: 0 0 160px;
- width: 160px;
+ flex: 0 0 var(--cover-rail-width, 160px);
+ width: var(--cover-rail-width, 160px);
aspect-ratio: 2 / 3;
border-radius: 12px;
}
@@ -100,7 +100,7 @@
}
.recently-added-page__skeleton-card {
- flex: 0 0 136px;
- width: 136px;
+ flex: 0 0 min(var(--cover-rail-width, 160px), 136px);
+ width: min(var(--cover-rail-width, 160px), 136px);
}
}
diff --git a/libs/portal/xtream/feature/src/lib/search-results/search-results.component.scss b/libs/portal/xtream/feature/src/lib/search-results/search-results.component.scss
index e9c3e0eab..86e51482b 100644
--- a/libs/portal/xtream/feature/src/lib/search-results/search-results.component.scss
+++ b/libs/portal/xtream/feature/src/lib/search-results/search-results.component.scss
@@ -10,7 +10,7 @@
// Results grid styling
.results-grid {
- @include grid.content-grid(140px, 20px);
+ @include grid.content-grid;
padding-bottom: 1rem;
}
diff --git a/libs/services/src/lib/settings-store.service.ts b/libs/services/src/lib/settings-store.service.ts
index 44b655113..d912122d1 100644
--- a/libs/services/src/lib/settings-store.service.ts
+++ b/libs/services/src/lib/settings-store.service.ts
@@ -34,6 +34,7 @@ const DEFAULT_SETTINGS: Settings = {
remoteControlPort: 8765,
epgUrl: [],
downloadFolder: '',
+ coverSize: 'medium',
};
export const SettingsStore = signalStore(
@@ -88,6 +89,7 @@ export const SettingsStore = signalStore(
remoteControlPort: store.remoteControlPort(),
epgUrl: store.epgUrl(),
downloadFolder: store.downloadFolder!(),
+ coverSize: store.coverSize!(),
};
},
diff --git a/libs/shared/interfaces/src/lib/settings.interface.ts b/libs/shared/interfaces/src/lib/settings.interface.ts
index 78a74fcab..fa72e2b1d 100644
--- a/libs/shared/interfaces/src/lib/settings.interface.ts
+++ b/libs/shared/interfaces/src/lib/settings.interface.ts
@@ -18,6 +18,8 @@ export enum StartupBehavior {
RestoreLastView = 'restore-last-view',
}
+export type CoverSize = 'small' | 'medium' | 'large';
+
/**
* Describes all available settings options of the application
*/
@@ -39,4 +41,6 @@ export interface Settings {
remoteControlPort: number;
/** Custom download folder path (uses system Downloads folder if not set) */
downloadFolder?: string;
+ /** Cover/poster sizing preset applied across grids and rails */
+ coverSize?: CoverSize;
}
diff --git a/libs/ui/styles/_content-grid.scss b/libs/ui/styles/_content-grid.scss
index e8237fee9..b0f9b3a8f 100644
--- a/libs/ui/styles/_content-grid.scss
+++ b/libs/ui/styles/_content-grid.scss
@@ -5,9 +5,12 @@
// @include grid.content-grid;
// @include grid.content-card;
-@mixin content-grid($min-width: 140px, $gap: 20px) {
+@mixin content-grid(
+ $min-width: var(--cover-grid-min-width, 148px),
+ $gap: var(--cover-gap, 16px)
+) {
display: grid;
- grid-template-columns: repeat(auto-fill, minmax($min-width, 1fr));
+ grid-template-columns: repeat(auto-fill, minmax(#{$min-width}, 1fr));
gap: $gap;
}
diff --git a/libs/workspace/dashboard/feature/src/lib/rails/dashboard-rail.component.scss b/libs/workspace/dashboard/feature/src/lib/rails/dashboard-rail.component.scss
index 87a3ae9b5..07a073318 100644
--- a/libs/workspace/dashboard/feature/src/lib/rails/dashboard-rail.component.scss
+++ b/libs/workspace/dashboard/feature/src/lib/rails/dashboard-rail.component.scss
@@ -1,7 +1,7 @@
:host {
display: block;
- --rail-card-width: 172px;
- --rail-gap: 14px;
+ --rail-card-width: var(--cover-rail-width, 172px);
+ --rail-gap: var(--cover-gap, 14px);
--rail-radius: 12px;
}
@@ -444,6 +444,6 @@
@media (max-width: 720px) {
:host {
- --rail-card-width: 140px;
+ --rail-card-width: min(var(--cover-rail-width, 172px), 140px);
}
}
diff --git a/libs/workspace/dashboard/feature/src/lib/rails/workspace-dashboard-rails.component.scss b/libs/workspace/dashboard/feature/src/lib/rails/workspace-dashboard-rails.component.scss
index a7f1f8645..7ba9317e0 100644
--- a/libs/workspace/dashboard/feature/src/lib/rails/workspace-dashboard-rails.component.scss
+++ b/libs/workspace/dashboard/feature/src/lib/rails/workspace-dashboard-rails.component.scss
@@ -417,18 +417,17 @@
.rails-page__skeleton-track {
display: flex;
- gap: 14px;
+ gap: var(--cover-gap, 14px);
padding: 4px 0 16px;
overflow: hidden;
}
.rails-page__skeleton-card {
@extend %skeleton-shimmer;
- // Matches the real .rail__card width (--rail-card-width: 172px) and
- // .rail__art aspect-ratio 2/3, so when cards arrive the geometry is
- // identical and there's no layout shift.
- flex: 0 0 172px;
- width: 172px;
+ // Mirrors the real .rail__card width (--cover-rail-width) so geometry
+ // matches when cards arrive — no layout shift.
+ flex: 0 0 var(--cover-rail-width, 172px);
+ width: var(--cover-rail-width, 172px);
aspect-ratio: 2 / 3;
border-radius: 12px;
}
@@ -474,8 +473,8 @@
}
.rails-page__skeleton-card {
- flex: 0 0 140px;
- width: 140px;
+ flex: 0 0 min(var(--cover-rail-width, 172px), 140px);
+ width: min(var(--cover-rail-width, 172px), 140px);
}
.hero__title {