mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 19:46:16 -08:00
feat(ui): add filter and sort menu to header and clean styles
Add a new mat-menu component for filtering and sorting playlists in the header area. The filter section iterates playlistTypes and allows toggling type selection with visual check state. The sort section adds options for name (asc/desc) and date added (newest/oldest) with active-state visuals and click handlers that call setSortOptions. A close button is also included. Remove unused/duplicate CSS rules from header styles: drop .filter- container and obsolete .dropdown-menu-header rules to avoid styling conflicts and reduce dead code. Adjust surrounding selector formatting.
This commit is contained in:
1 parent
c84b42284a
commit
a874db0b41
6 files changed
+357
-190
No files matched your search
@@ -2,30 +2,28 @@ import {
|
||||
Component,
|
||||
HostBinding,
|
||||
OnInit,
|
||||
effect,
|
||||
inject,
|
||||
input,
|
||||
output,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatBadgeModule } from '@angular/material/badge';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { DataService, SortBy, SortOrder, SortService } from 'services';
|
||||
import { DataService } from 'services';
|
||||
//import { shell } from 'electron';
|
||||
import { AddPlaylistMenuComponent, PlaylistType } from 'components';
|
||||
import { selectActiveTypeFilters, setSelectedFilters } from 'm3u-state';
|
||||
import { HomeComponent } from '../../../home/home.component';
|
||||
import { AboutDialogComponent } from '../about-dialog/about-dialog.component';
|
||||
import { AddPlaylistDialogComponent } from '../add-playlist/add-playlist-dialog.component';
|
||||
import { FilterSortMenuComponent } from '../filter-sort-menu/filter-sort-menu.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
@@ -33,9 +31,10 @@ import { AddPlaylistDialogComponent } from '../add-playlist/add-playlist-dialog.
|
||||
styleUrls: ['./header.component.scss'],
|
||||
imports: [
|
||||
AddPlaylistMenuComponent,
|
||||
FilterSortMenuComponent,
|
||||
FormsModule,
|
||||
MatBadgeModule,
|
||||
MatButtonModule,
|
||||
MatCheckboxModule,
|
||||
MatDividerModule,
|
||||
MatIconModule,
|
||||
MatMenuModule,
|
||||
@@ -53,12 +52,13 @@ export class HeaderComponent implements OnInit {
|
||||
private dialog = inject(MatDialog);
|
||||
private dataService = inject(DataService);
|
||||
private router = inject(Router);
|
||||
private store = inject(Store);
|
||||
private sortService = inject(SortService);
|
||||
|
||||
readonly addPlaylistMenuComponent = viewChild.required(
|
||||
AddPlaylistMenuComponent
|
||||
);
|
||||
readonly filterSortMenuComponent = viewChild.required(
|
||||
FilterSortMenuComponent
|
||||
);
|
||||
readonly isDesktop = !!window.electron;
|
||||
readonly title = input.required<string>();
|
||||
readonly subtitle = input.required<string>();
|
||||
@@ -66,47 +66,6 @@ export class HeaderComponent implements OnInit {
|
||||
|
||||
isHome = true;
|
||||
|
||||
playlistTypes = [
|
||||
{
|
||||
title: 'M3U (local, url, text)',
|
||||
id: 'm3u',
|
||||
checked: true,
|
||||
},
|
||||
{
|
||||
title: 'Xtream',
|
||||
id: 'xtream',
|
||||
checked: true,
|
||||
},
|
||||
{
|
||||
title: 'Stalker',
|
||||
id: 'stalker',
|
||||
checked: true,
|
||||
},
|
||||
];
|
||||
|
||||
private readonly selectedTypeFilters = this.store.selectSignal(
|
||||
selectActiveTypeFilters
|
||||
);
|
||||
|
||||
readonly SortBy = SortBy;
|
||||
readonly SortOrder = SortOrder;
|
||||
private currentSortOptions: { by: SortBy; order: SortOrder };
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
if (this.selectedTypeFilters) {
|
||||
this.playlistTypes = this.playlistTypes.map((type) => {
|
||||
type.checked = this.selectedTypeFilters().includes(type.id);
|
||||
return type;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.sortService.getSortOptions().subscribe((options) => {
|
||||
this.currentSortOptions = options;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.isHome =
|
||||
this.activatedRoute.snapshot.component.name === HomeComponent.name;
|
||||
@@ -154,27 +113,6 @@ export class HeaderComponent implements OnInit {
|
||||
);
|
||||
}
|
||||
|
||||
onPlaylistFilterChange() {
|
||||
this.store.dispatch(
|
||||
setSelectedFilters({
|
||||
selectedFilters: this.playlistTypes
|
||||
.filter((f) => f.checked)
|
||||
.map((f) => f.id),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
setSortOptions(by: SortBy, order: SortOrder): void {
|
||||
this.sortService.setSortOptions({ by, order });
|
||||
}
|
||||
|
||||
isSortActive(by: SortBy, order: SortOrder): boolean {
|
||||
return (
|
||||
this.currentSortOptions?.by === by &&
|
||||
this.currentSortOptions?.order === order
|
||||
);
|
||||
}
|
||||
|
||||
onSearchQueryUpdate(query: string): void {
|
||||
this.searchQuery.emit(query);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user