mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-13 04:26:16 -08:00
Merge pull request #423 from 4gray/style/material-update
Style: Material 3 update
This commit is contained in:
30 files changed
+503
-1856
No files matched your search
+6
-7
@@ -32,8 +32,7 @@
|
||||
"src/manifest.webmanifest"
|
||||
],
|
||||
"styles": [
|
||||
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
||||
"src/styles.scss",
|
||||
"src/m3-theme.scss",
|
||||
"./node_modules/video.js/dist/video-js.css"
|
||||
],
|
||||
"scripts": [],
|
||||
@@ -95,24 +94,24 @@
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"buildTarget": "iptvnator:build"
|
||||
"buildTarget": "iptvnator:build"
|
||||
},
|
||||
"configurations": {
|
||||
"dev": {
|
||||
"buildTarget": "iptvnator:build:dev"
|
||||
"buildTarget": "iptvnator:build:dev"
|
||||
},
|
||||
"web": {
|
||||
"buildTarget": "iptvnator:build:web"
|
||||
"buildTarget": "iptvnator:build:web"
|
||||
},
|
||||
"production": {
|
||||
"buildTarget": "iptvnator:build:production"
|
||||
"buildTarget": "iptvnator:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"buildTarget": "iptvnator:build"
|
||||
"buildTarget": "iptvnator:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
|
||||
+1
-1
@@ -2,6 +2,6 @@ import { Titlebar, TitlebarColor } from 'custom-electron-titlebar';
|
||||
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
new Titlebar({
|
||||
backgroundColor: TitlebarColor.fromHex('#000'),
|
||||
backgroundColor: TitlebarColor.fromHex('#1b1c1c'),
|
||||
});
|
||||
});
|
||||
Generated
+22
-1630
File diff suppressed because it is too large.
Load diff
+3
-3
@@ -53,8 +53,8 @@
|
||||
"dependencies": {
|
||||
"@angular-builders/jest": "17.0.0",
|
||||
"@angular/animations": "18.2.1",
|
||||
"@angular/cdk": "16.1.5",
|
||||
"@angular/material": "16.1.5",
|
||||
"@angular/cdk": "18.2.1",
|
||||
"@angular/material": "18.2.1",
|
||||
"@electron/remote": "2.1.0",
|
||||
"@ngrx/component-store": "18.0.2",
|
||||
"@ngrx/effects": "18.0.2",
|
||||
@@ -157,4 +157,4 @@
|
||||
"browserslist": [
|
||||
"chrome 91"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,6 @@
|
||||
.recent-playlists {
|
||||
height: calc(100vh - 106px);
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 480px) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<mat-list-item cdkDrag (click)="playlistClicked.emit(item._id)">
|
||||
<mat-icon matListItemAvatar cdkDragHandle class="drag-icon"
|
||||
<mat-icon matListItemIcon cdkDragHandle class="drag-icon"
|
||||
>drag_indicator</mat-icon
|
||||
>
|
||||
<mat-icon
|
||||
matListItemAvatar
|
||||
matListItemIcon
|
||||
class="upload-type-icon"
|
||||
*ngIf="item?.url"
|
||||
[matTooltip]="
|
||||
@@ -12,21 +12,21 @@
|
||||
>cloud</mat-icon
|
||||
>
|
||||
<mat-icon
|
||||
matListItemAvatar
|
||||
matListItemIcon
|
||||
class="upload-type-icon"
|
||||
*ngIf="!item?.url && !item.serverUrl && !item.macAddress"
|
||||
[matTooltip]="'HOME.PLAYLISTS.ADDED_VIA_FILE' | translate"
|
||||
>folder</mat-icon
|
||||
>
|
||||
<mat-icon
|
||||
matListItemAvatar
|
||||
matListItemIcon
|
||||
class="upload-type-icon"
|
||||
*ngIf="item?.serverUrl"
|
||||
[matTooltip]="'HOME.PLAYLISTS.XTREAM_PLAYLIST' | translate"
|
||||
>public</mat-icon
|
||||
>
|
||||
<mat-icon
|
||||
matListItemAvatar
|
||||
matListItemIcon
|
||||
class="upload-type-icon"
|
||||
*ngIf="item?.macAddress"
|
||||
[matTooltip]="'HOME.PLAYLISTS.STALKER_PORTAL' | translate"
|
||||
@@ -101,4 +101,3 @@
|
||||
</button>
|
||||
</span>
|
||||
</mat-list-item>
|
||||
<mat-divider />
|
||||
@@ -14,8 +14,8 @@ mat-list-item {
|
||||
|
||||
.cdk-drag-preview {
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 5px 5px -3px rgb(0 0 0 / 20%), 0 8px 10px 1px rgb(0 0 0 / 14%), 0 3px 14px 2px rgb(0 0 0 / 12%);
|
||||
border-radius: 30px;
|
||||
box-shadow: 0 5px 5px -3px rgb(0 0 0 / 20%), 0 8px 10px 1px rgba(58, 58, 58, 0.14), 0 3px 14px 2px rgb(0 0 0 / 12%);
|
||||
}
|
||||
|
||||
.cdk-drag-placeholder {
|
||||
@@ -28,7 +28,6 @@ mat-list-item {
|
||||
|
||||
.drag-icon {
|
||||
cursor: move;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@if (allPlaylistsLoaded()) {
|
||||
<mat-form-field class="full-width search-field" subscriptSizing="dynamic">
|
||||
<mat-form-field class="search-field" subscriptSizing="dynamic">
|
||||
<mat-icon matPrefix>search</mat-icon>
|
||||
<input
|
||||
matInput
|
||||
#searchQuery
|
||||
@@ -17,7 +18,7 @@
|
||||
<mat-list-item
|
||||
*ngIf="playlists.length === 0; else playlistsTemplate"
|
||||
>
|
||||
<mat-icon class="favorites-icon" matListItemAvatar
|
||||
<mat-icon class="favorites-icon" matListItemIcon
|
||||
>search</mat-icon
|
||||
>
|
||||
<div matListItemTitle>
|
||||
@@ -30,7 +31,7 @@
|
||||
|
||||
<ng-template #playlistsTemplate>
|
||||
<mat-list-item (click)="getGlobalFavorites()">
|
||||
<mat-icon class="favorites-icon" matListItemAvatar
|
||||
<mat-icon class="favorites-icon" matListItemIcon
|
||||
>star</mat-icon
|
||||
>
|
||||
<div matListItemTitle>
|
||||
@@ -43,7 +44,6 @@
|
||||
}}
|
||||
</div>
|
||||
</mat-list-item>
|
||||
<mat-divider />
|
||||
|
||||
<app-playlist-item
|
||||
*ngFor="
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mat-list-base {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.playlists-list {
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-field {
|
||||
border-radius: 0;
|
||||
width: 96%;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.meta {
|
||||
@@ -16,24 +24,35 @@
|
||||
margin-top: 2px !important;
|
||||
}
|
||||
|
||||
::ng-deep .cdk-drag-preview .mat-list-item-content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
padding: 0 16px;
|
||||
position: relative;
|
||||
height: inherit;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
|
||||
.mat-list-text {
|
||||
::ng-deep {
|
||||
div[matformfieldlineripple] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search-field > .mat-mdc-text-field-wrapper {
|
||||
border-radius: 30px;
|
||||
}
|
||||
|
||||
.cdk-drag-preview .mat-list-item-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: auto;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
padding-left: 16px;
|
||||
padding: 0 16px;
|
||||
position: relative;
|
||||
height: inherit;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
|
||||
.mat-list-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: auto;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
padding-left: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,10 +62,11 @@
|
||||
|
||||
#skeleton-container {
|
||||
padding-top: 10px;
|
||||
width: 100%;
|
||||
|
||||
.skeleton-item {
|
||||
display: flex;
|
||||
padding-left: 25px;
|
||||
padding: 0 20px;
|
||||
height: 72px;
|
||||
|
||||
.text {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
type="text"
|
||||
id="serverUrl"
|
||||
formControlName="serverUrl"
|
||||
(input)="extractParams(form.value.serverUrl)"
|
||||
/>
|
||||
<mat-hint>{{
|
||||
'HOME.XTREAM_PLAYLIST.URL_VALIDATION_ERROR' | translate
|
||||
|
||||
@@ -67,4 +67,25 @@ export class XtreamCodeImportComponent {
|
||||
);
|
||||
this.addClicked.emit();
|
||||
}
|
||||
|
||||
extractParams(urlAsString: string): void {
|
||||
if (
|
||||
this.form.get('username').value !== '' ||
|
||||
this.form.get('password').value !== ''
|
||||
)
|
||||
return;
|
||||
try {
|
||||
// Create a new URL object from the complete link
|
||||
const url = new URL(urlAsString);
|
||||
|
||||
// Extract username and password from query parameters
|
||||
const username = url.searchParams.get('username') || '';
|
||||
const password = url.searchParams.get('password') || '';
|
||||
|
||||
this.form.get('username')?.setValue(username);
|
||||
this.form.get('password')?.setValue(password);
|
||||
} catch (error) {
|
||||
console.error('Invalid URL', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-9
@@ -8,15 +8,17 @@
|
||||
</div>
|
||||
</ng-template>
|
||||
<div class="search-panel">
|
||||
<input
|
||||
class="full-width search-bar"
|
||||
type="search"
|
||||
#search
|
||||
[placeholder]="'CHANNELS.SEARCH_CHANNEL' | translate"
|
||||
[(ngModel)]="searchTerm.name"
|
||||
/>
|
||||
<mat-form-field class="search-bar">
|
||||
<input
|
||||
matInput
|
||||
class="full-width"
|
||||
type="search"
|
||||
#search
|
||||
[placeholder]="'CHANNELS.SEARCH_CHANNEL' | translate"
|
||||
[(ngModel)]="searchTerm.name"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<mat-nav-list style="overflow: hidden">
|
||||
<cdk-virtual-scroll-viewport
|
||||
itemSize="50"
|
||||
@@ -39,7 +41,7 @@
|
||||
[logo]="channel?.tvg?.logo"
|
||||
(clicked)="selectChannel(channel)"
|
||||
[selected]="selected?.id === channel?.id"
|
||||
></app-channel-list-item>
|
||||
/>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
</mat-nav-list>
|
||||
</mat-tab>
|
||||
|
||||
+17
-20
@@ -1,3 +1,5 @@
|
||||
@use '@angular/material' as mat;
|
||||
|
||||
.mat-list-base {
|
||||
padding-top: 0;
|
||||
}
|
||||
@@ -7,14 +9,14 @@
|
||||
}
|
||||
|
||||
.search-panel {
|
||||
padding: 10px;
|
||||
padding: 10px 0 0 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
padding: 8px;
|
||||
background: #ddd;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
@include mat.form-field-density(-5);
|
||||
width: 96%;
|
||||
}
|
||||
|
||||
mat-nav-list {
|
||||
@@ -23,25 +25,20 @@ mat-nav-list {
|
||||
}
|
||||
|
||||
::ng-deep {
|
||||
.search-bar {
|
||||
div {
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
div[matformfieldlineripple], .mat-mdc-form-field-subscript-wrapper {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mat-expansion-panel-body {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.dark-theme {
|
||||
.search-bar {
|
||||
background: #666;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.search-bar::placeholder {
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-tab-label-content {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.mat-expansion-panel {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
+6
-2
@@ -11,7 +11,9 @@ import {
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatExpansionModule } from '@angular/material/expansion';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatListModule } from '@angular/material/list';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
@@ -36,10 +38,12 @@ import { ChannelListItemComponent } from './channel-list-item/channel-list-item.
|
||||
imports: [
|
||||
CommonModule,
|
||||
ChannelListItemComponent,
|
||||
MatExpansionModule,
|
||||
MatDividerModule,
|
||||
MatListModule,
|
||||
MatExpansionModule,
|
||||
MatFormFieldModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatListModule,
|
||||
MatTabsModule,
|
||||
TranslateModule,
|
||||
TitleCasePipe,
|
||||
|
||||
-8
@@ -1,11 +1,3 @@
|
||||
.channel-logo {
|
||||
max-height: 48px;
|
||||
overflow: hidden;
|
||||
border-radius: 0;
|
||||
margin-left: 10px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.channel-name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
+10
-9
@@ -27,14 +27,15 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
class="drag-icon"
|
||||
>drag_indicator</mat-icon
|
||||
>
|
||||
<div matListItemAvatar class="channel-logo" *ngIf="logo">
|
||||
<img
|
||||
[src]="logo"
|
||||
width="48"
|
||||
onerror="this.style.display='none'"
|
||||
/>
|
||||
</div>
|
||||
<p matListItemLine class="channel-name">
|
||||
<img
|
||||
matListItemAvatar
|
||||
class="channel-logo"
|
||||
*ngIf="logo"
|
||||
[src]="logo"
|
||||
width="48"
|
||||
onerror="this.style.display='none'"
|
||||
/>
|
||||
<p matListItemTitle class="channel-name">
|
||||
{{ name }}
|
||||
</p>
|
||||
<button
|
||||
@@ -48,7 +49,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
<mat-icon color="accent">star</mat-icon>
|
||||
</button>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>`,
|
||||
<!-- <mat-divider /> -->`,
|
||||
imports: [
|
||||
CommonModule,
|
||||
DragDropModule,
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<mat-divider />
|
||||
<!-- <mat-divider /> -->
|
||||
@if (sidebarView === 'CHANNELS') {
|
||||
<app-channel-list-container [channelList]="channels" />
|
||||
} @else {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#playlists-navigation {
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
|
||||
.current-playlist {
|
||||
display: flex;
|
||||
@@ -21,7 +19,6 @@
|
||||
|
||||
.channels-count {
|
||||
font-size: 0.8em;
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +27,6 @@
|
||||
height: calc(100vh - 60px);
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.electron {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.video-js {
|
||||
position: relative !important;
|
||||
width: 100% !important;
|
||||
height: calc(100vh - 54px);
|
||||
height: calc(100vh - 65px);
|
||||
}
|
||||
|
||||
/* Hide the captions settings item from the captions menu. */
|
||||
|
||||
@@ -14,7 +14,10 @@ const PACKAGE_JSON_URL =
|
||||
})
|
||||
export class SettingsService {
|
||||
/** Creates an instance of SettingsService */
|
||||
constructor(private http: HttpClient, private storage: StorageMap) {}
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
private storage: StorageMap
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Changes the visual theme of the application
|
||||
|
||||
@@ -66,8 +66,8 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
</ng-container>
|
||||
<mat-divider></mat-divider>
|
||||
<div class="row">
|
||||
<div class="column">
|
||||
{{ 'SETTINGS.VIDEO_PLAYER_LABEL' | translate }}
|
||||
@@ -111,8 +111,8 @@
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<div class="row" *ngIf="settingsForm.value.player === 'vlc'">
|
||||
<div class="column">
|
||||
{{ 'SETTINGS.VLC_PLAYER_PATH_LABEL' | translate }}
|
||||
@@ -131,8 +131,8 @@
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<div class="row">
|
||||
<div class="column">
|
||||
{{ 'SETTINGS.LANGUAGE' | translate }}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<h2 mat-dialog-title>Add Playlist: {{ playlistType }}</h2>
|
||||
<h2 mat-dialog-title>
|
||||
{{ 'HOME.URL_UPLOAD.ADD_PLAYLIST' | translate }}: {{ playlistType }}
|
||||
</h2>
|
||||
<mat-dialog-content class="mat-typography">
|
||||
@if (playlistType === 'file') {
|
||||
<app-file-upload
|
||||
|
||||
@@ -1,107 +1,114 @@
|
||||
<div class="logo">
|
||||
<img src="./assets/icons/icon-tv-256.png" height="100" />
|
||||
</div>
|
||||
<div class="main">
|
||||
<div class="title">{{ title }}</div>
|
||||
<div class="subtitle">{{ subtitle }}</div>
|
||||
</div>
|
||||
<div class="menu" *ngIf="isHome">
|
||||
<button
|
||||
mat-icon-button
|
||||
class="add-playlist-btn"
|
||||
[matMenuTriggerFor]="addPlaylistMenu"
|
||||
[matTooltip]="'HOME.URL_UPLOAD.ADD_PLAYLIST' | translate"
|
||||
data-test-id="add-playlist"
|
||||
>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
<!-- <button
|
||||
<mat-toolbar>
|
||||
<div class="logo">
|
||||
<img src="./assets/icons/icon-tv-256.png" height="100" />
|
||||
</div>
|
||||
<div class="main">
|
||||
<div class="title">{{ title }}</div>
|
||||
<div class="subtitle">{{ subtitle }}</div>
|
||||
</div>
|
||||
<div class="menu" *ngIf="isHome">
|
||||
<button
|
||||
mat-icon-button
|
||||
class="add-playlist-btn"
|
||||
[matMenuTriggerFor]="addPlaylistMenu"
|
||||
[matTooltip]="'HOME.URL_UPLOAD.ADD_PLAYLIST' | translate"
|
||||
data-test-id="add-playlist"
|
||||
>
|
||||
<mat-icon>add</mat-icon>
|
||||
</button>
|
||||
<!-- <button
|
||||
mat-icon-button
|
||||
[matTooltip]="'HOME.FILTER_BY_NAME' | translate"
|
||||
data-test-id="filter-playlist-by-name"
|
||||
>
|
||||
<mat-icon>search</mat-icon>
|
||||
</button> -->
|
||||
<button
|
||||
mat-icon-button
|
||||
[matMenuTriggerFor]="filterPlaylistMenu"
|
||||
[matTooltip]="'HOME.FILTER_BY_TYPE' | translate"
|
||||
data-test-id="filter-playlist-by-type"
|
||||
>
|
||||
<mat-icon>filter_list</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
*ngIf="isElectron; else pwaMenu"
|
||||
mat-icon-button
|
||||
(click)="openSettings()"
|
||||
[matTooltip]="'MENU.SETTINGS' | translate"
|
||||
data-test-id="open-settings"
|
||||
>
|
||||
<mat-icon>settings</mat-icon>
|
||||
</button>
|
||||
|
||||
<mat-menu #filterPlaylistMenu="matMenu">
|
||||
<section (click)="$event.stopPropagation()" class="filter-container">
|
||||
<h4>{{ 'HOME.FILTER_BY_TYPE' | translate }}:</h4>
|
||||
@for (type of playlistTypes; track $index) {
|
||||
<p>
|
||||
<mat-checkbox
|
||||
(click)="$event.stopPropagation()"
|
||||
[checked]="true"
|
||||
(change)="onPlaylistFilterChange()"
|
||||
[(ngModel)]="type.checked"
|
||||
>{{ type.title }}</mat-checkbox
|
||||
>
|
||||
</p>
|
||||
}
|
||||
</section>
|
||||
</mat-menu>
|
||||
|
||||
<mat-menu #addPlaylistMenu="matMenu">
|
||||
<button
|
||||
mat-menu-item
|
||||
[attr.aria-label]="'HOME.TABS.FILE_UPLOAD' | translate"
|
||||
(click)="opedAddPlaylistDialog('file')"
|
||||
mat-icon-button
|
||||
[matMenuTriggerFor]="filterPlaylistMenu"
|
||||
[matTooltip]="'HOME.FILTER_BY_TYPE' | translate"
|
||||
data-test-id="filter-playlist-by-type"
|
||||
>
|
||||
<mat-icon>attach_file</mat-icon>
|
||||
<span>{{ 'HOME.TABS.FILE_UPLOAD' | translate }}</span>
|
||||
<mat-icon>filter_list</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
[attr.aria-label]="'HOME.TABS.URL_UPLOAD' | translate"
|
||||
(click)="opedAddPlaylistDialog('url')"
|
||||
*ngIf="isElectron; else pwaMenu"
|
||||
mat-icon-button
|
||||
(click)="openSettings()"
|
||||
[matTooltip]="'MENU.SETTINGS' | translate"
|
||||
data-test-id="open-settings"
|
||||
>
|
||||
<mat-icon>link</mat-icon>
|
||||
<span>{{ 'HOME.TABS.URL_UPLOAD' | translate }}</span>
|
||||
<mat-icon>settings</mat-icon>
|
||||
</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>
|
||||
<mat-menu #filterPlaylistMenu="matMenu">
|
||||
<section
|
||||
(click)="$event.stopPropagation()"
|
||||
class="filter-container"
|
||||
>
|
||||
<h4>{{ 'HOME.FILTER_BY_TYPE' | translate }}:</h4>
|
||||
@for (type of playlistTypes; track $index) {
|
||||
<p>
|
||||
<mat-checkbox
|
||||
(click)="$event.stopPropagation()"
|
||||
[checked]="true"
|
||||
(change)="onPlaylistFilterChange()"
|
||||
[(ngModel)]="type.checked"
|
||||
>{{ type.title }}</mat-checkbox
|
||||
>
|
||||
</p>
|
||||
}
|
||||
</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>
|
||||
</mat-toolbar>
|
||||
|
||||
<ng-template #pwaMenu>
|
||||
<button
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
:host {
|
||||
background: #000;
|
||||
background: #1b1c1c;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
--mat-toolbar-standard-height: 100px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
@@ -19,13 +20,14 @@
|
||||
max-width: 100%;
|
||||
|
||||
.title {
|
||||
font-size: 1.1em;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: #999;
|
||||
font-size: 0.9em;
|
||||
margin-top: 10px;
|
||||
font-size: 0.7em;
|
||||
margin-top: 5px;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +43,7 @@
|
||||
|
||||
.add-playlist-btn {
|
||||
background-color: #3f51b5;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
|
||||
@@ -7,6 +7,7 @@ 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 { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Store } from '@ngrx/store';
|
||||
@@ -35,6 +36,7 @@ import {
|
||||
MatDividerModule,
|
||||
MatIconModule,
|
||||
MatMenuModule,
|
||||
MatToolbarModule,
|
||||
MatTooltipModule,
|
||||
NgIf,
|
||||
NgFor,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
aria-label="Content Type"
|
||||
[value]="contentType"
|
||||
(change)="changeContentType($event.value)"
|
||||
hideSingleSelectionIndicator
|
||||
>
|
||||
<mat-button-toggle
|
||||
*ngFor="
|
||||
@@ -23,10 +24,19 @@
|
||||
</mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
|
||||
<button mat-button (click)="favoritesClicked.emit()">
|
||||
<mat-icon>star</mat-icon>
|
||||
<span class="button-label">{{ 'CHANNELS.FAVORITES' | translate }}</span>
|
||||
</button>
|
||||
<div>
|
||||
<button mat-button (click)="openPlaylistDetails()">
|
||||
<mat-icon>info</mat-icon>
|
||||
<span class="button-label">{{ 'Info' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button mat-button (click)="favoritesClicked.emit()">
|
||||
<mat-icon>star</mat-icon>
|
||||
<span class="button-label">{{
|
||||
'CHANNELS.FAVORITES' | translate
|
||||
}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="sub-panel">
|
||||
<div class="breadcrumbs">
|
||||
@@ -41,12 +51,15 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="search" *ngIf="searchVisible">
|
||||
<input
|
||||
class="search-input"
|
||||
placeholder="Search by name"
|
||||
type="search"
|
||||
[ngModel]="searchPhrase()"
|
||||
(ngModelChange)="searchPhraseUpdate.next($event)"
|
||||
/>
|
||||
<mat-form-field class="search-input">
|
||||
<mat-icon matPrefix>search</mat-icon>
|
||||
<input
|
||||
matInput
|
||||
placeholder="Search by name"
|
||||
type="search"
|
||||
[ngModel]="searchPhrase()"
|
||||
(ngModelChange)="searchPhraseUpdate.next($event)"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,3 +1,5 @@
|
||||
@use '@angular/material' as mat;
|
||||
|
||||
:host {
|
||||
position: relative;
|
||||
}
|
||||
@@ -40,31 +42,36 @@
|
||||
|
||||
.search {
|
||||
text-align: center;
|
||||
|
||||
.search-input {
|
||||
padding: 6px 8px 6px 40px;
|
||||
width: 250px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #333;
|
||||
color: #000;
|
||||
background: #ccc url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' class='bi bi-search' viewBox='0 0 16 16'%3E%3Cpath d='M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z'%3E%3C/path%3E%3C/svg%3E") no-repeat 13px center;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-input {
|
||||
@include mat.form-field-density(-5);
|
||||
}
|
||||
|
||||
/* stylelint-disable-next-line no-descending-specificity */
|
||||
::ng-deep {
|
||||
|
||||
.search-input {
|
||||
div {
|
||||
border-radius: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.dark-theme {
|
||||
#navigation,
|
||||
#sub-panel {
|
||||
background: black;
|
||||
background: #1b1c1c;
|
||||
}
|
||||
|
||||
#sub-panel {
|
||||
border-bottom: 1px solid #333;
|
||||
}
|
||||
}
|
||||
|
||||
div[matformfieldlineripple] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
|
||||
@@ -3,10 +3,16 @@ import { Component, EventEmitter, Input, Output, inject } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { Subject, debounceTime, distinctUntilChanged } from 'rxjs';
|
||||
import { PlaylistInfoComponent } from '../../home/recent-playlists/playlist-info/playlist-info.component';
|
||||
import { selectCurrentPlaylist } from '../../state/selectors';
|
||||
import { Breadcrumb } from '../breadcrumb.interface';
|
||||
import { ContentTypeNavigationItem } from '../content-type-navigation-item.interface';
|
||||
import { ContentType } from '../content-type.enum';
|
||||
@@ -22,6 +28,8 @@ import { PortalStore } from '../portal.store';
|
||||
MatButtonModule,
|
||||
MatButtonToggleModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
NgFor,
|
||||
NgIf,
|
||||
RouterLink,
|
||||
@@ -42,9 +50,12 @@ export class NavigationBarComponent {
|
||||
@Output() searchTextChanged = new EventEmitter<string>();
|
||||
|
||||
ContentTypeEnum = ContentType;
|
||||
dialog = inject(MatDialog);
|
||||
portalStore = inject(PortalStore);
|
||||
store = inject(Store);
|
||||
searchPhrase = this.portalStore.searchPhrase;
|
||||
searchPhraseUpdate = new Subject<string>();
|
||||
currentPlaylist = this.store.selectSignal(selectCurrentPlaylist);
|
||||
|
||||
constructor() {
|
||||
this.searchPhraseUpdate
|
||||
@@ -54,6 +65,12 @@ export class NavigationBarComponent {
|
||||
});
|
||||
}
|
||||
|
||||
openPlaylistDetails() {
|
||||
this.dialog.open(PlaylistInfoComponent, {
|
||||
data: this.currentPlaylist(),
|
||||
});
|
||||
}
|
||||
|
||||
processBreadcrumbClick(item: Breadcrumb) {
|
||||
this.setSearchText('');
|
||||
this.breadcrumbClicked.emit(item);
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
@use 'sass:map';
|
||||
@use '@angular/material' as mat;
|
||||
@use 'styles' ;
|
||||
|
||||
@include mat.core();
|
||||
|
||||
$my-typography: mat.m2-define-typography-config();
|
||||
@include mat.typography-hierarchy($my-typography);
|
||||
|
||||
// Note: Color palettes are generated from primary: #ffffff
|
||||
$_palettes: (
|
||||
primary: (
|
||||
0: #000000,
|
||||
10: #1a1c1c,
|
||||
20: #2f3131,
|
||||
25: #3a3c3c,
|
||||
30: #454747,
|
||||
35: #515353,
|
||||
40: #5d5f5f,
|
||||
50: #767777,
|
||||
60: #909191,
|
||||
70: #aaabab,
|
||||
80: #c6c6c7,
|
||||
90: #e2e2e2,
|
||||
95: #f0f1f1,
|
||||
98: #f9f9f9,
|
||||
99: #fcfcfc,
|
||||
100: #ffffff,
|
||||
),
|
||||
secondary: (
|
||||
0: #000000,
|
||||
10: #1b1c1c,
|
||||
20: #303030,
|
||||
25: #3b3b3b,
|
||||
30: #474747,
|
||||
35: #525252,
|
||||
40: #5e5e5e,
|
||||
50: #777777,
|
||||
60: #919090,
|
||||
70: #acabab,
|
||||
80: #c8c6c6,
|
||||
90: #e4e2e2,
|
||||
95: #f2f0f0,
|
||||
98: #fbf9f8,
|
||||
99: #fefcfb,
|
||||
100: #ffffff,
|
||||
),
|
||||
tertiary: (
|
||||
0: #000000,
|
||||
10: #1a1c1c,
|
||||
20: #2f3131,
|
||||
25: #3a3c3c,
|
||||
30: #454747,
|
||||
35: #515353,
|
||||
40: #5d5f5f,
|
||||
50: #767777,
|
||||
60: #909191,
|
||||
70: #aaabab,
|
||||
80: #c6c6c7,
|
||||
90: #e2e2e2,
|
||||
95: #f0f1f1,
|
||||
98: #f9f9f9,
|
||||
99: #fcfcfc,
|
||||
100: #ffffff,
|
||||
),
|
||||
neutral: (
|
||||
0: #000000,
|
||||
10: #1b1c1c,
|
||||
20: #313030,
|
||||
25: #3c3b3b,
|
||||
30: #474646,
|
||||
35: #535252,
|
||||
40: #5f5e5e,
|
||||
50: #787776,
|
||||
60: #929090,
|
||||
70: #adabaa,
|
||||
80: #c9c6c5,
|
||||
90: #e5e2e1,
|
||||
95: #f4f0ef,
|
||||
98: #fcf8f8,
|
||||
99: #f6feff,
|
||||
100: #ffffff,
|
||||
4: #0e0e0e,
|
||||
6: #141313,
|
||||
12: #201f1f,
|
||||
17: #2a2a2a,
|
||||
22: #353434,
|
||||
24: #3a3939,
|
||||
87: #ddd9d9,
|
||||
92: #ebe7e7,
|
||||
94: #f1edec,
|
||||
96: #f6f3f2,
|
||||
),
|
||||
neutral-variant: (
|
||||
0: #000000,
|
||||
10: #181c1d,
|
||||
20: #2d3132,
|
||||
25: #383c3d,
|
||||
30: #444748,
|
||||
35: #4f5354,
|
||||
40: #5b5f60,
|
||||
50: #747878,
|
||||
60: #8e9192,
|
||||
70: #a8acac,
|
||||
80: #c4c7c8,
|
||||
90: #e0e3e3,
|
||||
95: #eef1f2,
|
||||
98: #f7fafa,
|
||||
99: #fafdfd,
|
||||
100: #ffffff,
|
||||
),
|
||||
error: (
|
||||
0: #000000,
|
||||
10: #410002,
|
||||
20: #690005,
|
||||
25: #7e0007,
|
||||
30: #93000a,
|
||||
35: #a80710,
|
||||
40: #ba1a1a,
|
||||
50: #de3730,
|
||||
60: #ff5449,
|
||||
70: #ff897d,
|
||||
80: #ffb4ab,
|
||||
90: #ffdad6,
|
||||
95: #ffedea,
|
||||
98: #fff8f7,
|
||||
99: #fffbff,
|
||||
100: #ffffff,
|
||||
),
|
||||
);
|
||||
|
||||
$_rest: (
|
||||
secondary: map.get($_palettes, secondary),
|
||||
neutral: map.get($_palettes, neutral),
|
||||
neutral-variant: map.get($_palettes, neutral-variant),
|
||||
error: map.get($_palettes, error),
|
||||
);
|
||||
$_primary: map.merge(map.get($_palettes, primary), $_rest);
|
||||
$_tertiary: map.merge(map.get($_palettes, tertiary), $_rest);
|
||||
|
||||
$light-theme: mat.define-theme((
|
||||
color: (
|
||||
theme-type: light,
|
||||
primary: $_primary,
|
||||
tertiary: $_tertiary,
|
||||
),
|
||||
));
|
||||
|
||||
$dark-theme: mat.define-theme((
|
||||
color: (
|
||||
theme-type: dark,
|
||||
primary: $_tertiary,
|
||||
tertiary: $_tertiary,
|
||||
),
|
||||
));
|
||||
|
||||
html {
|
||||
@include mat.all-component-themes($light-theme);
|
||||
|
||||
.dark-theme {
|
||||
@include mat.all-component-colors($dark-theme);
|
||||
}
|
||||
|
||||
/* // Apply the dark theme by default
|
||||
@include mat.core-theme($dark-theme);
|
||||
@include mat.button-theme($dark-theme);
|
||||
|
||||
// Apply the light theme only when the user prefers light themes.
|
||||
@media (prefers-color-scheme: light) {
|
||||
// Use the `-color` mixins to only apply color styles without reapplying the same
|
||||
// typography and density styles.
|
||||
@include mat.core-color($light-theme);
|
||||
@include mat.button-color($light-theme);
|
||||
} */
|
||||
}
|
||||
+4
-7
@@ -1,9 +1,6 @@
|
||||
@import '@angular/material/theming';
|
||||
@import 'themes/';
|
||||
// @import 'themes/';
|
||||
@import '@yangkghjh/videojs-aspect-ratio-panel/dist/videojs-aspect-ratio-panel.css';
|
||||
|
||||
@include mat-core();
|
||||
|
||||
body,
|
||||
html {
|
||||
user-select: none;
|
||||
@@ -44,12 +41,12 @@ textarea,
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.dark-theme .mat-expansion-panel,
|
||||
/* .dark-theme .mat-expansion-panel,
|
||||
.dark-theme .mat-drawer,
|
||||
.dark-theme .mat-app-background,
|
||||
.dark-theme.mat-app-background {
|
||||
background-color: #1d1d1d;
|
||||
}
|
||||
} */
|
||||
|
||||
.dark-theme {
|
||||
::-webkit-scrollbar {
|
||||
@@ -78,7 +75,7 @@ textarea,
|
||||
|
||||
.cet-container {
|
||||
.video-js {
|
||||
height: calc(100vh - 82px) !important;
|
||||
height: calc(100vh - 93px) !important;
|
||||
}
|
||||
|
||||
app-web-player-view > app-vjs-player > .video-js {
|
||||
|
||||
Reference in new issue
Block a user