UI clutter cleanup and reorganization

This commit is contained in:
Alex Shnitman 2025-06-02 22:32:23 +03:00
parent d15ec69d23
commit 7ac542d25c
2 changed files with 162 additions and 72 deletions

View File

@ -1,6 +1,9 @@
<nav class="navbar navbar-expand-md navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">MeTube</a>
<a class="navbar-brand d-flex align-items-center" href="#">
<img src="assets/icons/android-chrome-192x192.png" alt="MeTube Logo" height="32" class="me-2">
MeTube
</a>
<!--
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsDefault" aria-controls="navbarsDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
@ -44,97 +47,173 @@
<main role="main" class="container container-xl">
<form #f="ngForm">
<div class="container add-url-box">
<div class="row">
<div class="col add-url-component input-group">
<input type="text" autocomplete="off" spellcheck="false" class="form-control" placeholder="Video or playlist URL" name="addUrl" [(ngModel)]="addUrl" [disabled]="addInProgress || downloads.loading">
<!-- Main URL Input with Download Button -->
<div class="row mb-4">
<div class="col">
<div class="input-group input-group-lg shadow-sm">
<input type="text"
autocomplete="off"
spellcheck="false"
class="form-control form-control-lg"
placeholder="Enter video or playlist URL"
name="addUrl"
[(ngModel)]="addUrl"
[disabled]="addInProgress || downloads.loading">
<button class="btn btn-primary btn-lg px-4"
type="submit"
(click)="addDownload()"
[disabled]="addInProgress || downloads.loading">
<span class="spinner-border spinner-border-sm" role="status" id="add-spinner" *ngIf="addInProgress"></span>
{{ addInProgress ? "Adding..." : "Download" }}
</button>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-lg-3 add-url-component">
<!-- Options Row -->
<div class="row mb-3 g-3">
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text">Quality</span>
<select class="form-select" name="quality" [(ngModel)]="quality" (change)="qualityChanged()" [disabled]="addInProgress || downloads.loading">
<select class="form-select"
name="quality"
[(ngModel)]="quality"
(change)="qualityChanged()"
[disabled]="addInProgress || downloads.loading">
<option *ngFor="let q of qualities" [ngValue]="q.id">{{ q.text }}</option>
</select>
</div>
</div>
<div class="col-md-6 col-lg-3 add-url-component">
<div class="col-md-4">
<div class="input-group">
<span class="input-group-text">Format</span>
<select class="form-select" name="format" [(ngModel)]="format" (change)="formatChanged()" [disabled]="addInProgress || downloads.loading">
<select class="form-select"
name="format"
[(ngModel)]="format"
(change)="formatChanged()"
[disabled]="addInProgress || downloads.loading">
<option *ngFor="let f of formats" [ngValue]="f.id">{{ f.text }}</option>
</select>
</div>
</div>
<div class="col-md-6 col-lg-3 add-url-component">
<div class="input-group">
<span class="input-group-text">Auto Start</span>
<select class="form-select" name="autoStart" [(ngModel)]="autoStart" (change)="autoStartChanged()" [disabled]="addInProgress || downloads.loading">
<option [ngValue]="true">Yes</option>
<option [ngValue]="false">No</option>
</select>
</div>
<div class="col-md-4">
<button type="button"
class="btn btn-outline-secondary w-100 h-100"
(click)="toggleAdvanced()">
Advanced Options
</button>
</div>
<div class="col-md-6 col-lg-3 add-url-component d-flex align-items-center">
<div [attr.class]="showAdvanced() ? 'btn-group add-url-group' : 'add-url-group'" ngbDropdown #advancedDropdown="ngbDropdown" display="dynamic" placement="bottom-end">
<button class="btn btn-primary add-url" type="submit" (click)="addDownload()" [disabled]="addInProgress || downloads.loading">
<span class="spinner-border spinner-border-sm" role="status" id="add-spinner" *ngIf="addInProgress"></span>
{{ addInProgress ? "Adding..." : "Add" }}
</button>
<button class="btn btn-primary dropdown-toggle dropdown-toggle-split" id="advancedButton" type="button" title="Advanced options" [disabled]="addInProgress || downloads.loading" ngbDropdownAnchor (click)="advancedDropdown.open()" *ngIf="showAdvanced()">
<span class="sr-only">Advanced options</span>
</button>
<div ngbDropdownMenu aria-labelledby="advancedButton" class="dropdown-menu dropdown-menu-end folder-dropdown-menu">
<div class="container">
<div class="input-group add-url-component">
<span class="input-group-text">Download Folder</span>
<ng-select [items]="customDirs$ | async" placeholder="Default" [addTag]="allowCustomDir.bind(this)" addTagText="Create directory" [ngStyle]="{'flex-grow':'1'}" bindLabel="folder" [(ngModel)]="folder" [disabled]="addInProgress || downloads.loading"></ng-select>
</div>
<!-- Advanced Options Panel -->
<div class="row">
<div class="col-12">
<div class="collapse show" id="advancedOptions" [ngbCollapse]="!isAdvancedOpen">
<div class="card card-body">
<!-- Advanced Settings -->
<div class="row g-3 mb-2">
<div class="col-md-6">
<div class="input-group">
<span class="input-group-text">Auto Start</span>
<select class="form-select"
name="autoStart"
[(ngModel)]="autoStart"
(change)="autoStartChanged()"
[disabled]="addInProgress || downloads.loading"
ngbTooltip="Automatically start downloads when added">
<option [ngValue]="true">Yes</option>
<option [ngValue]="false">No</option>
</select>
</div>
</div>
<div class="input-group add-url-component">
<span class="input-group-text">Custom Name Prefix</span>
<input type="text" autocomplete="off" spellcheck="false" class="form-control" placeholder="Default" name="customNamePrefix" [(ngModel)]="customNamePrefix" [disabled]="addInProgress || downloads.loading">
<div class="col-md-6">
<div class="input-group">
<span class="input-group-text">Download Folder</span>
<ng-select [items]="customDirs$ | async"
placeholder="Default"
[addTag]="allowCustomDir.bind(this)"
addTagText="Create directory"
bindLabel="folder"
[(ngModel)]="folder"
[disabled]="addInProgress || downloads.loading"
ngbTooltip="Choose where to save downloads. Type to create a new folder.">
</ng-select>
</div>
</div>
<div class="add-url-component">
<div class="row align-items-center gy-2">
<div class="col-12 col-md-6 order-md-2">
<div class="input-group">
<span class="input-group-text">Items limit</span>
<input type="number" min="0" autocomplete="off" class="form-control" placeholder="Default" name="playlistItemLimit" (keydown)="isNumber($event)" [(ngModel)]="playlistItemLimit" [disabled]="addInProgress || downloads.loading">
</div>
<div class="col-md-6">
<div class="input-group">
<span class="input-group-text">Custom Name Prefix</span>
<input type="text"
class="form-control"
placeholder="Default"
name="customNamePrefix"
[(ngModel)]="customNamePrefix"
[disabled]="addInProgress || downloads.loading"
ngbTooltip="Add a prefix to downloaded filenames">
</div>
</div>
<div class="col-md-6">
<div class="input-group">
<span class="input-group-text">Items Limit</span>
<input type="number"
min="0"
class="form-control"
placeholder="Default"
name="playlistItemLimit"
(keydown)="isNumber($event)"
[(ngModel)]="playlistItemLimit"
[disabled]="addInProgress || downloads.loading"
ngbTooltip="Maximum number of items to download from a playlist (0 = no limit)">
</div>
</div>
<div class="col-12">
<div class="form-check form-switch">
<input class="form-check-input"
type="checkbox"
role="switch"
name="playlistStrictMode"
[(ngModel)]="playlistStrictMode"
[disabled]="addInProgress || downloads.loading"
ngbTooltip="Only download playlists when URL explicitly points to a playlist">
<label class="form-check-label">Strict Playlist Mode</label>
</div>
</div>
</div>
<!-- Advanced Actions -->
<div class="row">
<div class="col-12">
<hr class="my-3">
<div class="row g-2">
<div class="col-md-4">
<button type="button"
class="btn btn-secondary w-100"
(click)="openBatchImportModal()">
<fa-icon [icon]="faFileImport" class="me-2"></fa-icon>
Import URLs
</button>
</div>
<div class="col-12 col-md-6 order-md-1">
<div class="input-group ms-1">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" name="playlistStrictMode" [(ngModel)]="playlistStrictMode" [disabled]="addInProgress || downloads.loading">
<label class="form-check-label">Strict Playlist mode</label>
</div>
</div>
<div class="col-md-4">
<button type="button"
class="btn btn-secondary w-100"
(click)="exportBatchUrls('all')">
<fa-icon [icon]="faFileExport" class="me-2"></fa-icon>
Export URLs
</button>
</div>
<div class="col-md-4">
<button type="button"
class="btn btn-secondary w-100"
(click)="copyBatchUrls('all')">
<fa-icon [icon]="faCopy" class="me-2"></fa-icon>
Copy URLs
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="btn-group ms-2" ngbDropdown>
<button type="button" class="btn btn-secondary" (click)="openBatchImportModal()">
Import
</button>
<button type="button" class="btn btn-secondary dropdown-toggle dropdown-toggle-split" ngbDropdownToggle>
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul ngbDropdownMenu class="dropdown-menu dropdown-menu-end">
<li>
<button class="dropdown-item" (click)="exportBatchUrls('all')">
Export All URLs
</button>
</li>
<li>
<button class="dropdown-item" (click)="copyBatchUrls('all')">
Copy All URLs
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
@ -267,7 +346,10 @@
</tbody>
</table>
</div>
<div class="footer text-center px-2">
<small *ngIf="versionInfo">{{ versionInfo }}</small>
</div>
</main><!-- /.container -->
<footer class="footer navbar-dark bg-dark py-3 mt-5">
<div class="container text-center">
<small class="text-light" *ngIf="versionInfo">{{ versionInfo }}</small>
</div>
</footer>

