mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
feat(ui): add empty-state and expose addPlaylist event
Introduce explicit empty-state handling in RecentPlaylists: - Replace previous direct rendering of an empty mat-list item with app-empty-state for two cases: a global "welcome" state when no playlists exist at all, and a "no-results" state when filters/search return nothing. This clarifies UX and provides a CTA for adding playlists in the welcome state. - Change playlist data binding from playlists$ to playlistsData$ and adapt loops and accessors to data.playlists / data.totalCount. - Keep existing global favorites item and playlist-item rendering. Wire up addPlaylist event and components: - Add addPlaylistClicked output to RecentPlaylists component and forward the event from the home component so the parent can open the add-playlist flow. - Import EmptyStateComponent and PlaylistType types used by the new output. Minor cleanup and imports: - Reformat some imports and add tap to RxJS imports. - Adjust template structure and placeholders for deferred loading.
This commit is contained in:
1 parent
b82d47f6b6
commit
aa2d5b9508
6 files changed
+68
-82
No files matched your search
@@ -6,4 +6,5 @@
|
||||
<app-recent-playlists
|
||||
class="recent-playlists"
|
||||
[searchQueryInput]="searchQuery()"
|
||||
(addPlaylistClicked)="onAddPlaylist($event)"
|
||||
/>
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Component, signal } from '@angular/core';
|
||||
import { Component, inject, signal } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { RecentPlaylistsComponent } from 'components';
|
||||
import { PlaylistType, RecentPlaylistsComponent } from 'components';
|
||||
import { AddPlaylistDialogComponent } from '../shared/components/add-playlist/add-playlist-dialog.component';
|
||||
import { HeaderComponent } from '../shared/components/header/header.component';
|
||||
|
||||
@Component({
|
||||
@@ -10,9 +12,21 @@ import { HeaderComponent } from '../shared/components/header/header.component';
|
||||
imports: [HeaderComponent, RecentPlaylistsComponent, TranslatePipe],
|
||||
})
|
||||
export class HomeComponent {
|
||||
private readonly dialog = inject(MatDialog);
|
||||
|
||||
searchQuery = signal<string>('');
|
||||
|
||||
onSearchQueryChange(query: string): void {
|
||||
this.searchQuery.set(query);
|
||||
}
|
||||
|
||||
onAddPlaylist(playlistType: PlaylistType): void {
|
||||
this.dialog.open<AddPlaylistDialogComponent, { type: PlaylistType }>(
|
||||
AddPlaylistDialogComponent,
|
||||
{
|
||||
width: '600px',
|
||||
data: { type: playlistType },
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -28,12 +28,15 @@
|
||||
<button
|
||||
mat-icon-button
|
||||
class="add-playlist-btn"
|
||||
[matMenuTriggerFor]="addPlaylistMenu"
|
||||
[matMenuTriggerFor]="addPlaylistMenuComponent().menu()"
|
||||
[matTooltip]="'HOME.URL_UPLOAD.ADD_PLAYLIST' | translate"
|
||||
data-test-id="add-playlist"
|
||||
>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
<app-add-playlist-menu
|
||||
(playlistTypeSelected)="opedAddPlaylistDialog($event)"
|
||||
/>
|
||||
<!-- Sort button -->
|
||||
<button
|
||||
mat-icon-button
|
||||
@@ -194,53 +197,6 @@
|
||||
}
|
||||
</section>
|
||||
</mat-menu>
|
||||
<mat-menu #addPlaylistMenu="matMenu">
|
||||
<button
|
||||
mat-menu-item
|
||||
[attr.aria-label]="'HOME.TABS.FILE_UPLOAD' | translate"
|
||||
(click)="opedAddPlaylistDialog('file')"
|
||||
>
|
||||
<mat-icon>attach_file</mat-icon>
|
||||
<span>{{ 'HOME.TABS.FILE_UPLOAD' | translate }}</span>
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
[attr.aria-label]="'HOME.TABS.URL_UPLOAD' | translate"
|
||||
(click)="opedAddPlaylistDialog('url')"
|
||||
>
|
||||
<mat-icon>link</mat-icon>
|
||||
<span>{{ 'HOME.TABS.URL_UPLOAD' | translate }}</span>
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
[attr.aria-label]="'HOME.TABS.TEXT_IMPORT' | translate"
|
||||
(click)="opedAddPlaylistDialog('text')"
|
||||
>
|
||||
<mat-icon>text_format</mat-icon>
|
||||
<span>{{ 'HOME.TABS.TEXT_IMPORT' | translate }}</span>
|
||||
</button>
|
||||
<mat-divider></mat-divider>
|
||||
<button
|
||||
mat-menu-item
|
||||
[attr.aria-label]="'HOME.TABS.XTREME_IMPORT' | translate"
|
||||
(click)="opedAddPlaylistDialog('xtream')"
|
||||
>
|
||||
<mat-icon>video_library</mat-icon>
|
||||
<span>{{ 'HOME.TABS.XTREME_IMPORT' | translate }}</span>
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
[attr.aria-label]="
|
||||
'HOME.TABS.STALKER_PORTAL_IMPORT' | translate
|
||||
"
|
||||
(click)="opedAddPlaylistDialog('stalker')"
|
||||
>
|
||||
<mat-icon>dashboard</mat-icon>
|
||||
<span>{{
|
||||
'HOME.TABS.STALKER_PORTAL_IMPORT' | translate
|
||||
}}</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, HostBinding, OnInit, effect, inject, input, output } from '@angular/core';
|
||||
import { Component, HostBinding, OnInit, effect, inject, input, output, viewChild } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
@@ -13,18 +13,17 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
import { DataService, SortBy, SortOrder, SortService } from 'services';
|
||||
//import { shell } from 'electron';
|
||||
import { selectActiveTypeFilters, setSelectedFilters } from 'm3u-state';
|
||||
import { AddPlaylistMenuComponent, PlaylistType } from 'components';
|
||||
import { HomeComponent } from '../../../home/home.component';
|
||||
import { AboutDialogComponent } from '../about-dialog/about-dialog.component';
|
||||
import {
|
||||
AddPlaylistDialogComponent,
|
||||
PlaylistType,
|
||||
} from '../add-playlist/add-playlist-dialog.component';
|
||||
import { AddPlaylistDialogComponent } from '../add-playlist/add-playlist-dialog.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
templateUrl: './header.component.html',
|
||||
styleUrls: ['./header.component.scss'],
|
||||
imports: [
|
||||
AddPlaylistMenuComponent,
|
||||
FormsModule,
|
||||
MatButtonModule,
|
||||
MatCheckboxModule,
|
||||
@@ -40,6 +39,7 @@ export class HeaderComponent implements OnInit {
|
||||
@HostBinding('class.home-header') get isHomeHeader() {
|
||||
return this.isHome;
|
||||
}
|
||||
|
||||
private activatedRoute = inject(ActivatedRoute);
|
||||
private dialog = inject(MatDialog);
|
||||
private dataService = inject(DataService);
|
||||
@@ -47,6 +47,7 @@ export class HeaderComponent implements OnInit {
|
||||
private store = inject(Store);
|
||||
private sortService = inject(SortService);
|
||||
|
||||
readonly addPlaylistMenuComponent = viewChild.required(AddPlaylistMenuComponent);
|
||||
readonly isDesktop = !!window.electron;
|
||||
readonly title = input.required<string>();
|
||||
readonly subtitle = input.required<string>();
|
||||
|
||||
Reference in new issue
Block a user