Files
iptvnator/apps/web/src/app/stalker/stalker-live-stream-layout/stalker-live-stream-layout.component.html
T
4gray c6bd861b49 refactor: streamline layout and styling for live stream component
- Consolidated SCSS styles for the live stream layout, reducing redundancy and improving maintainability.
- Introduced a new portal layout mixin for better structure.
- Enhanced sidebar and content container styles for improved user experience.
- Updated TypeScript component to utilize new styles and improve readability.
- Refactored channel list and recently viewed components for consistency in design.
- Optimized playlist service and store interactions for better performance.
- Added new translations for enhanced user interface clarity.
- Improved database schema with additional indexing for EPG programs.
2026-03-08 11:25:26 +01:00

144 lines
5.3 KiB
HTML

@let isEmbeddedPlayer =
player() === 'videojs' || player() === 'html5' || player() === 'artplayer';
@if (!isWorkspaceLayout || stalkerStore.selectedCategoryId()) {
<div
class="sidebar"
appResizable
[minWidth]="250"
[maxWidth]="600"
[defaultWidth]="400"
storageKey="sidebar-width"
>
@if (stalkerStore.selectedCategoryId() || !isWorkspaceLayout) {
<div class="sidebar-header">
@if (stalkerStore.selectedCategoryId()) {
<button mat-icon-button (click)="backToCategories()">
<mat-icon>chevron_left</mat-icon>
</button>
<h2>{{ selectedCategoryTitle() }}</h2>
} @else {
<app-playlist-switcher
class="switcher"
[currentTitle]="currentPlaylist()?.title || 'Portal'"
[subtitle]="'Stalker Portal'"
/>
}
</div>
}
@if (stalkerStore.selectedCategoryId()) {
<!-- <div class="search-panel">
<mat-form-field class="search-bar" subscriptSizing="dynamic">
<mat-icon matPrefix>search</mat-icon>
<input
matInput
[placeholder]="'PORTALS.SIDEBAR.SEARCH' | translate"
[ngModel]="searchString()"
(ngModelChange)="searchString.set($event)"
/>
@if (searchString()) {
<button matSuffix mat-icon-button (click)="searchString.set('')">
<mat-icon>close</mat-icon>
</button>
}
</mat-form-field>
</div> -->
<div #scrollContainer class="channels-list">
@for (item of itvChannels(); track item.id ?? $index) {
<app-channel-list-item
[name]="item.o_name || item.name"
[logo]="item.logo"
[selected]="isSelectedChannel(item)"
[epgProgram]="
epgPreviewPrograms.get(
normalizeStalkerEntityId(item.id)
) ?? null
"
[progressPercentage]="
currentProgramsProgress.get(
normalizeStalkerEntityId(item.id)
) ?? 0
"
[showFavoriteButton]="true"
[showProgramInfoButton]="false"
[isFavorite]="
favorites.get(normalizeStalkerEntityId(item.id)) ??
false
"
(clicked)="playChannel(item)"
(favoriteToggled)="toggleFavorite(item)"
/>
}
@if (isLoadingMore()) {
<div class="loading-indicator">
<mat-spinner diameter="24" />
</div>
}
</div>
} @else {
@if (isCategoryLoading()) {
<ngx-skeleton-loader
count="20"
[theme]="{
width: '95%',
height: '48px',
borderRadius: '40px',
}"
/>
} @else if (isCategoryFailed()) {
<app-playlist-error-view
[title]="
'PORTALS.ERROR_VIEW.UNKNOWN_ERROR.TITLE' | translate
"
[description]="
'PORTALS.ERROR_VIEW.UNKNOWN_ERROR.DESCRIPTION'
| translate
"
/>
} @else {
<app-category-view
[items]="categories()"
[selectedCategoryId]="
$any(stalkerStore.selectedCategoryId())
"
(categoryClicked)="selectCategory($event)"
/>
}
}
</div>
}
<div class="content-container">
@if (streamUrl && isEmbeddedPlayer) {
<div class="video-player">
<app-web-player-view [streamUrl]="streamUrl" />
</div>
}
@if (stalkerStore.selectedItem()) {
<div class="epg">
<div class="epg-content">
<app-epg-view [epgItems]="epgItems()" />
@if (isLoadingEpg()) {
<div class="loading-indicator">
<mat-spinner diameter="24" />
</div>
}
@if (hasMoreEpg() && !isLoadingEpg()) {
<div class="load-more-epg">
<button mat-button (click)="loadMoreEpg()">
{{ 'CHANNELS.LOAD_MORE' | translate }}
</button>
</div>
}
</div>
</div>
} @else {
<app-portal-empty-state
icon="live_tv"
[message]="'CHANNELS.SELECT_CHANNEL_PLAYBACK' | translate"
/>
}
</div>