Miglioramenti generali layout player landscape/portrait, traduzione pulsanti navigazione, gestione aggiornamenti PWA e modifiche al posizionamento del pulsante aggiungi canto

This commit is contained in:
David Frassi
2026-06-14 22:14:41 +02:00
parent d023bb7d3f
commit b4b7e10c5f
20 changed files with 1554 additions and 535 deletions
@@ -31,107 +31,159 @@
</div>
</div>
<ion-list lines="none" class="input-list">
<ion-item class="custom-input-item">
<ion-label position="stacked">Titolo del Canto</ion-label>
<ion-input [(ngModel)]="title" placeholder="Es: Il Signore è la mia salvezza"></ion-input>
</ion-item>
<div class="editor-preview-split">
<!-- Left Column: Inputs & Editor -->
<div class="editor-column">
<ion-list lines="none" class="input-list">
<ion-item class="custom-input-item">
<ion-label position="stacked">Titolo del Canto</ion-label>
<ion-input [(ngModel)]="title" placeholder="Es: Il Signore è la mia salvezza"></ion-input>
</ion-item>
<div class="category-selectors">
<ion-item class="custom-input-item select-item">
<ion-label position="stacked">Momento Liturgico</ion-label>
<ion-select [(ngModel)]="selectedLiturgico" placeholder="Scegli momento" multiple="true" interface="popover">
<ion-select-option *ngFor="let lit of cantiService.indiceLiturgico()" [value]="lit.id">
{{ lit.tag_name }}
</ion-select-option>
</ion-select>
</ion-item>
<div class="category-selectors">
<ion-item class="custom-input-item select-item">
<ion-label position="stacked">Momento Liturgico</ion-label>
<ion-select [(ngModel)]="selectedLiturgico" placeholder="Scegli momento" multiple="true" interface="popover">
<ion-select-option *ngFor="let lit of cantiService.indiceLiturgico()" [value]="lit.id">
{{ lit.tag_name }}
</ion-select-option>
</ion-select>
</ion-item>
<ion-item class="custom-input-item select-item">
<ion-label position="stacked">Periodo / Tema</ion-label>
<ion-select [(ngModel)]="selectedTematico" placeholder="Scegli tema" multiple="true" interface="popover">
<ion-select-option *ngFor="let tem of cantiService.indiceTematico()" [value]="tem.id">
{{ tem.tag_name }}
</ion-select-option>
</ion-select>
</ion-item>
</div>
<!-- TOOLBARS -->
<div class="toolbar-section">
<div class="horizontal-toolbar">
<ion-button *ngFor="let tag of commonTags" size="small" fill="outline" (click)="insertText(tag.start)">
{{ tag.label }}
</ion-button>
</div>
</div>
<!-- Main Chords Selector Toolbar -->
<div class="toolbar-section">
<div class="horizontal-toolbar main-chords-toolbar">
<ion-button
*ngFor="let group of groupedChords"
size="small"
[fill]="selectedRootChord === group.root ? 'solid' : 'outline'"
[color]="selectedRootChord === group.root ? 'secondary' : 'light'"
(click)="selectRoot(group.root)">
{{ group.root }}
</ion-button>
</div>
</div>
<!-- Variations Toolbar (only visible if a root chord is selected) -->
<div class="toolbar-section variations-container" *ngIf="selectedRootChord">
<div class="horizontal-toolbar variations-toolbar">
<span class="variations-label">Variazioni {{ selectedRootChord }}:</span>
<ion-button
size="small"
*ngFor="let chord of getVariations()"
(click)="insertChord(chord)">
{{ chord }}
</ion-button>
</div>
</div>
<!-- EDITOR AREA -->
<div class="editor-wrapper" [class.hc]="isHighContrast">
<div class="editor-header">
<div class="editor-title-group">
<span>Editor Testo</span>
<ion-item class="custom-input-item select-item">
<ion-label position="stacked">Periodo / Tema</ion-label>
<ion-select [(ngModel)]="selectedTematico" placeholder="Scegli tema" multiple="true" interface="popover">
<ion-select-option *ngFor="let tem of cantiService.indiceTematico()" [value]="tem.id">
{{ tem.tag_name }}
</ion-select-option>
</ion-select>
</ion-item>
</div>
<div class="editor-actions">
<ion-button fill="clear" size="small" (click)="undo()" [disabled]="undoStack.length === 0">
<ion-icon name="undo-outline"></ion-icon>
</ion-button>
<ion-button fill="clear" size="small" (click)="takePhoto()">
<ion-icon name="camera-outline"></ion-icon>
<!-- TOOLBARS -->
<div class="toolbar-section">
<div class="horizontal-toolbar">
<ion-button *ngFor="let tag of commonTags" size="small" fill="outline" (click)="insertText(tag.start)">
{{ tag.label }}
</ion-button>
</div>
</div>
<!-- Main Chords Selector Toolbar -->
<div class="toolbar-section">
<div class="horizontal-toolbar main-chords-toolbar">
<ion-button
*ngFor="let group of groupedChords"
size="small"
[fill]="selectedRootChord === group.root ? 'solid' : 'outline'"
[color]="selectedRootChord === group.root ? 'secondary' : 'light'"
(click)="selectRoot(group.root)">
{{ group.root }}
</ion-button>
</div>
</div>
<!-- Variations Toolbar (only visible if a root chord is selected) -->
<div class="toolbar-section variations-container" *ngIf="selectedRootChord">
<div class="horizontal-toolbar variations-toolbar">
<span class="variations-label">Variazioni {{ selectedRootChord }}:</span>
<ion-button
size="small"
*ngFor="let chord of getVariations()"
(click)="insertChord(chord)">
{{ chord }}
</ion-button>
</div>
</div>
<!-- EDITOR AREA -->
<div class="editor-wrapper" [class.hc]="isHighContrast">
<div class="editor-header">
<div class="editor-title-group">
<span>Editor Testo</span>
</div>
<div class="editor-actions">
<ion-button fill="clear" size="small" (click)="undo()" [disabled]="undoStack.length === 0">
<ion-icon name="undo-outline"></ion-icon>
</ion-button>
<ion-button fill="clear" size="small" (click)="takePhoto()">
<ion-icon name="camera-outline"></ion-icon>
</ion-button>
</div>
</div>
<ion-item class="custom-input-item textarea-item">
<ion-textarea
#contentTextarea
[(ngModel)]="content"
placeholder="Scrivi o scansiona..."
rows="18"
class="content-textarea"
(paste)="onPaste($event)">
</ion-textarea>
</ion-item>
</div>
<ion-item class="custom-input-item">
<ion-label position="stacked">Autore / Link YouTube</ion-label>
<ion-input [(ngModel)]="author" placeholder="Autore"></ion-input>
<ion-input [(ngModel)]="youtubeLink" placeholder="URL YouTube"></ion-input>
</ion-item>
</ion-list>
<div class="action-buttons">
<ion-button expand="block" (click)="saveToMyCanti()" class="send-btn" [disabled]="!title || !content || isProcessingOCR">
<ion-icon slot="start" name="save-outline"></ion-icon>
Salva nei Miei Canti
</ion-button>
</div>
</div>
<!-- Right Column: Active Preview Pane -->
<div class="preview-column">
<div class="preview-card" [class.hc]="isHighContrast">
<div class="preview-header">
<span class="preview-title">Anteprima Attiva</span>
<ion-button fill="clear" size="small" (click)="toggleChordsPreview()" class="preview-toggle-btn">
<ion-icon slot="start" [name]="showChordsPreview ? 'musical-notes-outline' : 'text-outline'"></ion-icon>
{{ showChordsPreview ? 'Con Accordi' : 'Solo Testo' }}
</ion-button>
</div>
<div class="preview-body">
<div class="preview-song-header">
<h2 class="preview-song-title">{{ title || 'Titolo del Canto' }}</h2>
<p class="preview-song-author" *ngIf="author">{{ author }}</p>
</div>
<div class="preview-lyrics-container">
<div *ngFor="let section of parsedSections"
class="preview-section"
[class.chorus]="section.type === 'chorus'"
[class.verse-num]="section.type === 'verse_num'">
<div *ngIf="section.type === 'chorus'" class="preview-section-label">Rit.</div>
<div *ngIf="section.type === 'verse_num' && section.verseNumber" class="preview-section-label preview-verse-num-label">{{ section.verseNumber }}.</div>
<div *ngFor="let line of section.lines" class="preview-lyric-line">
<!-- Chord mode -->
<ng-container *ngIf="showChordsPreview; else textOnly">
<span *ngFor="let seg of line.segments; let i = index" class="preview-chord-segment" [class.contiguous-next]="lyricsParser.isContiguousNext(line.segments, i)">
<span *ngIf="seg.chord" class="preview-chord">{{ seg.chord }}</span>
<span class="preview-seg-text">{{ seg.text }}</span>
</span>
</ng-container>
<!-- Text only mode -->
<ng-template #textOnly>
{{ line.text }}
</ng-template>
</div>
</div>
<div class="preview-empty" *ngIf="!content">
Il testo formattato apparirà qui mentre scrivi...
</div>
</div>
</div>
</div>
<ion-item class="custom-input-item textarea-item">
<ion-textarea
#contentTextarea
[(ngModel)]="content"
placeholder="Scrivi o scansiona..."
rows="18"
class="content-textarea"
(paste)="onPaste($event)">
</ion-textarea>
</ion-item>
</div>
<ion-item class="custom-input-item">
<ion-label position="stacked">Autore / Link YouTube</ion-label>
<ion-input [(ngModel)]="author" placeholder="Autore"></ion-input>
<ion-input [(ngModel)]="youtubeLink" placeholder="URL YouTube"></ion-input>
</ion-item>
</ion-list>
<div class="action-buttons">
<ion-button expand="block" (click)="saveToMyCanti()" class="send-btn" [disabled]="!title || !content || isProcessingOCR">
<ion-icon slot="start" name="save-outline"></ion-icon>
Salva nei Miei Canti
</ion-button>
</div>
</div>