mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-10 18:36:15 -08:00
refactor(dashboard): split recently-watched into VOD and live rails
Per UX audit: a single "Recently Watched" rail mixed channels and VOD
into a grid where the two card formats fought for visual attention.
Split it into two rails — "Continue watching" (movies/series) and
"Live now on your favorites" (live channels) — so each surface uses
the card format that fits its content type.
Also relabel the rail header link from "Manage all" to "See all {N}"
when the total count exceeds what's rendered, so the user knows how
many items the link expands into; falls back to "See all" otherwise.
i18n: three new keys (LIVE_RECENT, SEE_ALL, SEE_ALL_COUNT) translated
across all 17 locales by per-locale agents reusing each file's existing
glossary; placeholder integrity verified.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
a27a29fcf2
commit
a048c18763
23 files changed
+187
-12
No files matched your search
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "ترتيب الفئات",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "متابعة المشاهدة",
|
||||
"LIVE_RECENT": "يُبث الآن على المفضلة لديك",
|
||||
"UNTITLED_SOURCE": "مصدر بدون عنوان",
|
||||
"GLOBAL_FAVORITES": "المفضلة العامة",
|
||||
"REMOVE_FROM_HISTORY": "إزالة من السجل",
|
||||
"RECENT_SOURCES": "المصادر المستخدمة مؤخرًا",
|
||||
"MANAGE_ALL": "إدارة الكل",
|
||||
"SEE_ALL": "عرض الكل",
|
||||
"SEE_ALL_COUNT": "عرض الكل ({{count}})",
|
||||
"RECENTLY_WATCHED": "ما تمت مشاهدته مؤخرًا",
|
||||
"XTREAM_RECENTLY_ADDED": "أُضيفت مؤخرًا على Xtream",
|
||||
"NO_HISTORY": "لم يتم العثور على عناصر لهذا الفلتر.",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "ترتيب التصنيفات",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "كمل المشاهدة",
|
||||
"LIVE_RECENT": "مباشر دابا على المفضلة ديالك",
|
||||
"UNTITLED_SOURCE": "مصدر بلا عنوان",
|
||||
"GLOBAL_FAVORITES": "المفضلة العامة",
|
||||
"REMOVE_FROM_HISTORY": "حيد من السجل",
|
||||
"RECENT_SOURCES": "المصادر المستعملة مؤخراً",
|
||||
"MANAGE_ALL": "تدبير الكل",
|
||||
"SEE_ALL": "شوف الكل",
|
||||
"SEE_ALL_COUNT": "شوف الكل ({{count}})",
|
||||
"RECENTLY_WATCHED": "متشافين مؤخراً",
|
||||
"XTREAM_RECENTLY_ADDED": "تزادو مؤخراً على Xtream",
|
||||
"NO_HISTORY": "ما تلقاو حتى عناصر لهاد الفلتر.",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "Сартаваць катэгорыі",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "Працягнуць прагляд",
|
||||
"LIVE_RECENT": "Цяпер у эфіры на выбраных",
|
||||
"UNTITLED_SOURCE": "Крыніца без назвы",
|
||||
"GLOBAL_FAVORITES": "Усе фаварыты",
|
||||
"REMOVE_FROM_HISTORY": "Выдаліць з гісторыі",
|
||||
"RECENT_SOURCES": "Нядаўна выкарыстаныя крыніцы",
|
||||
"MANAGE_ALL": "Кіраваць усімі",
|
||||
"SEE_ALL": "Паказаць усё",
|
||||
"SEE_ALL_COUNT": "Паказаць усё ({{count}})",
|
||||
"RECENTLY_WATCHED": "Нядаўна прагледжаныя",
|
||||
"XTREAM_RECENTLY_ADDED": "Нядаўна дададзеныя на Xtream",
|
||||
"NO_HISTORY": "Не знойдзена элементаў для гэтага фільтра.",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "Kategorien sortieren",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "Weiter schauen",
|
||||
"LIVE_RECENT": "Jetzt live auf Ihren Favoriten",
|
||||
"UNTITLED_SOURCE": "Unbenannte Quelle",
|
||||
"GLOBAL_FAVORITES": "Globale Favoriten",
|
||||
"REMOVE_FROM_HISTORY": "Aus Verlauf entfernen",
|
||||
"RECENT_SOURCES": "Zuletzt verwendete Quellen",
|
||||
"MANAGE_ALL": "Alle verwalten",
|
||||
"SEE_ALL": "Alle anzeigen",
|
||||
"SEE_ALL_COUNT": "Alle {{count}} anzeigen",
|
||||
"RECENTLY_WATCHED": "Zuletzt angesehen",
|
||||
"XTREAM_RECENTLY_ADDED": "Neu auf Xtream",
|
||||
"NO_HISTORY": "Keine Elemente für diesen Filter gefunden.",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "Ταξινόμηση κατηγοριών",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "Συνέχιση παρακολούθησης",
|
||||
"LIVE_RECENT": "Ζωντανά τώρα στα αγαπημένα σας",
|
||||
"UNTITLED_SOURCE": "Πηγή χωρίς τίτλο",
|
||||
"GLOBAL_FAVORITES": "Βασικά Αγαπημένα",
|
||||
"REMOVE_FROM_HISTORY": "Αφαίρεση από το ιστορικό",
|
||||
"RECENT_SOURCES": "Πρόσφατα χρησιμοποιημένες πηγές",
|
||||
"MANAGE_ALL": "Διαχείριση όλων",
|
||||
"SEE_ALL": "Δείτε όλα",
|
||||
"SEE_ALL_COUNT": "Δείτε όλα {{count}}",
|
||||
"RECENTLY_WATCHED": "Πρόσφατα προβληθέντα",
|
||||
"XTREAM_RECENTLY_ADDED": "Πρόσφατα προστέθηκαν στο Xtream",
|
||||
"NO_HISTORY": "Δεν βρέθηκαν στοιχεία για αυτό το φίλτρο.",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "Sort categories",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "Continue Watching",
|
||||
"LIVE_RECENT": "Live now on your favorites",
|
||||
"UNTITLED_SOURCE": "Untitled source",
|
||||
"GLOBAL_FAVORITES": "Global Favorites",
|
||||
"REMOVE_FROM_HISTORY": "Remove from history",
|
||||
"RECENT_SOURCES": "Recently Used Sources",
|
||||
"MANAGE_ALL": "Manage all",
|
||||
"SEE_ALL": "See all",
|
||||
"SEE_ALL_COUNT": "See all {{count}}",
|
||||
"RECENTLY_WATCHED": "Recently Watched",
|
||||
"XTREAM_RECENTLY_ADDED": "Recently Added on Xtream",
|
||||
"NO_HISTORY": "No items found for this filter.",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "Ordenar categorías",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "Continuar viendo",
|
||||
"LIVE_RECENT": "Ahora en vivo en tus favoritos",
|
||||
"UNTITLED_SOURCE": "Fuente sin título",
|
||||
"GLOBAL_FAVORITES": "Favoritos globales",
|
||||
"REMOVE_FROM_HISTORY": "Quitar del historial",
|
||||
"RECENT_SOURCES": "Fuentes usadas recientemente",
|
||||
"MANAGE_ALL": "Gestionar todo",
|
||||
"SEE_ALL": "Ver todo",
|
||||
"SEE_ALL_COUNT": "Ver todos ({{count}})",
|
||||
"RECENTLY_WATCHED": "Vistos recientemente",
|
||||
"XTREAM_RECENTLY_ADDED": "Añadidos recientemente en Xtream",
|
||||
"NO_HISTORY": "No se encontraron elementos para este filtro.",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "Trier les catégories",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "Reprendre la lecture",
|
||||
"LIVE_RECENT": "En direct sur vos favoris",
|
||||
"UNTITLED_SOURCE": "Source sans titre",
|
||||
"GLOBAL_FAVORITES": "Favoris globaux",
|
||||
"REMOVE_FROM_HISTORY": "Retirer de l'historique",
|
||||
"RECENT_SOURCES": "Sources récemment utilisées",
|
||||
"MANAGE_ALL": "Tout gérer",
|
||||
"SEE_ALL": "Voir tout",
|
||||
"SEE_ALL_COUNT": "Voir les {{count}}",
|
||||
"RECENTLY_WATCHED": "Récemment regardés",
|
||||
"XTREAM_RECENTLY_ADDED": "Récemment ajoutés sur Xtream",
|
||||
"NO_HISTORY": "Aucun élément trouvé pour ce filtre.",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "Ordina categorie",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "Continua a guardare",
|
||||
"LIVE_RECENT": "Live ora sui tuoi preferiti",
|
||||
"UNTITLED_SOURCE": "Sorgente senza titolo",
|
||||
"GLOBAL_FAVORITES": "Preferiti globali",
|
||||
"REMOVE_FROM_HISTORY": "Rimuovi dalla cronologia",
|
||||
"RECENT_SOURCES": "Sorgenti usate di recente",
|
||||
"MANAGE_ALL": "Gestisci tutto",
|
||||
"SEE_ALL": "Vedi tutto",
|
||||
"SEE_ALL_COUNT": "Vedi tutti ({{count}})",
|
||||
"RECENTLY_WATCHED": "Visti di recente",
|
||||
"XTREAM_RECENTLY_ADDED": "Aggiunti di recente su Xtream",
|
||||
"NO_HISTORY": "Nessun elemento corrisponde a questo filtro.",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "カテゴリを並び替え",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "視聴を再開",
|
||||
"LIVE_RECENT": "お気に入りで現在放送中",
|
||||
"UNTITLED_SOURCE": "無題のソース",
|
||||
"GLOBAL_FAVORITES": "グローバルお気に入り",
|
||||
"REMOVE_FROM_HISTORY": "履歴から削除",
|
||||
"RECENT_SOURCES": "最近使用したソース",
|
||||
"MANAGE_ALL": "すべて管理",
|
||||
"SEE_ALL": "すべて表示",
|
||||
"SEE_ALL_COUNT": "すべて表示 ({{count}})",
|
||||
"RECENTLY_WATCHED": "最近視聴した項目",
|
||||
"XTREAM_RECENTLY_ADDED": "Xtreamに最近追加された項目",
|
||||
"NO_HISTORY": "このフィルターに該当する項目はありません。",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "카테고리 정렬",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "이어서 시청",
|
||||
"LIVE_RECENT": "즐겨찾기에서 지금 라이브 중인 채널입니다",
|
||||
"UNTITLED_SOURCE": "제목 없는 소스",
|
||||
"GLOBAL_FAVORITES": "전체 즐겨찾기",
|
||||
"REMOVE_FROM_HISTORY": "기록에서 제거",
|
||||
"RECENT_SOURCES": "최근에 사용한 소스",
|
||||
"MANAGE_ALL": "모두 관리",
|
||||
"SEE_ALL": "모두 보기",
|
||||
"SEE_ALL_COUNT": "{{count}}개 모두 보기",
|
||||
"RECENTLY_WATCHED": "최근에 시청한 항목",
|
||||
"XTREAM_RECENTLY_ADDED": "Xtream에 최근 추가됨",
|
||||
"NO_HISTORY": "이 필터에 해당하는 항목이 없습니다.",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "Categorieën sorteren",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "Verder kijken",
|
||||
"LIVE_RECENT": "Nu live op je favorieten",
|
||||
"UNTITLED_SOURCE": "Naamloze bron",
|
||||
"GLOBAL_FAVORITES": "Algemene favorieten",
|
||||
"REMOVE_FROM_HISTORY": "Verwijderen uit geschiedenis",
|
||||
"RECENT_SOURCES": "Recent gebruikte bronnen",
|
||||
"MANAGE_ALL": "Alles beheren",
|
||||
"SEE_ALL": "Alles bekijken",
|
||||
"SEE_ALL_COUNT": "Alle {{count}} bekijken",
|
||||
"RECENTLY_WATCHED": "Recent bekeken",
|
||||
"XTREAM_RECENTLY_ADDED": "Recent toegevoegd op Xtream",
|
||||
"NO_HISTORY": "Geen items gevonden voor dit filter.",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "Sortuj kategorie",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "Kontynuuj oglądanie",
|
||||
"LIVE_RECENT": "Na żywo w Twoich ulubionych",
|
||||
"UNTITLED_SOURCE": "Źródło bez tytułu",
|
||||
"GLOBAL_FAVORITES": "Globalne ulubione",
|
||||
"REMOVE_FROM_HISTORY": "Usuń z historii",
|
||||
"RECENT_SOURCES": "Ostatnio używane źródła",
|
||||
"MANAGE_ALL": "Zarządzaj wszystkimi",
|
||||
"SEE_ALL": "Zobacz wszystkie",
|
||||
"SEE_ALL_COUNT": "Zobacz wszystkie ({{count}})",
|
||||
"RECENTLY_WATCHED": "Ostatnio oglądane",
|
||||
"XTREAM_RECENTLY_ADDED": "Ostatnio dodane w Xtream",
|
||||
"NO_HISTORY": "Brak elementów dla tego filtra.",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "Ordenar categorias",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "Continuar assistindo",
|
||||
"LIVE_RECENT": "Ao vivo agora nos seus favoritos",
|
||||
"UNTITLED_SOURCE": "Fonte sem título",
|
||||
"GLOBAL_FAVORITES": "Favoritos globais",
|
||||
"REMOVE_FROM_HISTORY": "Remover do histórico",
|
||||
"RECENT_SOURCES": "Fontes usadas recentemente",
|
||||
"MANAGE_ALL": "Gerenciar tudo",
|
||||
"SEE_ALL": "Ver todos",
|
||||
"SEE_ALL_COUNT": "Ver todos ({{count}})",
|
||||
"RECENTLY_WATCHED": "Assistidos recentemente",
|
||||
"XTREAM_RECENTLY_ADDED": "Adicionados recentemente no Xtream",
|
||||
"NO_HISTORY": "Nenhum item encontrado para este filtro.",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "Сортировать категории",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "Продолжить просмотр",
|
||||
"LIVE_RECENT": "Сейчас в эфире на избранных каналах",
|
||||
"UNTITLED_SOURCE": "Источник без названия",
|
||||
"GLOBAL_FAVORITES": "Глобальные избранные",
|
||||
"REMOVE_FROM_HISTORY": "Удалить из истории",
|
||||
"RECENT_SOURCES": "Недавно использованные источники",
|
||||
"MANAGE_ALL": "Управлять всем",
|
||||
"SEE_ALL": "Смотреть все",
|
||||
"SEE_ALL_COUNT": "Смотреть все {{count}}",
|
||||
"RECENTLY_WATCHED": "Недавно просмотренные",
|
||||
"XTREAM_RECENTLY_ADDED": "Недавно добавленные на Xtream",
|
||||
"NO_HISTORY": "Для этого фильтра элементы не найдены.",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "Kategorileri sırala",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "İzlemeye Devam Et",
|
||||
"LIVE_RECENT": "Favorilerinizde şu an canlı",
|
||||
"UNTITLED_SOURCE": "Adsız kaynak",
|
||||
"GLOBAL_FAVORITES": "Tüm Favoriler",
|
||||
"REMOVE_FROM_HISTORY": "Geçmişten kaldır",
|
||||
"RECENT_SOURCES": "Son Kullanılan Kaynaklar",
|
||||
"MANAGE_ALL": "Tümünü yönet",
|
||||
"SEE_ALL": "Tümünü gör",
|
||||
"SEE_ALL_COUNT": "{{count}} öğenin tümünü gör",
|
||||
"RECENTLY_WATCHED": "Son İzlenenler",
|
||||
"XTREAM_RECENTLY_ADDED": "Xtream'de Yeni Eklenenler",
|
||||
"NO_HISTORY": "Bu filtre için öğe bulunamadı.",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "排序分类",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "继续观看",
|
||||
"LIVE_RECENT": "收藏频道正在播放",
|
||||
"UNTITLED_SOURCE": "未命名源",
|
||||
"GLOBAL_FAVORITES": "全局收藏",
|
||||
"REMOVE_FROM_HISTORY": "从历史记录中移除",
|
||||
"RECENT_SOURCES": "最近使用的源",
|
||||
"MANAGE_ALL": "管理全部",
|
||||
"SEE_ALL": "查看全部",
|
||||
"SEE_ALL_COUNT": "查看全部 {{count}} 个",
|
||||
"RECENTLY_WATCHED": "最近观看",
|
||||
"XTREAM_RECENTLY_ADDED": "Xtream 最近添加",
|
||||
"NO_HISTORY": "没有项目匹配此筛选。",
|
||||
|
||||
@@ -823,11 +823,14 @@
|
||||
"CATEGORY_SORT_ARIA": "排序分類",
|
||||
"DASHBOARD": {
|
||||
"CONTINUE_WATCHING": "繼續觀看",
|
||||
"LIVE_RECENT": "我的最愛正在直播",
|
||||
"UNTITLED_SOURCE": "未命名的來源",
|
||||
"GLOBAL_FAVORITES": "全域我的最愛",
|
||||
"REMOVE_FROM_HISTORY": "從歷史記錄中移除",
|
||||
"RECENT_SOURCES": "最近使用的來源",
|
||||
"MANAGE_ALL": "管理全部",
|
||||
"SEE_ALL": "查看全部",
|
||||
"SEE_ALL_COUNT": "查看全部 {{count}} 個",
|
||||
"RECENTLY_WATCHED": "最近觀看",
|
||||
"XTREAM_RECENTLY_ADDED": "Xtream 最近新增",
|
||||
"NO_HISTORY": "找不到符合此篩選條件的項目。",
|
||||
|
||||
@@ -419,6 +419,75 @@ describe('DashboardDataService', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('splits global recent items into VOD and live computed signals so the dashboard can render two rails', async () => {
|
||||
// Seed an Xtream movie and an Xtream series alongside the M3U live
|
||||
// channel already present in defaultPlaylists, then verify the
|
||||
// splits land on the right computed signal.
|
||||
dbServiceMock.getGlobalRecentlyViewed.mockResolvedValue([
|
||||
{
|
||||
id: 401,
|
||||
category_id: 18,
|
||||
title: 'Recent Movie',
|
||||
rating: '7.8',
|
||||
viewed_at: '2026-04-21T10:00:00.000Z',
|
||||
poster_url: 'https://example.com/recent-movie.png',
|
||||
xtream_id: 7001,
|
||||
type: 'movie',
|
||||
playlist_id: 'xtream-1',
|
||||
playlist_name: 'Xtream Playlist',
|
||||
},
|
||||
{
|
||||
id: 402,
|
||||
category_id: 19,
|
||||
title: 'Recent Series',
|
||||
rating: '8.1',
|
||||
viewed_at: '2026-04-22T10:00:00.000Z',
|
||||
poster_url: 'https://example.com/recent-series.png',
|
||||
xtream_id: 7002,
|
||||
type: 'series',
|
||||
playlist_id: 'xtream-1',
|
||||
playlist_name: 'Xtream Playlist',
|
||||
},
|
||||
]);
|
||||
|
||||
playlistsSignal.set([
|
||||
...playlistsSignal(),
|
||||
{
|
||||
_id: 'xtream-1',
|
||||
title: 'Xtream Playlist',
|
||||
count: 1,
|
||||
importDate: '2026-01-01T00:00:00.000Z',
|
||||
autoRefresh: false,
|
||||
serverUrl: 'https://example.com',
|
||||
},
|
||||
]);
|
||||
|
||||
await service.reloadGlobalRecentItems();
|
||||
|
||||
const vodTitles = service
|
||||
.globalRecentVodItems()
|
||||
.map((item) => item.title);
|
||||
const liveTitles = service
|
||||
.globalRecentLiveItems()
|
||||
.map((item) => item.title);
|
||||
|
||||
expect(vodTitles).toEqual(
|
||||
expect.arrayContaining(['Recent Movie', 'Recent Series'])
|
||||
);
|
||||
expect(vodTitles).not.toContain('Channel One');
|
||||
|
||||
expect(liveTitles).toContain('Channel One');
|
||||
expect(liveTitles).not.toEqual(
|
||||
expect.arrayContaining(['Recent Movie', 'Recent Series'])
|
||||
);
|
||||
|
||||
// Splits stay mutually exclusive — sum of partitions equals the whole.
|
||||
expect(
|
||||
service.globalRecentVodItems().length +
|
||||
service.globalRecentLiveItems().length
|
||||
).toBe(service.globalRecentItems().length);
|
||||
});
|
||||
|
||||
it('prioritizes recently used Xtream sources over newer imported M3U sources', async () => {
|
||||
playlistsSignal.set([
|
||||
{
|
||||
|
||||
@@ -196,6 +196,19 @@ export class DashboardDataService {
|
||||
.slice(0, 200)
|
||||
);
|
||||
|
||||
// Split the recent list by content type so the dashboard can render
|
||||
// movies/series ("Continue watching") separately from live channels
|
||||
// ("Live now on your favorites"). Two card formats — one rail each.
|
||||
readonly globalRecentVodItems = computed<GlobalRecentItem[]>(() =>
|
||||
this.globalRecentItems().filter(
|
||||
(item) => item.type === 'movie' || item.type === 'series'
|
||||
)
|
||||
);
|
||||
|
||||
readonly globalRecentLiveItems = computed<GlobalRecentItem[]>(() =>
|
||||
this.globalRecentItems().filter((item) => item.type === 'live')
|
||||
);
|
||||
|
||||
readonly stalkerGlobalFavorites = computed<DashboardFavoriteItem[]>(() => {
|
||||
this.languageTick();
|
||||
return buildStalkerFavoriteItems(
|
||||
|
||||
@@ -14,9 +14,20 @@
|
||||
[routerLink]="link"
|
||||
[attr.data-test-id]="testId() ? testId() + '-manage-all' : null"
|
||||
>
|
||||
<span class="rail__see-all-label">{{
|
||||
'WORKSPACE.DASHBOARD.MANAGE_ALL' | translate
|
||||
}}</span>
|
||||
<span class="rail__see-all-label">
|
||||
@if ((totalCount() ?? items().length) > items().length) {
|
||||
{{
|
||||
'WORKSPACE.DASHBOARD.SEE_ALL_COUNT'
|
||||
| translate
|
||||
: {
|
||||
count:
|
||||
totalCount() ?? items().length,
|
||||
}
|
||||
}}
|
||||
} @else {
|
||||
{{ 'WORKSPACE.DASHBOARD.SEE_ALL' | translate }}
|
||||
}
|
||||
</span>
|
||||
<mat-icon>chevron_right</mat-icon>
|
||||
</a>
|
||||
}
|
||||
|
||||
+24
-7
@@ -102,16 +102,33 @@
|
||||
</section>
|
||||
}
|
||||
|
||||
<!-- Recently watched rail -->
|
||||
@if (recentlyWatchedCards().length > 0) {
|
||||
<!-- Continue watching (movies + series) -->
|
||||
@if (continueWatchingCards().length > 0) {
|
||||
<lib-dashboard-rail
|
||||
[label]="'WORKSPACE.DASHBOARD.RECENTLY_WATCHED' | translate"
|
||||
[items]="recentlyWatchedCards()"
|
||||
[totalCount]="data.globalRecentItems().length"
|
||||
[label]="'WORKSPACE.DASHBOARD.CONTINUE_WATCHING' | translate"
|
||||
[items]="continueWatchingCards()"
|
||||
[totalCount]="data.globalRecentVodItems().length"
|
||||
[seeAllLink]="['/workspace/global-recent']"
|
||||
[testId]="'dashboard-recently-watched-rail'"
|
||||
[testId]="'dashboard-continue-watching-rail'"
|
||||
/>
|
||||
} @else if (data.globalRecentLoading()) {
|
||||
}
|
||||
|
||||
<!-- Live now on your favorites (channels you recently watched) -->
|
||||
@if (liveOnFavoritesCards().length > 0) {
|
||||
<lib-dashboard-rail
|
||||
[label]="'WORKSPACE.DASHBOARD.LIVE_RECENT' | translate"
|
||||
[items]="liveOnFavoritesCards()"
|
||||
[totalCount]="data.globalRecentLiveItems().length"
|
||||
[seeAllLink]="['/workspace/global-recent']"
|
||||
[testId]="'dashboard-live-recent-rail'"
|
||||
/>
|
||||
}
|
||||
|
||||
@if (
|
||||
continueWatchingCards().length === 0 &&
|
||||
liveOnFavoritesCards().length === 0 &&
|
||||
data.globalRecentLoading()
|
||||
) {
|
||||
<section
|
||||
class="rails-page__skeleton-rail"
|
||||
aria-hidden="true"
|
||||
|
||||
+13
-2
@@ -270,9 +270,20 @@ export class WorkspaceDashboardRailsComponent {
|
||||
};
|
||||
});
|
||||
|
||||
readonly recentlyWatchedCards = computed<DashboardRailCard[]>(() =>
|
||||
// Split the mixed "recently watched" history into two rails. VOD items
|
||||
// (movies/series) get one rail; live channels get their own. Two card
|
||||
// formats — one rail each — so users can scan each surface at a glance
|
||||
// instead of decoding a mixed grid of fallback posters and channel logos.
|
||||
readonly continueWatchingCards = computed<DashboardRailCard[]>(() =>
|
||||
this.data
|
||||
.globalRecentItems()
|
||||
.globalRecentVodItems()
|
||||
.slice(0, RAIL_ITEM_LIMIT)
|
||||
.map((item) => this.toRecentCard(item))
|
||||
);
|
||||
|
||||
readonly liveOnFavoritesCards = computed<DashboardRailCard[]>(() =>
|
||||
this.data
|
||||
.globalRecentLiveItems()
|
||||
.slice(0, RAIL_ITEM_LIMIT)
|
||||
.map((item) => this.toRecentCard(item))
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user