fix linting

This commit is contained in:
2026-03-15 22:23:58 +01:00
parent 67884e4638
commit 2d4f1ee314
50 changed files with 986 additions and 1430 deletions

View File

@@ -3,4 +3,3 @@
<div [@fader]="o.isActivated ? o.activatedRoute : ''" class="content"> <div [@fader]="o.isActivated ? o.activatedRoute : ''" class="content">
<router-outlet #o="outlet"></router-outlet> <router-outlet #o="outlet"></router-outlet>
</div> </div>

View File

@@ -4,10 +4,7 @@
<div class="text"> <div class="text">
<div class="welcome">WILLKOMMEN</div> <div class="welcome">WILLKOMMEN</div>
<div class="name">{{ user.name }}</div> <div class="name">{{ user.name }}</div>
<div class="roles"> <div class="roles">Es wurden noch keine Berechtigungen zugeteilt, bitte wende Dich an den Administrator!</div>
Es wurden noch keine Berechtigungen zugeteilt, bitte wende Dich an den
Administrator!
</div>
</div> </div>
} }
</div> </div>

View File

@@ -7,22 +7,17 @@
<div class="view"> <div class="view">
<swiper-container scrollbar="true"> <swiper-container scrollbar="true">
@for (song of show.songs; track trackBy(i, song); let i = $index) { @for (song of show.songs; track trackBy(i, song); let i = $index) {
<swiper-slide <swiper-slide class="song-swipe">
class="song-swipe">
<div class="song-title">{{ song.title }}</div> <div class="song-title">{{ song.title }}</div>
<div class="legal"> <div class="legal">
@if (song.artist) { @if (song.artist) {
<p>{{ song.artist }}</p> <p>{{ song.artist }}</p>
} }
</div> </div>
<app-song-text <app-song-text [text]="song.text"></app-song-text>
[text]="song.text"
></app-song-text>
</swiper-slide> </swiper-slide>
} }
</swiper-container> </swiper-container>
</div> </div>
</div> </div>
} }

View File

@@ -1,27 +1,17 @@
@if (song) { @if (song) { @if (song.artist) {
@if (song.artist) {
<p>{{ song.artist }}</p> <p>{{ song.artist }}</p>
} } @if (song.label) {
@if (song.label) {
<p>{{ song.label }}</p> <p>{{ song.label }}</p>
} } @if (song.termsOfUse) {
@if (song.termsOfUse) {
<p class="terms-of-use">{{ song.termsOfUse }}</p> <p class="terms-of-use">{{ song.termsOfUse }}</p>
} } @if (song.origin) {
@if (song.origin) {
<p>{{ song.origin }}</p> <p>{{ song.origin }}</p>
} } @if (song.legalOwnerId) {
@if (song.legalOwnerId) {
<div> <div>
@if (song.legalOwner === 'CCLI' && config) { @if (song.legalOwner === 'CCLI' && config) {
<p> <p>CCLI-Liednummer {{ song.legalOwnerId }}, CCLI-Lizenznummer {{ config.ccliLicenseId }}</p>
CCLI-Liednummer {{ song.legalOwnerId }}, CCLI-Lizenznummer } @if (song.legalOwner !== 'CCLI') {
{{ config.ccliLicenseId }}
</p>
}
@if (song.legalOwner !== 'CCLI') {
<p>Liednummer {{ song.legalOwnerId }}</p> <p>Liednummer {{ song.legalOwnerId }}</p>
} }
</div> </div>
} } }
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -20,14 +20,12 @@
<div>{{ showType | showType }}</div> <div>{{ showType | showType }}</div>
<div class="date">{{ date | date: "dd.MM.yyyy" }}</div> <div class="date">{{ date | date: "dd.MM.yyyy" }}</div>
</div> </div>
} } @if (songId === 'dynamicText') {
@if (songId === 'dynamicText') {
<div @songSwitch class="start fullscreen dynamic-text"> <div @songSwitch class="start fullscreen dynamic-text">
<div>{{ presentationDynamicCaption }}</div> <div>{{ presentationDynamicCaption }}</div>
<div class="date">{{ presentationDynamicText }}</div> <div class="date">{{ presentationDynamicText }}</div>
</div> </div>
} } @if (song && songId !== 'title' && songId !== 'empty' && songId !== 'dynamicText') {
@if (song && songId !== 'title' && songId !== 'empty' && songId !== 'dynamicText') {
<app-song-text <app-song-text
[@songSwitch]="songId" [@songSwitch]="songId"
[fullscreen]="true" [fullscreen]="true"
@@ -38,13 +36,8 @@
[text]="song.text" [text]="song.text"
chordMode="hide" chordMode="hide"
></app-song-text> ></app-song-text>
} } @if (song && songId !== 'title' && songId !== 'empty' && songId !== 'dynamicText') {
@if (song && songId !== 'title' && songId !== 'empty' && songId !== 'dynamicText') { <app-legal [@songSwitch]="songId" [config]="config$ | async" [song]="song"></app-legal>
<app-legal
[@songSwitch]="songId"
[config]="config$ | async"
[song]="song"
></app-legal>
} }
</div> </div>
} }

View File

