mirror of
https://github.com/Myxelium/Bridge-Multi.git
synced 2026-04-09 05:09:39 +00:00
Add compact table and update themes
This commit is contained in:
@@ -1,11 +1,6 @@
|
|||||||
<app-search-bar />
|
<app-search-bar />
|
||||||
<div class="flex flex-1 overflow-hidden">
|
<div class="flex flex-1 overflow-hidden">
|
||||||
<div
|
<app-result-table #resultTable (rowClicked)="chartSidebar.onRowClicked($event)" />
|
||||||
#resultTableDiv
|
|
||||||
class="basis-2/3 flex-1 overflow-y-auto scrollbar scrollbar-w-2 scrollbar-h-2 scrollbar-track-base-300 scrollbar-thumb-neutral scrollbar-thumb-rounded-full"
|
|
||||||
(scroll)="resultTable.tableScrolled($event)">
|
|
||||||
<app-result-table #resultTable (rowClicked)="chartSidebar.onRowClicked($event)" />
|
|
||||||
</div>
|
|
||||||
<div class="basis-1/3 min-w-[310px] max-w-[512px]">
|
<div class="basis-1/3 min-w-[310px] max-w-[512px]">
|
||||||
<app-chart-sidebar #chartSidebar />
|
<app-chart-sidebar #chartSidebar />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,21 +1,9 @@
|
|||||||
import { AfterViewInit, Component, ElementRef, HostBinding, ViewChild } from '@angular/core'
|
import { Component, HostBinding } from '@angular/core'
|
||||||
|
|
||||||
import { SearchService } from 'src-angular/app/core/services/search.service'
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-browse',
|
selector: 'app-browse',
|
||||||
templateUrl: './browse.component.html',
|
templateUrl: './browse.component.html',
|
||||||
})
|
})
|
||||||
export class BrowseComponent implements AfterViewInit {
|
export class BrowseComponent {
|
||||||
@HostBinding('class.contents') contents = true
|
@HostBinding('class.contents') contents = true
|
||||||
|
|
||||||
@ViewChild('resultTableDiv', { static: true }) resultTableDiv: ElementRef
|
|
||||||
|
|
||||||
constructor(private searchService: SearchService) { }
|
|
||||||
|
|
||||||
ngAfterViewInit() {
|
|
||||||
this.searchService.newSearch.subscribe(() => {
|
|
||||||
this.resultTableDiv.nativeElement.scrollTop = 0
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,40 @@
|
|||||||
<table id="resultTable" class="table table-zebra table-pin-rows">
|
<div
|
||||||
<thead>
|
#resultTableDiv
|
||||||
<tr>
|
class="basis-2/3 flex-1 overflow-y-auto scrollbar scrollbar-w-2 scrollbar-h-2 scrollbar-track-base-300 scrollbar-thumb-neutral scrollbar-thumb-rounded-full"
|
||||||
<th class="collapsing" id="checkboxColumn">
|
(scroll)="tableScrolled()">
|
||||||
<input type="checkbox" class="checkbox" [(ngModel)]="allSelected" />
|
<table id="resultTable" class="table table-zebra table-pin-rows" [class.table-xs]="settingsService.isCompactTable">
|
||||||
</th>
|
<thead>
|
||||||
<th [ngClass]="sortDirection" (click)="onColClicked('name')">
|
<tr>
|
||||||
Name <i *ngIf="sortColumn === 'name'" class="bi bi-caret-{{ sortDirection === 'ascending' ? 'down' : 'up' }}-fill"></i>
|
<th class="collapsing" id="checkboxColumn">
|
||||||
</th>
|
<input type="checkbox" class="checkbox" [(ngModel)]="allSelected" />
|
||||||
<th [ngClass]="sortDirection" (click)="onColClicked('artist')">
|
</th>
|
||||||
Artist
|
<th [ngClass]="sortDirection" (click)="onColClicked('name')">
|
||||||
<i *ngIf="sortColumn === 'artist'" class="bi bi-caret-{{ sortDirection === 'ascending' ? 'down' : 'up' }}-fill"></i>
|
Name <i *ngIf="sortColumn === 'name'" class="bi bi-caret-{{ sortDirection === 'ascending' ? 'down' : 'up' }}-fill"></i>
|
||||||
</th>
|
</th>
|
||||||
<th [ngClass]="sortDirection" (click)="onColClicked('album')">
|
<th [ngClass]="sortDirection" (click)="onColClicked('artist')">
|
||||||
Album <i *ngIf="sortColumn === 'album'" class="bi bi-caret-{{ sortDirection === 'ascending' ? 'down' : 'up' }}-fill"></i>
|
Artist
|
||||||
</th>
|
<i *ngIf="sortColumn === 'artist'" class="bi bi-caret-{{ sortDirection === 'ascending' ? 'down' : 'up' }}-fill"></i>
|
||||||
<th [ngClass]="sortDirection" (click)="onColClicked('genre')">
|
</th>
|
||||||
Genre <i *ngIf="sortColumn === 'genre'" class="bi bi-caret-{{ sortDirection === 'ascending' ? 'down' : 'up' }}-fill"></i>
|
<th [ngClass]="sortDirection" (click)="onColClicked('album')">
|
||||||
</th>
|
Album <i *ngIf="sortColumn === 'album'" class="bi bi-caret-{{ sortDirection === 'ascending' ? 'down' : 'up' }}-fill"></i>
|
||||||
<th [ngClass]="sortDirection" (click)="onColClicked('year')">
|
</th>
|
||||||
Year <i *ngIf="sortColumn === 'year'" class="bi bi-caret-{{ sortDirection === 'ascending' ? 'down' : 'up' }}-fill"></i>
|
<th [ngClass]="sortDirection" (click)="onColClicked('genre')">
|
||||||
</th>
|
Genre <i *ngIf="sortColumn === 'genre'" class="bi bi-caret-{{ sortDirection === 'ascending' ? 'down' : 'up' }}-fill"></i>
|
||||||
</tr>
|
</th>
|
||||||
</thead>
|
<th [ngClass]="sortDirection" (click)="onColClicked('year')">
|
||||||
<tbody>
|
Year <i *ngIf="sortColumn === 'year'" class="bi bi-caret-{{ sortDirection === 'ascending' ? 'down' : 'up' }}-fill"></i>
|
||||||
@for (song of songs; track song) {
|
</th>
|
||||||
<tr
|
</tr>
|
||||||
app-result-table-row
|
</thead>
|
||||||
(click)="onRowClicked(song)"
|
<tbody>
|
||||||
[class.!bg-neutral]="activeSong === song"
|
@for (song of songs; track song) {
|
||||||
[class.!text-neutral-content]="activeSong === song"
|
<tr
|
||||||
[song]="song"></tr>
|
app-result-table-row
|
||||||
}
|
(click)="onRowClicked(song)"
|
||||||
</tbody>
|
[class.!bg-neutral]="activeSong === song"
|
||||||
</table>
|
[class.!text-neutral-content]="activeSong === song"
|
||||||
|
[song]="song"></tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component, EventEmitter, HostBinding, OnInit, Output, QueryList, ViewChildren } from '@angular/core'
|
import { Component, ElementRef, EventEmitter, HostBinding, HostListener, OnInit, Output, QueryList, ViewChild, ViewChildren } from '@angular/core'
|
||||||
|
|
||||||
import { sortBy } from 'lodash'
|
import { sortBy } from 'lodash'
|
||||||
import { SettingsService } from 'src-angular/app/core/services/settings.service'
|
import { SettingsService } from 'src-angular/app/core/services/settings.service'
|
||||||
@@ -17,6 +17,7 @@ export class ResultTableComponent implements OnInit {
|
|||||||
|
|
||||||
@Output() rowClicked = new EventEmitter<ChartData[]>()
|
@Output() rowClicked = new EventEmitter<ChartData[]>()
|
||||||
|
|
||||||
|
@ViewChild('resultTableDiv', { static: true }) resultTableDiv: ElementRef
|
||||||
@ViewChildren('tableRow') tableRows: QueryList<ResultTableRowComponent>
|
@ViewChildren('tableRow') tableRows: QueryList<ResultTableRowComponent>
|
||||||
|
|
||||||
activeSong: ChartData[] | null = null
|
activeSong: ChartData[] | null = null
|
||||||
@@ -31,13 +32,16 @@ export class ResultTableComponent implements OnInit {
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.searchService.newSearch.subscribe(() => {
|
this.searchService.newSearch.subscribe(() => {
|
||||||
|
this.resultTableDiv.nativeElement.scrollTop = 0
|
||||||
this.activeSong = null
|
this.activeSong = null
|
||||||
this.sortDirection = 'ascending'
|
this.sortDirection = 'ascending'
|
||||||
this.sortColumn = null
|
this.sortColumn = null
|
||||||
this.updateSort()
|
this.updateSort()
|
||||||
|
setTimeout(() => this.tableScrolled(), 0)
|
||||||
})
|
})
|
||||||
this.searchService.updateSearch.subscribe(() => {
|
this.searchService.updateSearch.subscribe(() => {
|
||||||
this.updateSort()
|
this.updateSort()
|
||||||
|
setTimeout(() => this.tableScrolled(), 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,13 +89,16 @@ export class ResultTableComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tableScrolled(event: Event): void {
|
@HostListener('window:resize', ['$event'])
|
||||||
if (event.target instanceof HTMLElement) {
|
onResize() {
|
||||||
if (event.target.scrollHeight - (event.target.scrollTop + event.target.clientHeight) < 100) {
|
this.tableScrolled()
|
||||||
// Scrolled near the bottom of the table
|
}
|
||||||
if (this.searchService.areMorePages && !this.searchService.searchLoading) {
|
tableScrolled(): void {
|
||||||
this.searchService.search(this.searchService.searchControl.value || '*', true).subscribe()
|
const table = this.resultTableDiv.nativeElement
|
||||||
}
|
if (table.scrollHeight - (table.scrollTop + table.clientHeight) < 100) {
|
||||||
|
// Scrolled near the bottom of the table
|
||||||
|
if (this.searchService.areMorePages && !this.searchService.searchLoading) {
|
||||||
|
this.searchService.search(this.searchService.searchControl.value || '*', true).subscribe()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,8 +29,9 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li><a (click)="setTheme('business')">Business</a></li>
|
<li><a (click)="setTheme('business')">Business</a></li>
|
||||||
<li><a (click)="setTheme('dark')">Dark</a></li>
|
<li><a (click)="setTheme('dark')">Dark</a></li>
|
||||||
<li><a (click)="setTheme('halloween')">Halloween</a></li>
|
<li><a (click)="setTheme('dim')">Dim</a></li>
|
||||||
<li><a (click)="setTheme('night')">Night</a></li>
|
<li><a (click)="setTheme('night')">Night</a></li>
|
||||||
|
<li><a (click)="setTheme('sunset')">Sunset</a></li>
|
||||||
<li><a (click)="setTheme('synthwave')">Synthwave</a></li>
|
<li><a (click)="setTheme('synthwave')">Synthwave</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
@@ -40,6 +41,7 @@
|
|||||||
<li><a (click)="setTheme('aqua')">Aqua</a></li>
|
<li><a (click)="setTheme('aqua')">Aqua</a></li>
|
||||||
<li><a (click)="setTheme('emerald')">Emerald</a></li>
|
<li><a (click)="setTheme('emerald')">Emerald</a></li>
|
||||||
<li><a (click)="setTheme('lemonade')">Lemonade</a></li>
|
<li><a (click)="setTheme('lemonade')">Lemonade</a></li>
|
||||||
|
<li><a (click)="setTheme('nord')">Nord</a></li>
|
||||||
<li><a (click)="setTheme('valentine')">Valentine</a></li>
|
<li><a (click)="setTheme('valentine')">Valentine</a></li>
|
||||||
<li><a (click)="setTheme('winter')">Winter</a></li>
|
<li><a (click)="setTheme('winter')">Winter</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -94,17 +96,34 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<label class="label cursor-pointer">
|
<label class="label cursor-pointer">
|
||||||
<input type="radio" class="radio radio-secondary mr-2" [value]="true" [formControl]="isSng" />
|
<input type="radio" name="isSng" class="radio radio-secondary mr-2" [value]="true" [formControl]="isSng" />
|
||||||
.sng
|
.sng
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="label cursor-pointer">
|
<label class="label cursor-pointer">
|
||||||
<input type="radio" class="radio radio-secondary mr-2" [value]="false" [formControl]="isSng" />
|
<input type="radio" name="isSng" class="radio radio-secondary mr-2" [value]="false" [formControl]="isSng" />
|
||||||
.zip
|
.zip
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">Table Layout</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<label class="label cursor-pointer">
|
||||||
|
<input type="radio" name="isCompactTable" class="radio radio-secondary mr-2" [value]="false" [formControl]="isCompactTable" />
|
||||||
|
Default
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="label cursor-pointer">
|
||||||
|
<input type="radio" name="isCompactTable" class="radio radio-secondary mr-2" [value]="true" [formControl]="isCompactTable" />
|
||||||
|
Compact
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="absolute bottom-8 right-8 flex gap-6">
|
<div class="absolute bottom-8 right-8 flex gap-6">
|
||||||
<div class="join">
|
<div class="join">
|
||||||
<button *ngIf="updateAvailable" class="join-item btn btn-primary" (click)="downloadUpdate()">
|
<button *ngIf="updateAvailable" class="join-item btn btn-primary" (click)="downloadUpdate()">
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export class SettingsComponent implements OnInit {
|
|||||||
@ViewChild('themeDropdown', { static: true }) themeDropdown: ElementRef
|
@ViewChild('themeDropdown', { static: true }) themeDropdown: ElementRef
|
||||||
|
|
||||||
public isSng: FormControl<boolean>
|
public isSng: FormControl<boolean>
|
||||||
|
public isCompactTable: FormControl<boolean>
|
||||||
|
|
||||||
updateAvailable: boolean | null = false
|
updateAvailable: boolean | null = false
|
||||||
loginClicked = false
|
loginClicked = false
|
||||||
@@ -29,6 +30,8 @@ export class SettingsComponent implements OnInit {
|
|||||||
) {
|
) {
|
||||||
this.isSng = new FormControl<boolean>(settingsService.isSng, { nonNullable: true })
|
this.isSng = new FormControl<boolean>(settingsService.isSng, { nonNullable: true })
|
||||||
this.isSng.valueChanges.subscribe(value => settingsService.isSng = value)
|
this.isSng.valueChanges.subscribe(value => settingsService.isSng = value)
|
||||||
|
this.isCompactTable = new FormControl<boolean>(settingsService.isCompactTable, { nonNullable: true })
|
||||||
|
this.isCompactTable.valueChanges.subscribe(value => settingsService.isCompactTable = value)
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
|
|||||||
@@ -82,4 +82,12 @@ export class SettingsService {
|
|||||||
this.settings.isSng = value
|
this.settings.isSng = value
|
||||||
this.saveSettings()
|
this.saveSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isCompactTable() {
|
||||||
|
return this.settings.isCompactTable
|
||||||
|
}
|
||||||
|
set isCompactTable(value: boolean) {
|
||||||
|
this.settings.isCompactTable = value
|
||||||
|
this.saveSettings()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ import { Difficulty, Instrument } from 'scan-chart'
|
|||||||
export const themes = [
|
export const themes = [
|
||||||
'business',
|
'business',
|
||||||
'dark',
|
'dark',
|
||||||
'halloween',
|
'dim',
|
||||||
'night',
|
'night',
|
||||||
|
'sunset',
|
||||||
'synthwave',
|
'synthwave',
|
||||||
'aqua',
|
'aqua',
|
||||||
'emerald',
|
'emerald',
|
||||||
'lemonade',
|
'lemonade',
|
||||||
|
'nord',
|
||||||
'valentine',
|
'valentine',
|
||||||
'winter',
|
'winter',
|
||||||
'aren',
|
'aren',
|
||||||
@@ -23,6 +25,7 @@ export interface Settings {
|
|||||||
theme: typeof themes[number] // The name of the currently enabled UI theme
|
theme: typeof themes[number] // The name of the currently enabled UI theme
|
||||||
libraryPath: string | undefined // The path to the user's library
|
libraryPath: string | undefined // The path to the user's library
|
||||||
isSng: boolean // If the chart should be downloaded as a .sng file or as a chart folder
|
isSng: boolean // If the chart should be downloaded as a .sng file or as a chart folder
|
||||||
|
isCompactTable: boolean // If the search result table should have reduced padding
|
||||||
instrument: Instrument | null // The instrument selected by default, or `null` for "Any Instrument"
|
instrument: Instrument | null // The instrument selected by default, or `null` for "Any Instrument"
|
||||||
difficulty: Difficulty | null // The difficulty selected by default, or `null` for "Any Difficulty"
|
difficulty: Difficulty | null // The difficulty selected by default, or `null` for "Any Difficulty"
|
||||||
}
|
}
|
||||||
@@ -35,6 +38,7 @@ export const defaultSettings: Settings = {
|
|||||||
theme: 'dark',
|
theme: 'dark',
|
||||||
libraryPath: undefined,
|
libraryPath: undefined,
|
||||||
isSng: false,
|
isSng: false,
|
||||||
|
isCompactTable: false,
|
||||||
instrument: 'guitar',
|
instrument: 'guitar',
|
||||||
difficulty: null,
|
difficulty: null,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,12 +17,14 @@ module.exports = {
|
|||||||
themes: [
|
themes: [
|
||||||
'business',
|
'business',
|
||||||
'dark',
|
'dark',
|
||||||
'halloween',
|
'dim',
|
||||||
'night',
|
'night',
|
||||||
|
'sunset',
|
||||||
'synthwave',
|
'synthwave',
|
||||||
'aqua',
|
'aqua',
|
||||||
'emerald',
|
'emerald',
|
||||||
'lemonade',
|
'lemonade',
|
||||||
|
'nord',
|
||||||
'valentine',
|
'valentine',
|
||||||
'winter',
|
'winter',
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user