View File

@ -1,7 +1,7 @@
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { faTrashAlt, faCheckCircle, faTimesCircle, IconDefinition } from '@fortawesome/free-regular-svg-icons';
import { faRedoAlt, faSun, faMoon, faCircleHalfStroke, faCheck, faExternalLinkAlt, faDownload } from '@fortawesome/free-solid-svg-icons';
import { faRedoAlt, faSun, faMoon, faCircleHalfStroke, faCheck, faExternalLinkAlt, faDownload, faFileImport, faFileExport, faCopy } from '@fortawesome/free-solid-svg-icons';
import { CookieService } from 'ngx-cookie-service';
import { map, Observable, of } from 'rxjs';
@ -38,6 +38,7 @@ export class AppComponent implements AfterViewInit {
importInProgress = false;
cancelImportFlag = false;
versionInfo: string | null = null;
isAdvancedOpen = false;
@ViewChild('queueMasterCheckbox') queueMasterCheckbox: MasterCheckboxComponent;
@ViewChild('queueDelSelected') queueDelSelected: ElementRef;
@ -59,6 +60,9 @@ export class AppComponent implements AfterViewInit {
faCircleHalfStroke = faCircleHalfStroke;
faDownload = faDownload;
faExternalLinkAlt = faExternalLinkAlt;
faFileImport = faFileImport;
faFileExport = faFileExport;
faCopy = faCopy;
constructor(public downloads: DownloadsService, private cookieService: CookieService, private http: HttpClient) {
this.format = cookieService.get('metube_format') || 'any';
@ -451,4 +455,8 @@ export class AppComponent implements AfterViewInit {
}
});
}
toggleAdvanced() {
this.isAdvancedOpen = !this.isAdvancedOpen;
}
}