@@ -1,23 +1,14 @@
@if (show) { @if (show) {
<div @fade> <div @fade>
<app-card [closeIcon]="faIcon" [heading]="show.showType | showType" <app-card [closeIcon]="faIcon" [heading]="show.showType | showType" [subheading]="show.date.toDate() | date:'dd.MM.yyyy'" closeLink="/presentation/select">
[subheading]="show.date.toDate() | date:'dd.MM.yyyy'" closeLink="/presentation/select">
@if (!progress) { @if (!progress) {
<div class="song"> <div class="song">
@if (show) { @if (show) {
<div class="song-parts"> <div class="song-parts">
<div <div (click)="onSectionClick('title', -1, show.id)" [class.active]="show.presentationSongId === 'title'" class="song-part">
(click)="onSectionClick('title', -1, show.id)"
[class.active]="show.presentationSongId === 'title'"
class="song-part"
>
<div class="head">Veranstaltung</div> <div class="head">Veranstaltung</div>
</div> </div>
<div <div (click)="onSectionClick('empty', -1, show.id)" [class.active]="show.presentationSongId === 'empty'" class="song-part">
(click)="onSectionClick('empty', -1, show.id)"
[class.active]="show.presentationSongId === 'empty'"
class="song-part"
>
<div class="head">Leer</div> <div class="head">Leer</div>
</div> </div>
</div> </div>
@@ -26,16 +17,10 @@
@for (song of presentationSongs; track trackBy($index, song)) { @for (song of presentationSongs; track trackBy($index, song)) {
<div class="song"> <div class="song">
@if (show) { @if (show) {
<div <div [class.active]="show.presentationSongId === song.id" class="title song-part">
[class.active]="show.presentationSongId === song.id" <div (click)="onSectionClick(song.id, -1, show.id)" class="head">{{ song.title }}</div>
class="title song-part"
>
<div (click)="onSectionClick(song.id, -1, show.id)" class="head">
{{ song.title }}
</div> </div>
</div> } @if (show) {
}
@if (show) {
<div class="song-parts"> <div class="song-parts">
@for (section of song.sections; track section.type + '-' + section.number + '-' + $index; let i = $index) { @for (section of song.sections; track section.type + '-' + section.number + '-' + $index; let i = $index) {
<div <div
@@ -46,9 +31,7 @@
" "
class="song-part" class="song-part"
> >
<div class="head"> <div class="head">{{ section.type | sectionType }} {{ section.number + 1 }}</div>
{{ section.type | sectionType }} {{ section.number + 1 }}
</div>
<div class="fragment">{{ getFirstLine(section) }}</div> <div class="fragment">{{ getFirstLine(section) }}</div>
</div> </div>
} }
@@ -58,27 +41,17 @@
} }
<div class="song"> <div class="song">
@if (show) { @if (show) {
<div <div [class.active]="show.presentationSongId === 'dynamicText'" class="title song-part">
[class.active]="show.presentationSongId === 'dynamicText'" <div (click)="onSectionClick('dynamicText', -1, show.id)" class="head">Freier Text</div>
class="title song-part"
>
<div (click)="onSectionClick('dynamicText', -1, show.id)" class="head">
Freier Text
</div>
</div> </div>
} }
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Überschrift</mat-label> <mat-label>Überschrift</mat-label>
<input (ngModelChange)="onDynamicCaption($event, show.id)" [ngModel]="show.presentationDynamicCaption" <input (ngModelChange)="onDynamicCaption($event, show.id)" [ngModel]="show.presentationDynamicCaption" autocomplete="off" id="dynamic-caption" matInput type="text" />
autocomplete="off" id="dynamic-caption"
matInput
type="text">
</mat-form-field> </mat-form-field>
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Text</mat-label> <mat-label>Text</mat-label>
<textarea (ngModelChange)="onDynamicText($event, show.id)" [ngModel]="show.presentationDynamicText" <textarea (ngModelChange)="onDynamicText($event, show.id)" [ngModel]="show.presentationDynamicText" autocomplete="off" id="dynamic-text" matInput></textarea>
autocomplete="off" id="dynamic-text"
matInput></textarea>
</mat-form-field> </mat-form-field>
</div> </div>
@if (show) { @if (show) {
@@ -89,9 +62,7 @@
</button> </button>
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Hintergrund</mat-label> <mat-label>Hintergrund</mat-label>
<mat-select <mat-select (ngModelChange)="onBackground($event, show.id)" [ngModel]="show.presentationBackground">
(ngModelChange)="onBackground($event, show.id)"
[ngModel]="show.presentationBackground">
<mat-option value="none">kein Hintergrund</mat-option> <mat-option value="none">kein Hintergrund</mat-option>
<mat-option value="blue">Sternenhimmel</mat-option> <mat-option value="blue">Sternenhimmel</mat-option>
<mat-option value="green">Blätter</mat-option> <mat-option value="green">Blätter</mat-option>
@@ -100,29 +71,13 @@
<mat-option value="bible">Bibel</mat-option> <mat-option value="bible">Bibel</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-slider <mat-slider #slider [max]="100" [min]="10" [step]="2" class="zoom-slider" color="primary" ngDefaultControl
#slider ><input (ngModelChange)="onZoom($event, show.id)" [ngModel]="show.presentationZoom" matSliderThumb />
[max]="100"
[min]="10"
[step]="2"
class="zoom-slider"
color="primary"
ngDefaultControl
><input (ngModelChange)="onZoom($event, show.id)"
[ngModel]="show.presentationZoom"
matSliderThumb>
</mat-slider> </mat-slider>
</div> </div>
} } @if (show) {
@if (show) { <app-add-song [addedLive]="true" [showSongs]="showSongs" [show]="show" [songs]="songs$|async"></app-add-song>
<app-add-song } }
[addedLive]="true"
[showSongs]="showSongs"
[show]="show"
[songs]="songs$|async"
></app-add-song>
}
}
</app-card> </app-card>
</div> </div>
} }

View File

@@ -3,18 +3,13 @@
@if (visible) { @if (visible) {
<app-card heading="Bitte eine Veranstaltung auswählen"> <app-card heading="Bitte eine Veranstaltung auswählen">
@if (!shows.length) { @if (!shows.length) {
<p> <p>Es ist derzeit keine Veranstaltung vorhanden</p>
Es ist derzeit keine Veranstaltung vorhanden } @if (shows.length>0) {
</p>
}
@if (shows.length>0) {
<div class="list"> <div class="list">
@for (show of shows; track show.id) { @for (show of shows; track show.id) {
<button (click)="selectShow(show)" mat-stroked-button> <button (click)="selectShow(show)" mat-stroked-button>
<app-user-name [userId]="show.owner"></app-user-name> <app-user-name [userId]="show.owner"></app-user-name>
, , {{ show.showType | showType }}, {{ show.date.toDate() | date: "dd.MM.yyyy" }}
{{ show.showType | showType }},
{{ show.date.toDate() | date: "dd.MM.yyyy" }}
</button> </button>
} }
</div> </div>

View File

@@ -3,7 +3,5 @@
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button [mat-dialog-close]="false" mat-button>Abbrechen</button> <button [mat-dialog-close]="false" mat-button>Abbrechen</button>
<button [mat-dialog-close]="true" cdkFocusInitial mat-button> <button [mat-dialog-close]="true" cdkFocusInitial mat-button>Archivieren</button>
Archivieren
</button>
</div> </div>

View File

@@ -1,7 +1,5 @@
<div mat-dialog-content> <div mat-dialog-content>
<p> <p>Bitte melde die in dieser Veranstaltung verwendeten CCLI-Titel. Die Meldung ist Teil der CCLI-Lizenz und sorgt dafür, dass Songwriter und Verlage korrekt vergütet werden.</p>
Bitte melde die in dieser Veranstaltung verwendeten CCLI-Titel. Die Meldung ist Teil der CCLI-Lizenz und sorgt dafür, dass Songwriter und Verlage korrekt vergütet werden.
</p>
<p> <p>
Die Meldung erfolgt über Die Meldung erfolgt über
<a [href]="reportingUrl" rel="noreferrer" target="_blank">{{ reportingUrl }}</a>. <a [href]="reportingUrl" rel="noreferrer" target="_blank">{{ reportingUrl }}</a>.
@@ -38,7 +36,5 @@
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button [mat-dialog-close]="false" mat-button>Abbrechen</button> <button [mat-dialog-close]="false" mat-button>Abbrechen</button>
<button [mat-dialog-close]="true" cdkFocusInitial mat-button> <button [mat-dialog-close]="true" cdkFocusInitial mat-button>Alle CCLI-Titel wurden gemeldet</button>
Alle CCLI-Titel wurden gemeldet
</button>
</div> </div>

View File

@@ -1,13 +1,8 @@
<div mat-dialog-content> <div mat-dialog-content>
<a [href]="data.url">{{ data.url }}</a> <a [href]="data.url">{{ data.url }}</a>
<div [style.background-image]="'url('+qrCode+')'" alt="qrcode" class="qrcode"> <div [style.background-image]="'url('+qrCode+')'" alt="qrcode" class="qrcode"></div>
</div>
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button [mat-dialog-close]="true" cdkFocusInitial mat-button> <button [mat-dialog-close]="true" cdkFocusInitial mat-button>Schließen</button>
Schließen <button (click)="share()" mat-button>Teilen</button>
</button>
<button (click)="share()" mat-button>
Teilen
</button>
</div> </div>

View File

@@ -25,7 +25,7 @@ export class ShareDialogComponent {
const data = this.data; const data = this.data;
// eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
QRCode.toDataURL(data.url, { void QRCode.toDataURL(data.url, {
type: 'image/jpeg', type: 'image/jpeg',
quality: 0.92, quality: 0.92,
width: 1280, width: 1280,

View File

@@ -6,18 +6,12 @@
<mat-select formControlName="showType"> <mat-select formControlName="showType">
<mat-optgroup label="öffentlich"> <mat-optgroup label="öffentlich">
@for (key of showTypePublic; track key) { @for (key of showTypePublic; track key) {
<mat-option [value]="key">{{ <mat-option [value]="key">{{ key | showType }} </mat-option>
key | showType
}}
</mat-option>
} }
</mat-optgroup> </mat-optgroup>
<mat-optgroup label="privat"> <mat-optgroup label="privat">
@for (key of showTypePrivate; track key) { @for (key of showTypePrivate; track key) {
<mat-option [value]="key">{{ <mat-option [value]="key">{{ key | showType }} </mat-option>
key | showType
}}
</mat-option>
} }
</mat-optgroup> </mat-optgroup>
</mat-select> </mat-select>

View File

@@ -1,14 +1,10 @@
<div [formGroup]="filterFormGroup"> <div [formGroup]="filterFormGroup">
<div class="third"> <div class="third">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Zeitraum</mat-label> <mat-label>Zeitraum</mat-label>
<mat-select formControlName="time"> <mat-select formControlName="time">
@for (time of times; track time) { @for (time of times; track time) {
<mat-option [value]="time.key">{{ <mat-option [value]="time.key">{{ time.value }} </mat-option>
time.value
}}
</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@@ -18,10 +14,7 @@
<mat-select formControlName="owner"> <mat-select formControlName="owner">
<mat-option value="">Alle</mat-option> <mat-option value="">Alle</mat-option>
@for (owner of owners; track owner) { @for (owner of owners; track owner) {
<mat-option [value]="owner.key">{{ <mat-option [value]="owner.key">{{ owner.value }} </mat-option>
owner.value
}}
</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@@ -32,23 +25,16 @@
<mat-option value="">Alle</mat-option> <mat-option value="">Alle</mat-option>
<mat-optgroup label="öffentlich"> <mat-optgroup label="öffentlich">
@for (key of showTypePublic; track key) { @for (key of showTypePublic; track key) {
<mat-option [value]="key">{{ <mat-option [value]="key">{{ key | showType }} </mat-option>
key | showType
}}
</mat-option>
} }
</mat-optgroup> </mat-optgroup>
<mat-optgroup label="privat"> <mat-optgroup label="privat">
@for (key of showTypePrivate; track key) { @for (key of showTypePrivate; track key) {
<mat-option [value]="key">{{ <mat-option [value]="key">{{ key | showType }} </mat-option>
key | showType
}}
</mat-option>
} }
</mat-optgroup> </mat-optgroup>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
</div> </div>
<i>Anzahl der Suchergebnisse: {{ shows?.length ?? 0 }}</i> <i>Anzahl der Suchergebnisse: {{ shows?.length ?? 0 }}</i>

View File

@@ -7,12 +7,8 @@
</app-list-header> </app-list-header>
<ng-container *appRole="['leader']"> <ng-container *appRole="['leader']">
@if (privateShows$ | async; as shows) { @if (privateShows$ | async; as shows) { @if (shows.length > 0) {
@if (shows.length > 0) { <app-card [padding]="false" heading="Meine Veranstaltungen">
<app-card
[padding]="false"
heading="Meine Veranstaltungen"
>
@for (show of shows | sortBy: 'desc':'date'; track trackBy($index, show)) { @for (show of shows | sortBy: 'desc':'date'; track trackBy($index, show)) {
<app-list-item <app-list-item
[routerLink]="show.id" [routerLink]="show.id"
@@ -22,23 +18,14 @@
></app-list-item> ></app-list-item>
} }
</app-card> </app-card>
} } }
}
</ng-container> </ng-container>
@if (publicShows$ | async; as shows) { @if (publicShows$ | async; as shows) { @if (shows.length > 0) {
@if (shows.length > 0) { <app-card [padding]="false" heading="Veröffentlichte Veranstaltungen">
<app-card
[padding]="false"
heading="Veröffentlichte Veranstaltungen"
>
@for (show of shows | sortBy: 'desc':'date'; track trackBy($index, show)) { @for (show of shows | sortBy: 'desc':'date'; track trackBy($index, show)) {
<app-list-item <app-list-item [routerLink]="show.id" [show]="show"></app-list-item>
[routerLink]="show.id"
[show]="show"
></app-list-item>
} }
</app-card> </app-card>
} } }
}
</div> </div>

View File

@@ -34,11 +34,7 @@ export class ListComponent {
public showType$ = this.filter$.pipe(map((filterValues: FilterValues) => filterValues.showType)); public showType$ = this.filter$.pipe(map((filterValues: FilterValues) => filterValues.showType));
public shows$ = this.showService.list$(); public shows$ = this.showService.list$();
public privateShows$ = combineLatest([this.shows$, this.userService.user$]).pipe( public privateShows$ = combineLatest([this.shows$, this.userService.user$]).pipe(
map(([shows, user]) => map(([shows, user]) => shows.filter(show => show.owner === user?.id).filter(show => !show.published || show.reportedType === 'pending'))
shows
.filter(show => show.owner === user?.id)
.filter(show => !show.published || show.reportedType === 'pending')
)
); );
public queriedPublicShows$ = this.lastMonths$.pipe(switchMap(lastMonths => this.showService.listPublicSince$(lastMonths))); public queriedPublicShows$ = this.lastMonths$.pipe(switchMap(lastMonths => this.showService.listPublicSince$(lastMonths)));
public fallbackPublicShows$ = combineLatest([this.shows$, this.lastMonths$]).pipe( public fallbackPublicShows$ = combineLatest([this.shows$, this.lastMonths$]).pipe(

View File

@@ -6,18 +6,12 @@
<mat-select formControlName="showType"> <mat-select formControlName="showType">
<mat-optgroup label="öffentlich"> <mat-optgroup label="öffentlich">
@for (key of showTypePublic; track key) { @for (key of showTypePublic; track key) {
<mat-option [value]="key">{{ <mat-option [value]="key">{{ key | showType }} </mat-option>
key | showType
}}
</mat-option>
} }
</mat-optgroup> </mat-optgroup>
<mat-optgroup label="privat"> <mat-optgroup label="privat">
@for (key of showTypePrivate; track key) { @for (key of showTypePrivate; track key) {
<mat-option [value]="key">{{ <mat-option [value]="key">{{ key | showType }} </mat-option>
key | showType
}}
</mat-option>
} }
</mat-optgroup> </mat-optgroup>
</mat-select> </mat-select>

View File

@@ -16,11 +16,9 @@ describe('ShowService', () => {
beforeEach(async () => { beforeEach(async () => {
user$ = new BehaviorSubject<unknown>({id: 'user-1'}); user$ = new BehaviorSubject<unknown>({id: 'user-1'});
showDataServiceSpy = jasmine.createSpyObj<ShowDataService>( showDataServiceSpy = jasmine.createSpyObj<ShowDataService>('ShowDataService', ['read$', 'listPublicSince$', 'update', 'add'], {
'ShowDataService', list$: of(shows) as unknown as ShowDataService['list$'],
['read$', 'listPublicSince$', 'update', 'add'], });
{list$: of(shows) as unknown as ShowDataService['list$']}
);
showDataServiceSpy.read$.and.returnValue(of(shows[0])); showDataServiceSpy.read$.and.returnValue(of(shows[0]));
showDataServiceSpy.listPublicSince$.and.returnValue(of([shows[1]])); showDataServiceSpy.listPublicSince$.and.returnValue(of([shows[1]]));
showDataServiceSpy.update.and.resolveTo(); showDataServiceSpy.update.and.resolveTo();

View File

@@ -8,7 +8,8 @@
}} - {{ getStatus(show) }}" }} - {{ getStatus(show) }}"
> >
@if (!useSwiper) { @if (!useSwiper) {
<p class="show-meta">{{ show.public ? 'öffentliche' : 'geschlossene' }} Veranstaltung von <p class="show-meta">
{{ show.public ? 'öffentliche' : 'geschlossene' }} Veranstaltung von
<app-user-name [userId]="show.owner"></app-user-name> <app-user-name [userId]="show.owner"></app-user-name>
<ng-container *appOwner="show.owner"> <ng-container *appOwner="show.owner">
<app-badge [type]="getPublishedBadgeType(show)">{{ show.published | publishedType }}</app-badge> <app-badge [type]="getPublishedBadgeType(show)">{{ show.published | publishedType }}</app-badge>
@@ -25,22 +26,26 @@
} }
</div> </div>
<div [class.floating]="useSwiper"> <div [class.floating]="useSwiper">
<app-menu-button (click)="onZoomOut()" @fade [icon]="faZoomOut" class="btn-delete btn-icon" <app-menu-button (click)="onZoomOut()" @fade [icon]="faZoomOut" class="btn-delete btn-icon" matTooltip="Verkleinern"></app-menu-button>
matTooltip="Verkleinern"></app-menu-button> <app-menu-button (click)="onZoomIn()" @fade [icon]="faZoomIn" class="btn-delete btn-icon" matTooltip="Vergrößern"></app-menu-button>
<app-menu-button (click)="onZoomIn()" @fade [icon]="faZoomIn" class="btn-delete btn-icon" <app-menu-button
matTooltip="Vergrößern"></app-menu-button> (click)="useSwiper=!useSwiper;fullscreen(useSwiper)"
<app-menu-button (click)="useSwiper=!useSwiper;fullscreen(useSwiper)" @fade @fade
[icon]="useSwiper ? faRestore : faMaximize" class="btn-delete btn-icon" [icon]="useSwiper ? faRestore : faMaximize"
matTooltip="Vollbild"></app-menu-button> class="btn-delete btn-icon"
matTooltip="Vollbild"
></app-menu-button>
</div> </div>
</div> </div>
@if (showSongs && !useSwiper) { @if (showSongs && !useSwiper) {
<div (cdkDropListDropped)="drop($event, show)" <div
(cdkDropListDropped)="drop($event, show)"
[cdkDropListDisabled]="show.published || showText" [cdkDropListDisabled]="show.published || showText"
[style.--song-key-column-width]="getSongKeyColumnWidth(show)" [style.--song-key-column-width]="getSongKeyColumnWidth(show)"
[style.font-size]="textSize + 'em'" [style.font-size]="textSize + 'em'"
cdkDropList cdkDropList
class="song-list"> class="song-list"
>
@for (song of orderedShowSongs(show); track trackBy(i, song); let i = $index) { @for (song of orderedShowSongs(show); track trackBy(i, song); let i = $index) {
<div cdkDrag class="song-row"> <div cdkDrag class="song-row">
<app-song <app-song
@@ -55,91 +60,48 @@
</div> </div>
} }
</div> </div>
} } @if (useSwiper) {
@if (useSwiper) {
<swiper-container scrollbar="true"> <swiper-container scrollbar="true">
@for (song of orderedShowSongs(show); track trackBy(i, song); let i = $index) { @for (song of orderedShowSongs(show); track trackBy(i, song); let i = $index) {
<swiper-slide <swiper-slide [style.font-size]="textSize + 'em'" class="song-swipe">
[style.font-size]="textSize + 'em'" <app-song [fullscreen]="true" [index]="i" [showId]="showId" [showSong]="song" [showText]="true" [show]="show"></app-song>
class="song-swipe">
<app-song
[fullscreen]="true"
[index]="i"
[showId]="showId"
[showSong]="song"
[showText]="true"
[show]="show"
></app-song>
<div class="time">{{ currentTime | date: 'HH:mm' }}</div> <div class="time">{{ currentTime | date: 'HH:mm' }}</div>
@if (getNextSong(orderedShowSongs(show), i); as next) { @if (getNextSong(orderedShowSongs(show), i); as next) {
<div class="next-song">{{ next }} <div class="next-song">
{{ next }}
<fa-icon [icon]="faNextSong"></fa-icon> <fa-icon [icon]="faNextSong"></fa-icon>
</div> </div>
} }
</swiper-slide> </swiper-slide>
} }
</swiper-container> </swiper-container>
} } @if (songs$ | async; as songs) { @if (songs && !show.published && !useSwiper) {
@if (songs$ | async; as songs) { <app-add-song [showSongs]="showSongs" [show]="show" [songs]="songs"></app-add-song>
@if (songs && !show.published && !useSwiper) { } } @if (!useSwiper) {
<app-add-song
[showSongs]="showSongs"
[show]="show"
[songs]="songs"
></app-add-song>
}
}
@if (!useSwiper) {
<app-button-row> <app-button-row>
<ng-container *appRole="['leader']"> <ng-container *appRole="['leader']">
<ng-container *appOwner="show.owner"> <ng-container *appOwner="show.owner">
@if (!show.archived) { @if (!show.archived) {
<app-button (click)="onArchive(true)" [icon]="faBox"> <app-button (click)="onArchive(true)" [icon]="faBox"> Archivieren </app-button>
Archivieren } @if (show.archived) {
</app-button> <app-button (click)="onArchive(false)" [icon]="faBoxOpen"> Wiederherstellen </app-button>
} } @if (!show.published) {
@if (show.archived) { <app-button (click)="onPublish(show, true)" [icon]="faPublish"> Veröffentlichen </app-button>
<app-button (click)="onArchive(false)" [icon]="faBoxOpen"> } @if (show.published) {
Wiederherstellen <app-button (click)="onPublish(show, false)" [icon]="faUnpublish"> Veröffentlichung zurückziehen </app-button>
</app-button> } @if (show.published) {
} <app-button (click)="onShare(show)" [icon]="faShare"> Teilen </app-button>
@if (!show.published) { } @if (show.published && show.reportedType === 'pending') {
<app-button (click)="onPublish(show, true)" [icon]="faPublish"> <app-button (click)="onReport(show)" [icon]="faReport"> Melden </app-button>
Veröffentlichen } @if (!show.published) {
</app-button> <app-button (click)="onChange(show.id)" [icon]="faSliders"> Ändern </app-button>
}
@if (show.published) {
<app-button (click)="onPublish(show, false)" [icon]="faUnpublish">
Veröffentlichung zurückziehen
</app-button>
}
@if (show.published) {
<app-button (click)="onShare(show)" [icon]="faShare">
Teilen
</app-button>
}
@if (show.published && show.reportedType === 'pending') {
<app-button (click)="onReport(show)" [icon]="faReport">
Melden
</app-button>
}
@if (!show.published) {
<app-button (click)="onChange(show.id)" [icon]="faSliders">
Ändern
</app-button>
} }
</ng-container> </ng-container>
</ng-container> </ng-container>
<app-button [icon]="faDownload" [matMenuTriggerFor]="menu"> <app-button [icon]="faDownload" [matMenuTriggerFor]="menu"> Herunterladen </app-button>
Herunterladen
</app-button>
<mat-menu #menu="matMenu"> <mat-menu #menu="matMenu">
<app-button (click)="onDownload()" [icon]="faUser"> <app-button (click)="onDownload()" [icon]="faUser"> Ablauf für Lobpreisgruppe </app-button>
Ablauf für Lobpreisgruppe <app-button (click)="onDownloadHandout()" [icon]="faUsers"> Handout mit Copyright Infos </app-button>
</app-button>
<app-button (click)="onDownloadHandout()" [icon]="faUsers">
Handout mit Copyright Infos
</app-button>
</mat-menu> </mat-menu>
</app-button-row> </app-button-row>
} }

View File

@@ -188,7 +188,10 @@ export class ShowComponent implements OnInit, OnDestroy {
width: '350px', width: '350px',
}); });
dialogRef.afterClosed().pipe(take(1)).subscribe((archive: boolean) => { dialogRef
.afterClosed()
.pipe(take(1))
.subscribe((archive: boolean) => {
if (archive && this.showId != null) void this.setArchiveState(true); if (archive && this.showId != null) void this.setArchiveState(true);
}); });
} }
@@ -230,7 +233,10 @@ export class ShowComponent implements OnInit, OnDestroy {
data: {songs}, data: {songs},
}); });
dialogRef.afterClosed().pipe(take(1)).subscribe((reported: boolean) => { dialogRef
.afterClosed()
.pipe(take(1))
.subscribe((reported: boolean) => {
if (reported) { if (reported) {
void this.showService.update$(show.id, {reportedType: 'reported'}); void this.showService.update$(show.id, {reportedType: 'reported'});
} }

View File

@@ -5,21 +5,10 @@
<div class="key">{{ iSong.key }}</div> <div class="key">{{ iSong.key }}</div>
<div>{{ iSong.title }}</div> <div>{{ iSong.title }}</div>
</div> </div>
} } @if (!show.published && !fullscreen) {
@if (!show.published && !fullscreen) { <div class="song" [class.show-text-layout]="!!showText" [class.compact-layout]="!showText" [class.with-drag]="dragHandle && !edit">
<div
class="song"
[class.show-text-layout]="!!showText"
[class.compact-layout]="!showText"
[class.with-drag]="dragHandle && !edit"
>
@if (dragHandle && !edit) { @if (dragHandle && !edit) {
<button <button aria-label="Lied verschieben" cdkDragHandle class="drag-handle" type="button"></button>
aria-label="Lied verschieben"
cdkDragHandle
class="drag-handle"
type="button"
></button>
} }
<span class="title">{{ iSong.title }}</span> <span class="title">{{ iSong.title }}</span>
@if (!edit) { @if (!edit) {
@@ -31,28 +20,17 @@
<span>{{ iSong.key }}</span> <span>{{ iSong.key }}</span>
</div> </div>
</div> </div>
} } @if (!edit) {
@if (!edit) { <app-menu-button (click)="onEdit()" [icon]="faEdit" class="btn-edit btn-icon" matTooltip="Lied für diese Veranstaltung bearbeiten"></app-menu-button>
<app-menu-button (click)="onEdit()" [icon]="faEdit" class="btn-edit btn-icon" } @if (!edit) {
matTooltip="Lied für diese Veranstaltung bearbeiten"></app-menu-button> <app-menu-button (click)="onDelete()" [icon]="faDelete" class="btn-delete btn-icon" matTooltip="Lied aus Veranstaltung entfernen"></app-menu-button>
}
@if (!edit) {
<app-menu-button (click)="onDelete()" [icon]="faDelete" class="btn-delete btn-icon"
matTooltip="Lied aus Veranstaltung entfernen"></app-menu-button>
} }
</div> </div>
@if (!edit) { @if (!edit) {
<div <div aria-hidden="true" class="song select" [class.show-text-layout]="!!showText" [class.compact-layout]="!showText" [class.with-drag]="dragHandle">
aria-hidden="true"
class="song select"
[class.show-text-layout]="!!showText"
[class.compact-layout]="!showText"
[class.with-drag]="dragHandle"
>
@if (dragHandle) { @if (dragHandle) {
<span class="drag-handle-placeholder"></span> <span class="drag-handle-placeholder"></span>
} } @if (!showText) {
@if (!showText) {
<span class="keys"> <span class="keys">
<mat-form-field class="keys-select"> <mat-form-field class="keys-select">
<mat-select #option [formControl]="keyFormControl" tabIndex="-1"> <mat-select #option [formControl]="keyFormControl" tabIndex="-1">
@@ -78,29 +56,19 @@
<span class="btn-edit"></span> <span class="btn-edit"></span>
<span class="btn-delete"></span> <span class="btn-delete"></span>
</div> </div>
} } } @if (edit) {
}
@if (edit) {
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Songtext</mat-label> <mat-label>Songtext</mat-label>
<textarea [cdkTextareaAutosize]="true" <textarea [cdkTextareaAutosize]="true" [formControl]="editSongControl" class="edit" matInput matTooltip="Tonart ändern"></textarea>
[formControl]="editSongControl"
class="edit"
matInput
matTooltip="Tonart ändern"
></textarea>
</mat-form-field> </mat-form-field>
} } @if (edit) {
@if (edit) {
<div>Es wird nur der Liedtext für dieser Veranstaltung geändert.</div> <div>Es wird nur der Liedtext für dieser Veranstaltung geändert.</div>
} } @if (edit) {
@if (edit) {
<app-button-row> <app-button-row>
<app-button (click)="onSave()" [icon]="faSave">Speichern</app-button> <app-button (click)="onSave()" [icon]="faSave">Speichern</app-button>
<app-button (click)="onDiscard()" [icon]="faEraser">Verwerfen</app-button> <app-button (click)="onDiscard()" [icon]="faEraser">Verwerfen</app-button>
</app-button-row> </app-button-row>
} } @if (!edit && (showText)) {
@if (!edit && (showText)) {
<app-song-text <app-song-text
(chordModeChanged)="onChordModeChanged($event)" (chordModeChanged)="onChordModeChanged($event)"
[chordMode]="iSong.chordMode" [chordMode]="iSong.chordMode"

View File

@@ -10,10 +10,7 @@
<mat-select formControlName="type"> <mat-select formControlName="type">
<mat-option [value]="null">- kein Filter -</mat-option> <mat-option [value]="null">- kein Filter -</mat-option>
@for (type of types; track type) { @for (type of types; track type) {
<mat-option [value]="type">{{ <mat-option [value]="type">{{ type | songType }} </mat-option>
type | songType
}}
</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@@ -23,10 +20,7 @@
<mat-select formControlName="key"> <mat-select formControlName="key">
<mat-option [value]="null">- kein Filter -</mat-option> <mat-option [value]="null">- kein Filter -</mat-option>
@for (key of keys; track key) { @for (key of keys; track key) {
<mat-option [value]="key">{{ <mat-option [value]="key">{{ key | key }} </mat-option>
key | key
}}
</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@@ -36,10 +30,7 @@
<mat-select formControlName="legalType"> <mat-select formControlName="legalType">
<mat-option [value]="null">- kein Filter -</mat-option> <mat-option [value]="null">- kein Filter -</mat-option>
@for (key of legalType; track key) { @for (key of legalType; track key) {
<mat-option [value]="key">{{ <mat-option [value]="key">{{ key | legalType }} </mat-option>
key | legalType
}}
</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@@ -49,10 +40,7 @@
<mat-select formControlName="flag"> <mat-select formControlName="flag">
<mat-option [value]="null">- kein Filter -</mat-option> <mat-option [value]="null">- kein Filter -</mat-option>
@for (flag of getFlags(); track flag) { @for (flag of getFlags(); track flag) {
<mat-option [value]="flag">{{ <mat-option [value]="flag">{{ flag }} </mat-option>
flag
}}
</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>

View File

@@ -19,13 +19,11 @@
<div class="warning"> <div class="warning">
<fa-icon [icon]="faDraft"></fa-icon> <fa-icon [icon]="faDraft"></fa-icon>
</div> </div>
} } @if (song.status === 'set') {
@if (song.status === 'set') {
<div class="neutral"> <div class="neutral">
<fa-icon [icon]="faDraft"></fa-icon> <fa-icon [icon]="faDraft"></fa-icon>
</div> </div>
} } @if (song.status === 'final') {
@if (song.status === 'final') {
<div class="success"> <div class="success">
<fa-icon [icon]="faFinal"></fa-icon> <fa-icon [icon]="faFinal"></fa-icon>
</div> </div>

View File

@@ -2,13 +2,9 @@
@if (currentUpload) { @if (currentUpload) {
<div> <div>
<div class="progress"> <div class="progress">
<div <div [ngStyle]="{ width: currentUpload?.progress + '%' }" class="progress-bar progress-bar-animated"></div>
[ngStyle]="{ width: currentUpload?.progress + '%' }"
class="progress-bar progress-bar-animated"
></div>
</div> </div>
Progress: {{ currentUpload?.name }} | {{ currentUpload?.progress }}% Progress: {{ currentUpload?.name }} | {{ currentUpload?.progress }}% Complete
Complete
</div> </div>
} }
<div class="upload"> <div class="upload">
@@ -16,11 +12,7 @@
<input (change)="detectFiles($event)" type="file" /> <input (change)="detectFiles($event)" type="file" />
</label> </label>
<button <button (click)="uploadSingle()" [disabled]="!selectedFiles" mat-icon-button>
(click)="uploadSingle()"
[disabled]="!selectedFiles"
mat-icon-button
>
<mat-icon>cloud_upload</mat-icon> <mat-icon>cloud_upload</mat-icon>
</button> </button>
</div> </div>

View File

@@ -10,10 +10,7 @@
<mat-label>Typ</mat-label> <mat-label>Typ</mat-label>
<mat-select formControlName="type"> <mat-select formControlName="type">
@for (type of types; track type) { @for (type of types; track type) {
<mat-option [value]="type">{{ <mat-option [value]="type">{{ type | songType }} </mat-option>
type | songType
}}
</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@@ -21,10 +18,7 @@
<mat-label>Tonart</mat-label> <mat-label>Tonart</mat-label>
<mat-select formControlName="key"> <mat-select formControlName="key">
@for (key of keys; track key) { @for (key of keys; track key) {
<mat-option [value]="key">{{ <mat-option [value]="key">{{ key | key }} </mat-option>
key | key
}}
</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@@ -36,23 +30,14 @@
<mat-label>Status</mat-label> <mat-label>Status</mat-label>
<mat-select formControlName="status"> <mat-select formControlName="status">
@for (status of status; track status) { @for (status of status; track status) {
<mat-option [value]="status">{{ <mat-option [value]="status">{{ status | status }} </mat-option>
status | status
}}
</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
</div> </div>
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Songtext</mat-label> <mat-label>Songtext</mat-label>
<textarea <textarea (focus)="songtextFocus = true" (focusout)="songtextFocus = false" [cdkTextareaAutosize]="true" formControlName="text" matInput></textarea>
(focus)="songtextFocus = true"
(focusout)="songtextFocus = false"
[cdkTextareaAutosize]="true"
formControlName="text"
matInput
></textarea>
</mat-form-field> </mat-form-field>
@if (chordValidationIssues.length > 0) { @if (chordValidationIssues.length > 0) {
<div class="song-text-validation"> <div class="song-text-validation">
@@ -69,15 +54,13 @@
</div> </div>
} }
</div> </div>
} } @if (songtextFocus) {
@if (songtextFocus) {
<div class="song-text-help"> <div class="song-text-help">
<h3>Vorschau</h3> <h3>Vorschau</h3>
<app-song-text [text]="form.value.text" [validateChordNotation]="true" chordMode="show"></app-song-text> <app-song-text [text]="form.value.text" [validateChordNotation]="true" chordMode="show"></app-song-text>
<h3>Hinweise zur Bearbeitung</h3> <h3>Hinweise zur Bearbeitung</h3>
<h4>Aufbau</h4> <h4>Aufbau</h4>
Der Liedtext wird hintereinander weg geschrieben. Dabei werden Strophen, Der Liedtext wird hintereinander weg geschrieben. Dabei werden Strophen, Refrain und Bridge jeweils durch eine zusätzliche Zeile Markiert. z.B.
Refrain und Bridge jeweils durch eine zusätzliche Zeile Markiert. z.B.
<pre> <pre>
Strophe Strophe
Text der ersten Strophe Text der ersten Strophe
@@ -85,19 +68,19 @@
Text der zweiten Strophe Text der zweiten Strophe
Refrain Refrain
Und hier der Refrain Und hier der Refrain
</pre> </pre
>
<h3>Akkorde</h3> <h3>Akkorde</h3>
Die Akktorde werden jeweils in der Zeile über dem jeweiligen Liedtext Die Akktorde werden jeweils in der Zeile über dem jeweiligen Liedtext geschrieben. Sie werden jeweils durch Leerzeichen an die entsprechende Position gebracht. Bitte keine
geschrieben. Sie werden jeweils durch Leerzeichen an die entsprechende Tabulatoren verwenden! Folgende Schreibweisen sind erlaubt:
Position gebracht. Bitte keine Tabulatoren verwenden! Folgende
Schreibweisen sind erlaubt:
<pre> <pre>
Dur: C D E Dur: C D E
Moll: c d e Moll: c d e
Kreuz/B-Tonarten: C# f# Eb (Hb muss als B angegeben werden) Kreuz/B-Tonarten: C# f# Eb (Hb muss als B angegeben werden)
Basstöne: C/E D/C Basstöne: C/E D/C
Obertöne: c7 E9 f#maj7 Obertöne: c7 E9 f#maj7
</pre> </pre
>
Beispiel: Beispiel:
<pre> <pre>
Strophe Strophe
@@ -105,24 +88,18 @@
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
F# B Eb Cmaj7 C9 e F# B Eb Cmaj7 C9 e
sed diam nonumy eirmod tempor invidunt ut labore et dolore sed diam nonumy eirmod tempor invidunt ut labore et dolore
</pre> </pre
>
</div> </div>
} }
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Kommentar</mat-label> <mat-label>Kommentar</mat-label>
<textarea <textarea [cdkTextareaAutosize]="true" formControlName="comment" matInput></textarea>
[cdkTextareaAutosize]="true"
formControlName="comment"
matInput
></textarea>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-chip-grid #chipList> <mat-chip-grid #chipList>
@for (flag of flags; track flag) { @for (flag of flags; track flag) {
<mat-chip-row <mat-chip-row (removed)="removeFlag(flag)" [removable]="true">
(removed)="removeFlag(flag)"
[removable]="true"
>
{{ flag }}&nbsp; {{ flag }}&nbsp;
<fa-icon (click)="removeFlag(flag)" [icon]="faRemove"></fa-icon> <fa-icon (click)="removeFlag(flag)" [icon]="faRemove"></fa-icon>
</mat-chip-row> </mat-chip-row>
@@ -141,10 +118,7 @@
<mat-label>Rechtlicher Status</mat-label> <mat-label>Rechtlicher Status</mat-label>
<mat-select formControlName="legalType"> <mat-select formControlName="legalType">
@for (key of legalType; track key) { @for (key of legalType; track key) {
<mat-option [value]="key">{{ <mat-option [value]="key">{{ key | legalType }} </mat-option>
key | legalType
}}
</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@@ -152,10 +126,7 @@
<mat-label>Rechteinhaber</mat-label> <mat-label>Rechteinhaber</mat-label>
<mat-select formControlName="legalOwner"> <mat-select formControlName="legalOwner">
@for (key of legalOwner; track key) { @for (key of legalOwner; track key) {
<mat-option [value]="key">{{ <mat-option [value]="key">{{ key | legalOwner }} </mat-option>
key | legalOwner
}}
</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>

View File

@@ -4,7 +4,5 @@
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button [mat-dialog-close]="false" mat-button>Änderungen verwerfen</button> <button [mat-dialog-close]="false" mat-button>Änderungen verwerfen</button>
<button [mat-dialog-close]="true" cdkFocusInitial mat-button> <button [mat-dialog-close]="true" cdkFocusInitial mat-button>Speichern</button>
Speichern
</button>
</div> </div>

View File

@@ -1,3 +1 @@
<a [href]="url$ | async" target="_blank"> <a [href]="url$ | async" target="_blank"> {{ name }} </a>
{{ name }}
</a>

View File

@@ -1,9 +1,6 @@
<div class="split"> <div class="split">
@if (song$ | async; as song) { @if (song$ | async; as song) {
<app-card <app-card [heading]="song.number + ' - ' + song.title" closeLink="../">
[heading]="song.number + ' - ' + song.title"
closeLink="../"
>
<div class="song"> <div class="song">
<div> <div>
<div *appRole="['leader', 'contributor']" class="detail"> <div *appRole="['leader', 'contributor']" class="detail">
@@ -12,92 +9,47 @@
<div>Tempo: {{ song.tempo }}</div> <div>Tempo: {{ song.tempo }}</div>
<div>Status: {{ (song.status | status) || "entwurf" }}</div> <div>Status: {{ (song.status | status) || "entwurf" }}</div>
@if (song.legalOwner) { @if (song.legalOwner) {
<div>Rechteinhaber: {{ song.legalOwner | legalOwner }}</div>
} @if (song.legalOwnerId && song.legalOwner === 'CCLI') {
<div> <div>
Rechteinhaber: {{ song.legalOwner | legalOwner }} <a href="https://songselect.ccli.com/Songs/{{ song.legalOwnerId }}" target="_blank"> CCLI Nummer: {{ song.legalOwnerId }} </a>
</div> </div>
} } @if (song.legalOwnerId && song.legalOwner !== 'CCLI') {
@if (song.legalOwnerId && song.legalOwner === 'CCLI') { <div>Rechteinhaber ID: {{ song.legalOwnerId }}</div>
<div> } @if (song.artist) {
<a
href="https://songselect.ccli.com/Songs/{{ song.legalOwnerId }}"
target="_blank"
>
CCLI Nummer: {{ song.legalOwnerId }}
</a>
</div>
}
@if (song.legalOwnerId && song.legalOwner !== 'CCLI') {
<div>
Rechteinhaber ID: {{ song.legalOwnerId }}
</div>
}
@if (song.artist) {
<div>Künstler: {{ song.artist }}</div> <div>Künstler: {{ song.artist }}</div>
} } @if (song.label) {
@if (song.label) {
<div>Verlag: {{ song.label }}</div> <div>Verlag: {{ song.label }}</div>
} } @if (song.origin) {
@if (song.origin) {
<div>Quelle: {{ song.origin }}</div> <div>Quelle: {{ song.origin }}</div>
} }
<div <div [matTooltip]="songUsageTooltip$ | async" matTooltipPosition="above">Wie oft verwendet: {{ songCount$ | async }}</div>
[matTooltip]="songUsageTooltip$ | async"
matTooltipPosition="above"
>
Wie oft verwendet: {{ songCount$ | async }}
</div>
</div> </div>
</div> </div>
@if (user$ | async; as user) { @if (user$ | async; as user) {
<app-song-text <app-song-text [chordMode]="user.chordMode" [showSwitch]="true" [text]="song.text" [validateChordNotation]="true"></app-song-text>
[chordMode]="user.chordMode"
[showSwitch]="true"
[text]="song.text"
[validateChordNotation]="true"
></app-song-text>
} }
<mat-chip-listbox <mat-chip-listbox *appRole="['leader', 'contributor']" aria-label="Attribute">
*appRole="['leader', 'contributor']"
aria-label="Attribute"
>
@for (flag of getFlags(song.flags); track flag) { @for (flag of getFlags(song.flags); track flag) {
<mat-chip-option>{{ <mat-chip-option>{{ flag }} </mat-chip-option>
flag
}}
</mat-chip-option>
} }
</mat-chip-listbox> </mat-chip-listbox>
<div *appRole="['leader', 'contributor']" class="text"> <div *appRole="['leader', 'contributor']" class="text">{{ song.comment }}</div>
{{ song.comment }}
</div>
</div> </div>
<app-button-row> <app-button-row>
<app-button <app-button (click)="onDelete(song.id)" *appRole="['admin']" [icon]="faDelete">Löschen </app-button>
(click)="onDelete(song.id)" <app-button *appRole="['contributor']" [icon]="faEdit" routerLink="edit">Bearbeiten </app-button>
*appRole="['admin']"
[icon]="faDelete"
>Löschen
</app-button>
<app-button *appRole="['contributor']" [icon]="faEdit" routerLink="edit"
>Bearbeiten
</app-button>
<ng-container *appRole="['leader']"> <ng-container *appRole="['leader']">
<app-button [icon]="faFileCirclePlus" [matMenuTriggerFor]="menu"> <app-button [icon]="faFileCirclePlus" [matMenuTriggerFor]="menu"> Zu Veranstaltung hinzufügen </app-button>
Zu Veranstaltung hinzufügen
</app-button>
<mat-menu #menu="matMenu"> <mat-menu #menu="matMenu">
@for (show of privateShows$|async; track show.id) { @for (show of privateShows$|async; track show.id) {
<app-button (click)="addSongToShow(show, song)"> <app-button (click)="addSongToShow(show, song)"> {{ show.date.toDate() | date: "dd.MM.yyyy" }} {{ show.showType | showType }} </app-button>
{{ show.date.toDate() | date: "dd.MM.yyyy" }} {{ show.showType | showType }}
</app-button>
} }
</mat-menu> </mat-menu>
</ng-container> </ng-container>
</app-button-row> </app-button-row>
</app-card> </app-card>
} } @if (files$ | async; as files) { @if (files.length > 0) {
@if (files$ | async; as files) {
@if (files.length > 0) {
<app-card heading="Anhänge"> <app-card heading="Anhänge">
@for (file of files$ | async; track file.id) { @for (file of files$ | async; track file.id) {
<p> <p>
@@ -105,6 +57,5 @@
</p> </p>
} }
</app-card> </app-card>
} } }
}
</div> </div>

View File

@@ -2,30 +2,19 @@
<app-card heading="Hallo {{ user.name }}"> <app-card heading="Hallo {{ user.name }}">
<p> <p>
@if (getUserRoles(user.role).length === 0) { @if (getUserRoles(user.role).length === 0) {
<span class="warn" <span class="warn">Es wurden noch keine Berechtigungen zugeteilt, bitte wende Dich an den Administrator!</span>
>Es wurden noch keine Berechtigungen zugeteilt, bitte wende Dich an den
Administrator!</span
>
} }
<span>{{ transdormUserRoles(user.role) }}</span> <span>{{ transdormUserRoles(user.role) }}</span>
</p> </p>
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>bevorzugte Anzeige der Akkorde</mat-label> <mat-label>bevorzugte Anzeige der Akkorde</mat-label>
<mat-select <mat-select (ngModelChange)="onChordModeChanged(user.id, $event)" [ngModel]="user.chordMode">
(ngModelChange)="onChordModeChanged(user.id, $event)"
[ngModel]="user.chordMode"
>
<mat-option [value]="null"></mat-option> <mat-option [value]="null"></mat-option>
<mat-option value="hide">nur den Liedtext anzeigen</mat-option> <mat-option value="hide">nur den Liedtext anzeigen</mat-option>
<mat-option value="onlyFirst" <mat-option value="onlyFirst">in Strophen die Akkorde nur für die erste anzeigen </mat-option>
>in Strophen die Akkorde nur für die erste anzeigen
</mat-option>
<mat-option value="show">alle anzeigen</mat-option> <mat-option value="show">alle anzeigen</mat-option>
</mat-select> </mat-select>
<mat-hint <mat-hint>Das ist nur die Voreinstellung, die Anzeige kann für jedes Lied geändert werden. </mat-hint>
>Das ist nur die Voreinstellung, die Anzeige kann für jedes Lied geändert
werden.
</mat-hint>
</mat-form-field> </mat-form-field>
<app-button-row> <app-button-row>
<app-button [icon]="faSignOut" routerLink="../logout">Abmelden</app-button> <app-button [icon]="faSignOut" routerLink="../logout">Abmelden</app-button>

View File

@@ -6,16 +6,9 @@
</mat-form-field> </mat-form-field>
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Rolle</mat-label> <mat-label>Rolle</mat-label>
<mat-select <mat-select (ngModelChange)="onRoleChanged(id, $event)" [ngModel]="roles" multiple>
(ngModelChange)="onRoleChanged(id, $event)"
[ngModel]="roles"
multiple
>
@for (role of ROLE_TYPES; track role) { @for (role of ROLE_TYPES; track role) {
<mat-option [value]="role">{{ <mat-option [value]="role">{{ role | role }} </mat-option>
role | role
}}
</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@@ -23,9 +16,7 @@
<fa-icon [icon]="faClose"></fa-icon> <fa-icon [icon]="faClose"></fa-icon>
</button> </button>
</div> </div>
} } @if (!edit) {
@if (!edit) {
<div (click)="edit = true" class="users list-item"> <div (click)="edit = true" class="users list-item">
<span>{{ name }}</span> <span>{{ name }}</span>
<span <span

View File

@@ -9,34 +9,14 @@
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>Passwort</mat-label> <mat-label>Passwort</mat-label>
<input <input (keyup.enter)="onLogin()" formControlName="pass" matInput type="password" />
(keyup.enter)="onLogin()"
formControlName="pass"
matInput
type="password"
/>
</mat-form-field> </mat-form-field>
@if (errorMessage) { @if (errorMessage) {
<p class="error">{{ errorMessage | authMessage }}</p> <p class="error">{{ errorMessage | authMessage }}</p>
} }
<button <button (click)="onLogin()" class="btn-login" color="primary" mat-stroked-button>Anmelden</button>
(click)="onLogin()" <button class="btn-password" mat-stroked-button routerLink="/user/password">Passwort zurücksetzen</button>
class="btn-login" <button class="btn-user" mat-stroked-button routerLink="/user/new">neuen Benutzer anlegen</button>
color="primary"
mat-stroked-button
>
Anmelden
</button>
<button
class="btn-password"
mat-stroked-button
routerLink="/user/password"
>
Passwort zurücksetzen
</button>
<button class="btn-user" mat-stroked-button routerLink="/user/new">
neuen Benutzer anlegen
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -16,8 +16,6 @@
} }
<app-button-row> <app-button-row>
<app-button (click)="onCreate()" [icon]="faNewUser" <app-button (click)="onCreate()" [icon]="faNewUser">Benutzer anlegen </app-button>
>Benutzer anlegen
</app-button>
</app-button-row> </app-button-row>
</app-card> </app-card>

View File

@@ -1,4 +1 @@
<app-card> <app-card> Eine E-Mail mit dem neuen Passwort wurde gesendet. Darin ist der link enthalten, über den das neue Passwort eingegeben werden kann. </app-card>
Eine E-Mail mit dem neuen Passwort wurde gesendet. Darin ist der link
enthalten, über den das neue Passwort eingegeben werden kann.
</app-card>

View File

@@ -2,17 +2,11 @@
<div [formGroup]="form" class="form"> <div [formGroup]="form" class="form">
<mat-form-field appearance="outline"> <mat-form-field appearance="outline">
<mat-label>E-Mail Addresse</mat-label> <mat-label>E-Mail Addresse</mat-label>
<input <input (keyup.enter)="onResetPassword()" formControlName="user" matInput />
(keyup.enter)="onResetPassword()"
formControlName="user"
matInput
/>
</mat-form-field> </mat-form-field>
<app-button-row> <app-button-row>
<app-button (click)="onResetPassword()" [icon]="faNewPassword" <app-button (click)="onResetPassword()" [icon]="faNewPassword">neues Passwort anfordern </app-button>
>neues Passwort anfordern
</app-button>
@if (errorMessage) { @if (errorMessage) {
<p class="error">{{ errorMessage | authMessage }}</p> <p class="error">{{ errorMessage | authMessage }}</p>
} }

View File

@@ -36,6 +36,5 @@ export class UserService {
public incSongCount = (songId: string): Promise<void | null> => this.songUsage.incSongCount(songId); public incSongCount = (songId: string): Promise<void | null> => this.songUsage.incSongCount(songId);
public decSongCount = (songId: string): Promise<void | null> => this.songUsage.decSongCount(songId); public decSongCount = (songId: string): Promise<void | null> => this.songUsage.decSongCount(songId);
public rebuildSongUsage = (): Promise<SongUsageMigrationResult> => this.songUsage.rebuildSongUsage(); public rebuildSongUsage = (): Promise<SongUsageMigrationResult> => this.songUsage.rebuildSongUsage();
public rebuildShowSongIds = (onProgress?: (progress: MigrationProgress) => void): Promise<ShowSongIndexMigrationResult> => public rebuildShowSongIds = (onProgress?: (progress: MigrationProgress) => void): Promise<ShowSongIndexMigrationResult> => this.showSongIndex.rebuildShowSongIds(onProgress);
this.showSongIndex.rebuildShowSongIds(onProgress);
} }

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1 @@
<input <input (ngModelChange)="valueChange($event)" [ngModel]="value" placeholder="Suche" />
(ngModelChange)="valueChange($event)"
[ngModel]="value"
placeholder="Suche"
/>

View File

@@ -1,24 +1,9 @@
<nav [class.hidden]="isNavigationHidden(windowScroll$|async)" class="head"> <nav [class.hidden]="isNavigationHidden(windowScroll$|async)" class="head">
<div class="links"> <div class="links">
<app-brand routerLink="/brand"></app-brand> <app-brand routerLink="/brand"></app-brand>
<app-link <app-link *appRole="['user', 'presenter', 'leader']" [icon]="faSongs" link="/songs" text="Lieder"></app-link>
*appRole="['user', 'presenter', 'leader']" <app-link *appRole="['leader', 'member']" [icon]="faShows" link="/shows" text="Veranstaltungen"></app-link>
[icon]="faSongs" <app-link *appRole="['presenter']" [icon]="faPresentation" link="/presentation" text="Präsentation"></app-link>
link="/songs"
text="Lieder"
></app-link>
<app-link
*appRole="['leader', 'member']"
[icon]="faShows"
link="/shows"
text="Veranstaltungen"
></app-link>
<app-link
*appRole="['presenter']"
[icon]="faPresentation"
link="/presentation"
text="Präsentation"
></app-link>
<app-link [icon]="faUser" link="/user" text="Benutzer"></app-link> <app-link [icon]="faUser" link="/user" text="Benutzer"></app-link>
</div> </div>
<div *appRole="['user', 'presenter', 'leader']" class="actions"> <div *appRole="['user', 'presenter', 'leader']" class="actions">

View File

@@ -1,8 +1,6 @@
<button [disabled]="disabled" mat-button> <button [disabled]="disabled" mat-button>
@if (icon) { @if (icon) {
<span <span><fa-icon [icon]="icon"></fa-icon><span class="content">&nbsp;</span></span>
><fa-icon [icon]="icon"></fa-icon><span class="content">&nbsp;</span></span
>
} }
<span class="button-content"> <span class="button-content">
<ng-content></ng-content> <ng-content></ng-content>

View File

@@ -1,17 +1,11 @@
<div [class.fullscreen]="fullscreen" [class.padding]="padding" class="card"> <div [class.fullscreen]="fullscreen" [class.padding]="padding" class="card">
@if (closeLink && !fullscreen) { @if (closeLink && !fullscreen) {
<button <button [routerLink]="closeLink" class="btn-close" mat-icon-button>
[routerLink]="closeLink"
class="btn-close"
mat-icon-button
>
<fa-icon [icon]="closeIcon"></fa-icon> <fa-icon [icon]="closeIcon"></fa-icon>
</button> </button>
} } @if (heading && !fullscreen) {
@if (heading && !fullscreen) {
<div class="heading">{{ heading }}</div> <div class="heading">{{ heading }}</div>
} } @if (subheading && !fullscreen) {
@if (subheading && !fullscreen) {
<div class="subheading">{{ subheading }}</div> <div class="subheading">{{ subheading }}</div>
} }
<ng-content></ng-content> <ng-content></ng-content>

View File

@@ -1,9 +1,5 @@
<div class="header"> <div class="header">
<button <button (click)="onFilterClick()" [class.filter-active]="anyFilterActive" mat-icon-button>
(click)="onFilterClick()"
[class.filter-active]="anyFilterActive"
mat-icon-button
>
<fa-icon [icon]="faFilter"></fa-icon> <fa-icon [icon]="faFilter"></fa-icon>
</button> </button>
<button mat-icon-button routerLink="new"> <button mat-icon-button routerLink="new">

View File

@@ -1,9 +1,4 @@
<svg <svg height="1024" viewBox="0 0 270.93 270.93" width="1024" xmlns="http://www.w3.org/2000/svg">
height="1024"
viewBox="0 0 270.93 270.93"
width="1024"
xmlns="http://www.w3.org/2000/svg"
>
<defs></defs> <defs></defs>
<g fill="#fff"> <g fill="#fff">
<path <path
@@ -13,10 +8,7 @@
d="m116.87 10.157-1.8882 4.7801-1.1823 4.7845-4.4402 0.29048-1.7967-4.5884-2.4969-4.4939-3.6268 0.47781-1.2476 4.9864-0.54906 4.8977-4.3633 0.86861-2.3806-4.3153-3.0618-4.1295-3.5339 0.94706-0.58683 5.1069 0.09583 4.9268-4.2121 1.4307-2.9239-3.9681-3.5745-3.6937-3.3799 1.4002 0.08404 5.1388 0.73936 4.8731-3.9914 1.9681-3.4163-3.5528-4.0248-3.1955-3.1693 1.8287 0.75527 5.0851 1.3683 4.7336-3.6995 2.4722-3.8506-3.0749-4.4083-2.6435-2.9035 2.2281 1.4118 4.9413 1.9739 4.5158-3.345 2.934-4.218-2.5462-4.7162-2.0466-2.5869 2.5883 2.0451 4.7147 2.5462 4.2195-2.934 3.345-4.5143-1.9739-4.9428-1.4118-2.2281 2.902 2.6435 4.4083 3.0763 3.8505-2.4721 3.6995-4.7351-1.3668-5.0837-0.75527-1.8301 3.1679 3.1969 4.0262 3.5513 3.4163-1.9681 3.9899-4.8716-0.73787-5.1403-0.08569-1.4002 3.3814 3.6951 3.5745 3.9667 2.9224-1.4307 4.2136-4.9268-0.09583-5.1069 0.58683-0.94699 3.5338 4.1294 3.0619 4.3153 2.3806-0.86853 4.3633-4.8963 0.54756-4.9864 1.2476-0.47788 3.6283 4.4925 2.4968 4.5899 1.7968-0.29196 4.4388-4.783 1.1838-4.7816 1.8882v3.6588l4.7816 1.8883 4.783 1.1823 0.29196 4.4402-4.5899 1.7967-4.4925 2.4954 0.47788 3.6283 4.9864 1.2476 4.8963 0.54905 0.86853 4.3632-4.3153 2.3806-4.1294 3.0618 0.94699 3.5338 5.1069 0.58686 4.9268-0.0958 1.4307 4.2122-3.9667 2.9239-3.6951 3.5745 1.4002 3.3799 5.1403-0.0857 4.8716-0.73787 1.9681 3.9914-3.5513 3.4162-3.1969 4.0249 1.8301 3.1693 5.0837-0.75535 4.7351-1.3682 2.4721 3.6994-3.0763 3.8505-2.6435 4.4083 2.2281 2.9035 4.9428-1.4133 4.5143-1.9739 2.934 3.345-2.5462 4.2195-2.0451 4.7162 2.5869 2.5868 4.7162-2.0451 4.218-2.5463 3.345 2.9326-1.9739 4.5158-1.4118 4.9428 2.9035 2.2281 4.4083-2.645 3.8506-3.0749 3.6995 2.4722-1.3683 4.7336-0.75527 5.0851 3.1693 1.8301 4.0248-3.1969 3.4163-3.5513 3.9914 1.9681-0.73936 4.8717-0.08404 5.1403 3.3799 1.4002 3.5745-3.6952 2.9239-3.9666 4.2121 1.4292-0.09583 4.9283 0.58683 5.1069 3.5339 0.94699 3.0618-4.1309 2.3806-4.3139 4.3633 0.8686 0.54906 4.8963 1.2476 4.9864 3.6268 0.47787 2.4969-4.494 1.7967-4.5884 4.4402 0.29189 1.1823 4.7831 1.8882 4.7816h3.6588l1.8882-4.7816 1.1823-4.7831 4.4402-0.29189 1.7967 4.5884 2.4969 4.494 3.6268-0.47787 1.2491-4.9864 0.54757-4.8963 4.3633-0.8686 2.3806 4.3139 3.0619 4.1309 3.5338-0.94699 0.58682-5.1069-0.0958-4.9283 4.2136-1.4292 2.9224 3.9666 3.5745 3.6952 3.3799-1.4002-0.0843-5.1403-0.73787-4.8717 3.9899-1.9681 3.4163 3.5513 4.0262 3.1969 3.1679-1.8301-0.75528-5.0851-1.3668-4.7336 3.6995-2.4722 3.8505 3.0749 4.4083 2.645 2.902-2.2281-1.4118-4.9428-1.9739-4.5158 3.345-2.9326 4.2194 2.5463 4.7148 2.0451 2.5883-2.5868-2.0465-4.7162-2.5462-4.2195 2.934-3.345 4.5157 1.9739 4.9414 1.4133 2.2281-2.9035-2.6435-4.4083-3.0749-3.8505 2.4707-3.6994 4.7351 1.3682 5.0837 0.75535 1.8301-3.1693-3.1969-4.0249-3.5513-3.4162 1.9681-3.9914 4.8716 0.73787 5.1403 0.0857 1.4002-3.3799-3.6951-3.5745-3.9668-2.9239 1.4307-4.2122 4.9268 0.0958 5.107-0.58686 0.94698-3.5338-4.1294-3.0618-4.3153-2.3806 0.86852-4.3632 4.8978-0.54905 4.9864-1.2476 0.47781-3.6283-4.4939-2.4954-4.5884-1.7967 0.29058-4.4402 4.7845-1.1823 4.7801-1.8883v-3.6588l-4.7801-1.8882-4.7845-1.1838-0.29058-4.4388 4.5884-1.7968 4.4939-2.4968-0.47781-3.6283-4.9864-1.2476-4.8978-0.54757-0.86852-4.3633 4.3153-2.3806 4.1294-3.0619-0.94698-3.5338-5.107-0.58683-4.9268 0.09583-1.4307-4.2136 3.9668-2.9224 3.6951-3.5745-1.4002-3.3814-5.1403 0.08569-4.8716 0.73787-1.9681-3.9899 3.5513-3.4163 3.1969-4.0262-1.8301-3.1679-5.0837 0.75527-4.7351 1.3668-2.4707-3.6995 3.0749-3.8505 2.6435-4.4083-2.2281-2.902-4.9414 1.4118-4.5157 1.9739-2.934-3.345 2.5462-4.2195 2.0465-4.7147-2.5883-2.5883-4.7148 2.0466-4.2194 2.5462-3.345-2.934 1.9739-4.5158 1.4118-4.9413-2.902-2.2281-4.4083 2.6435-3.8505 3.0749-3.6995-2.4722 1.3668-4.7336 0.75528-5.0851-3.1679-1.8287-4.0262 3.1955-3.4163 3.5528-3.9899-1.9681 0.73787-4.8731 0.0843-5.1388-3.3799-1.4002-3.5745 3.6937-2.9224 3.9681-4.2136-1.4307 0.0958-4.9268-0.58682-5.1069-3.5338-0.94706-3.0619 4.1295-2.3806 4.3153-4.3633-0.86861-0.54757-4.8977-1.2491-4.9864-3.6268-0.47781-2.4969 4.4939-1.7967 4.5884-4.4402-0.29048-1.1823-4.7845-1.8882-4.7801zm1.8301 21.667a96.677 96.677 0 0 1 96.677 96.677 96.677 96.677 0 0 1-96.677 96.677 96.677 96.677 0 0 1-96.677-96.677 96.677 96.677 0 0 1 96.677-96.677z" d="m116.87 10.157-1.8882 4.7801-1.1823 4.7845-4.4402 0.29048-1.7967-4.5884-2.4969-4.4939-3.6268 0.47781-1.2476 4.9864-0.54906 4.8977-4.3633 0.86861-2.3806-4.3153-3.0618-4.1295-3.5339 0.94706-0.58683 5.1069 0.09583 4.9268-4.2121 1.4307-2.9239-3.9681-3.5745-3.6937-3.3799 1.4002 0.08404 5.1388 0.73936 4.8731-3.9914 1.9681-3.4163-3.5528-4.0248-3.1955-3.1693 1.8287 0.75527 5.0851 1.3683 4.7336-3.6995 2.4722-3.8506-3.0749-4.4083-2.6435-2.9035 2.2281 1.4118 4.9413 1.9739 4.5158-3.345 2.934-4.218-2.5462-4.7162-2.0466-2.5869 2.5883 2.0451 4.7147 2.5462 4.2195-2.934 3.345-4.5143-1.9739-4.9428-1.4118-2.2281 2.902 2.6435 4.4083 3.0763 3.8505-2.4721 3.6995-4.7351-1.3668-5.0837-0.75527-1.8301 3.1679 3.1969 4.0262 3.5513 3.4163-1.9681 3.9899-4.8716-0.73787-5.1403-0.08569-1.4002 3.3814 3.6951 3.5745 3.9667 2.9224-1.4307 4.2136-4.9268-0.09583-5.1069 0.58683-0.94699 3.5338 4.1294 3.0619 4.3153 2.3806-0.86853 4.3633-4.8963 0.54756-4.9864 1.2476-0.47788 3.6283 4.4925 2.4968 4.5899 1.7968-0.29196 4.4388-4.783 1.1838-4.7816 1.8882v3.6588l4.7816 1.8883 4.783 1.1823 0.29196 4.4402-4.5899 1.7967-4.4925 2.4954 0.47788 3.6283 4.9864 1.2476 4.8963 0.54905 0.86853 4.3632-4.3153 2.3806-4.1294 3.0618 0.94699 3.5338 5.1069 0.58686 4.9268-0.0958 1.4307 4.2122-3.9667 2.9239-3.6951 3.5745 1.4002 3.3799 5.1403-0.0857 4.8716-0.73787 1.9681 3.9914-3.5513 3.4162-3.1969 4.0249 1.8301 3.1693 5.0837-0.75535 4.7351-1.3682 2.4721 3.6994-3.0763 3.8505-2.6435 4.4083 2.2281 2.9035 4.9428-1.4133 4.5143-1.9739 2.934 3.345-2.5462 4.2195-2.0451 4.7162 2.5869 2.5868 4.7162-2.0451 4.218-2.5463 3.345 2.9326-1.9739 4.5158-1.4118 4.9428 2.9035 2.2281 4.4083-2.645 3.8506-3.0749 3.6995 2.4722-1.3683 4.7336-0.75527 5.0851 3.1693 1.8301 4.0248-3.1969 3.4163-3.5513 3.9914 1.9681-0.73936 4.8717-0.08404 5.1403 3.3799 1.4002 3.5745-3.6952 2.9239-3.9666 4.2121 1.4292-0.09583 4.9283 0.58683 5.1069 3.5339 0.94699 3.0618-4.1309 2.3806-4.3139 4.3633 0.8686 0.54906 4.8963 1.2476 4.9864 3.6268 0.47787 2.4969-4.494 1.7967-4.5884 4.4402 0.29189 1.1823 4.7831 1.8882 4.7816h3.6588l1.8882-4.7816 1.1823-4.7831 4.4402-0.29189 1.7967 4.5884 2.4969 4.494 3.6268-0.47787 1.2491-4.9864 0.54757-4.8963 4.3633-0.8686 2.3806 4.3139 3.0619 4.1309 3.5338-0.94699 0.58682-5.1069-0.0958-4.9283 4.2136-1.4292 2.9224 3.9666 3.5745 3.6952 3.3799-1.4002-0.0843-5.1403-0.73787-4.8717 3.9899-1.9681 3.4163 3.5513 4.0262 3.1969 3.1679-1.8301-0.75528-5.0851-1.3668-4.7336 3.6995-2.4722 3.8505 3.0749 4.4083 2.645 2.902-2.2281-1.4118-4.9428-1.9739-4.5158 3.345-2.9326 4.2194 2.5463 4.7148 2.0451 2.5883-2.5868-2.0465-4.7162-2.5462-4.2195 2.934-3.345 4.5157 1.9739 4.9414 1.4133 2.2281-2.9035-2.6435-4.4083-3.0749-3.8505 2.4707-3.6994 4.7351 1.3682 5.0837 0.75535 1.8301-3.1693-3.1969-4.0249-3.5513-3.4162 1.9681-3.9914 4.8716 0.73787 5.1403 0.0857 1.4002-3.3799-3.6951-3.5745-3.9668-2.9239 1.4307-4.2122 4.9268 0.0958 5.107-0.58686 0.94698-3.5338-4.1294-3.0618-4.3153-2.3806 0.86852-4.3632 4.8978-0.54905 4.9864-1.2476 0.47781-3.6283-4.4939-2.4954-4.5884-1.7967 0.29058-4.4402 4.7845-1.1823 4.7801-1.8883v-3.6588l-4.7801-1.8882-4.7845-1.1838-0.29058-4.4388 4.5884-1.7968 4.4939-2.4968-0.47781-3.6283-4.9864-1.2476-4.8978-0.54757-0.86852-4.3633 4.3153-2.3806 4.1294-3.0619-0.94698-3.5338-5.107-0.58683-4.9268 0.09583-1.4307-4.2136 3.9668-2.9224 3.6951-3.5745-1.4002-3.3814-5.1403 0.08569-4.8716 0.73787-1.9681-3.9899 3.5513-3.4163 3.1969-4.0262-1.8301-3.1679-5.0837 0.75527-4.7351 1.3668-2.4707-3.6995 3.0749-3.8505 2.6435-4.4083-2.2281-2.902-4.9414 1.4118-4.5157 1.9739-2.934-3.345 2.5462-4.2195 2.0465-4.7147-2.5883-2.5883-4.7148 2.0466-4.2194 2.5462-3.345-2.934 1.9739-4.5158 1.4118-4.9413-2.902-2.2281-4.4083 2.6435-3.8505 3.0749-3.6995-2.4722 1.3668-4.7336 0.75528-5.0851-3.1679-1.8287-4.0262 3.1955-3.4163 3.5528-3.9899-1.9681 0.73787-4.8731 0.0843-5.1388-3.3799-1.4002-3.5745 3.6937-2.9224 3.9681-4.2136-1.4307 0.0958-4.9268-0.58682-5.1069-3.5338-0.94706-3.0619 4.1295-2.3806 4.3153-4.3633-0.86861-0.54757-4.8977-1.2491-4.9864-3.6268-0.47781-2.4969 4.4939-1.7967 4.5884-4.4402-0.29048-1.1823-4.7845-1.8882-4.7801zm1.8301 21.667a96.677 96.677 0 0 1 96.677 96.677 96.677 96.677 0 0 1-96.677 96.677 96.677 96.677 0 0 1-96.677-96.677 96.677 96.677 0 0 1 96.677-96.677z"
id="gear-lg" id="gear-lg"
/> />
<g <g aria-label="WORSHIP GENERATOR" transform="matrix(.92405 0 0 1.164 -6.4481 5.9862)">
aria-label="WORSHIP GENERATOR"
transform="matrix(.92405 0 0 1.164 -6.4481 5.9862)"
>
<path <path
d="m26.155 213.81q-1.5697 4.1147-2.9258 8.0808-1.3468 3.9568-1.4118 4.1333h-1.2911q-0.04644-0.17647-1.0031-2.9537-0.9474-2.7865-2.5078-6.9291h-0.01858q-1.3654 3.4274-2.5171 6.5575-1.1425 3.1209-1.2168 3.3252h-1.3189q-0.07431-0.26936-1.1982-3.641-1.1146-3.3809-2.9815-8.4523l1.5233-0.59445q0.037153 0.13004 1.0867 3.2695 1.0496 3.1394 2.4057 7.0498h0.01858q1.4304-3.6038 2.4893-6.604 1.0682-3.0001 1.1146-3.1394h1.4397q0.03715 0.15791 1.1239 3.3995 1.096 3.2416 2.2199 6.3439h0.01858q1.4861-4.059 2.5078-7.1148 1.0217-3.0558 1.0589-3.2045z" d="m26.155 213.81q-1.5697 4.1147-2.9258 8.0808-1.3468 3.9568-1.4118 4.1333h-1.2911q-0.04644-0.17647-1.0031-2.9537-0.9474-2.7865-2.5078-6.9291h-0.01858q-1.3654 3.4274-2.5171 6.5575-1.1425 3.1209-1.2168 3.3252h-1.3189q-0.07431-0.26936-1.1982-3.641-1.1146-3.3809-2.9815-8.4523l1.5233-0.59445q0.037153 0.13004 1.0867 3.2695 1.0496 3.1394 2.4057 7.0498h0.01858q1.4304-3.6038 2.4893-6.604 1.0682-3.0001 1.1146-3.1394h1.4397q0.03715 0.15791 1.1239 3.3995 1.096 3.2416 2.2199 6.3439h0.01858q1.4861-4.059 2.5078-7.1148 1.0217-3.0558 1.0589-3.2045z"
/> />

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -1,81 +1,41 @@
@if (sections && !fullscreen) { @if (sections && !fullscreen) {
<div <div (click)="onClick()" [class.chords]="iChordMode !== 'hide'" class="song-text">
(click)="onClick()"
[class.chords]="iChordMode !== 'hide'"
class="song-text"
>
@if (showSwitch) { @if (showSwitch) {
<button <button (click)="onChordClick()" class="menu" mat-icon-button>
(click)="onChordClick()"
class="menu"
mat-icon-button
>
<fa-icon [icon]="faLines"></fa-icon> <fa-icon [icon]="faLines"></fa-icon>
</button> </button>
} }
<div [class.offset]="fullscreen" [style.top.px]="offset + 50"> <div [class.offset]="fullscreen" [style.top.px]="offset + 50">
@for (section of sections; track section.type + '-' + section.number + '-' + $index; let i = $index) { @for (section of sections; track section.type + '-' + section.number + '-' + $index; let i = $index) {
<div <div #section [class.chorus]="section.type === 1" class="section">
#section
[class.chorus]="section.type === 1"
class="section"
>
@for (line of getLines(section); track (line.lineNumber ?? $index) + '-' + line.type + '-' + $index) { @for (line of getLines(section); track (line.lineNumber ?? $index) + '-' + line.type + '-' + $index) {
<div <div [class.chord]="line.type === 0" [class.comment]="isComment(line.text)" [class.disabled]="checkDisabled(i)" class="line">
[class.chord]="line.type === 0"
[class.comment]="isComment(line.text)"
[class.disabled]="checkDisabled(i)"
class="line"
>
@for (segment of getDisplaySegments(line); track $index) { @for (segment of getDisplaySegments(line); track $index) {
<span [class.invalid-chord-token]="segment.invalid" [class.invalid-tab-token]="segment.isTab">{{ segment.text }}</span> <span [class.invalid-chord-token]="segment.invalid" [class.invalid-tab-token]="segment.isTab">{{ segment.text }}</span>
} }
</div> </div>
} }
</div> </div>
} } @if (sections.length===0) {
@if (sections.length===0) { <div class="error">Es wurden keine Liedabschnitte gefunden! Bitte mindestens einen Abschnitt festlegen!</div>
<div class="error">
Es wurden keine Liedabschnitte gefunden! Bitte mindestens einen Abschnitt festlegen!
</div>
} }
</div> </div>
<ng-content></ng-content> <ng-content></ng-content>
</div> </div>
} } @if (sections && fullscreen) {
<div (click)="onClick()" [@songSwitch]="sections" [class.chords]="iChordMode !== 'hide'" class="song-text">
@if (sections && fullscreen) {
<div
(click)="onClick()"
[@songSwitch]="sections"
[class.chords]="iChordMode !== 'hide'"
class="song-text"
>
@if (showSwitch) { @if (showSwitch) {
<button <button (click)="onChordClick()" class="menu" mat-icon-button>
(click)="onChordClick()"
class="menu"
mat-icon-button
>
<fa-icon [icon]="faLines"></fa-icon> <fa-icon [icon]="faLines"></fa-icon>
</button> </button>
} }
<div [class.offset]="fullscreen" [style.top.px]="offset + 50"> <div [class.offset]="fullscreen" [style.top.px]="offset + 50">
@if (header) { @if (header) {
<h1>{{ header }}</h1> <h1>{{ header }}</h1>
} } @for (section of sections; track section.type + '-' + section.number + '-' + $index; let i = $index) {
@for (section of sections; track section.type + '-' + section.number + '-' + $index; let i = $index) { <div #section [class.chorus]="section.type === 1" class="section">
<div
#section
[class.chorus]="section.type === 1"
class="section"
>
@for (line of getLines(section); track (line.lineNumber ?? $index) + '-' + line.type + '-' + $index) { @for (line of getLines(section); track (line.lineNumber ?? $index) + '-' + line.type + '-' + $index) {
<div <div [class.chord]="line.type === 0" [class.disabled]="checkDisabled(i)" class="line">
[class.chord]="line.type === 0"
[class.disabled]="checkDisabled(i)"
class="line"
>
@for (segment of getDisplaySegments(line, true); track $index) { @for (segment of getDisplaySegments(line, true); track $index) {
<span [class.invalid-chord-token]="segment.invalid" [class.invalid-tab-token]="segment.isTab">{{ segment.text }}</span> <span [class.invalid-chord-token]="segment.invalid" [class.invalid-tab-token]="segment.isTab">{{ segment.text }}</span>
} }

File diff suppressed because one or more lines are too long

View File

@@ -53,13 +53,10 @@ bootstrapApplication(AppComponent, {
rebuildShowSongIds: async () => { rebuildShowSongIds: async () => {
console.info('[wgeneratorAdmin] rebuildShowSongIds started'); console.info('[wgeneratorAdmin] rebuildShowSongIds started');
const result = await userService.rebuildShowSongIds(progress => { const result = await userService.rebuildShowSongIds(progress => {
console.info( console.info(`[wgeneratorAdmin] rebuildShowSongIds ${progress.processed}/${progress.total} shows processed`, {
`[wgeneratorAdmin] rebuildShowSongIds ${progress.processed}/${progress.total} shows processed`,
{
showId: progress.showId, showId: progress.showId,
showSongsProcessed: progress.showSongsProcessed, showSongsProcessed: progress.showSongsProcessed,
} });
);
}); });
console.info('[wgeneratorAdmin] rebuildShowSongIds finished', result); console.info('[wgeneratorAdmin] rebuildShowSongIds finished', result);
return result; return result;

View File

@@ -78,7 +78,7 @@ const defaultTestingProviders: TestingProviderList = [
}, },
]; ];
const originalConfigureTestingModule = TestBed.configureTestingModule.bind(TestBed) as typeof TestBed.configureTestingModule; const originalConfigureTestingModule = TestBed.configureTestingModule.bind(TestBed);
const configureTestingModule: typeof TestBed.configureTestingModule = moduleDef => { const configureTestingModule: typeof TestBed.configureTestingModule = moduleDef => {
const extraProviders: TestingProviderList = moduleDef?.providers ?? []; const extraProviders: TestingProviderList = moduleDef?.providers ?? [];
const mergedModuleDef: TestingModuleDefinition = moduleDef ? {...moduleDef} : {}; const mergedModuleDef: TestingModuleDefinition = moduleDef ? {...moduleDef} : {};