Files
print-calculator/frontend/src/app/features/admin/pages/admin-home-media.component.html
2026-03-11 14:18:47 +00:00

400 lines
15 KiB
HTML

<section class="section-card ui-stack ui-stack--roomy">
<header class="section-header">
<div class="header-copy">
<p class="eyebrow ui-eyebrow ui-eyebrow--compact">Back-office media</p>
<h2>Media home</h2>
</div>
<div class="header-side ui-stack ui-stack--dense">
<div class="header-stats ui-inline-actions">
<article class="stat-chip ui-stat-chip">
<strong>{{ configuredSectionCount }}</strong>
<span>sezioni gestite</span>
</article>
<article class="stat-chip ui-stat-chip">
<strong>{{ activeImageCount }}</strong>
<span>immagini attive</span>
</article>
</div>
<button
type="button"
class="ui-button"
(click)="loadHomeMedia()"
[disabled]="loading"
>
Aggiorna
</button>
</div>
</header>
<p class="status-banner ui-banner ui-banner--error" *ngIf="errorMessage">
{{ errorMessage }}
</p>
<p class="status-banner ui-banner ui-banner--success" *ngIf="successMessage">
{{ successMessage }}
</p>
<div class="group-stack ui-stack" *ngIf="!loading; else loadingTpl">
<section
class="group-card ui-subpanel ui-subpanel--warm"
*ngFor="let group of sectionGroups"
>
<header class="group-header ui-row ui-row--between">
<h3>{{ group.title }}</h3>
</header>
<div class="sections ui-stack ui-stack--dense">
<section
class="media-panel ui-subpanel ui-subpanel--elevated"
*ngFor="
let section of getSectionsForGroup(group.id);
trackBy: trackSection
"
>
<header
class="media-panel-header ui-row ui-row--between ui-row--wrap"
>
<div class="media-panel-copy ui-stack ui-stack--dense">
<div class="title-row ui-row ui-row--center ui-row--wrap">
<h4>{{ section.title }}</h4>
<span class="count-pill ui-pill ui-pill--soft">
{{ section.items.length }}
{{ section.items.length === 1 ? "attiva" : "attive" }}
</span>
</div>
</div>
<div class="media-panel-meta ui-row ui-row--wrap ui-row--end">
<span class="usage-pill ui-pill ui-pill--neutral"
>{{ section.usageType }} / {{ section.usageKey }}</span
>
<span class="layout-pill ui-pill ui-pill--light">
Variante {{ section.preferredVariantName }}
</span>
</div>
</header>
<div class="workspace ui-workspace-compact">
<div class="upload-panel ui-subpanel ui-subpanel--soft">
<div class="panel-heading ui-stack ui-stack--dense">
<h5>
{{
getFormState(section.usageKey).replacingUsageId
? "Sostituisci immagine"
: "Carica immagine"
}}
</h5>
</div>
<div class="form-grid ui-form-grid ui-form-grid--two">
<div class="form-field form-field--wide ui-form-field">
<span class="ui-form-caption">File immagine</span>
<input
[id]="'media-file-' + section.usageKey"
class="sr-only"
type="file"
accept=".jpg,.jpeg,.png,.webp"
(change)="onFileSelected(section.usageKey, $event)"
/>
<label
class="file-picker ui-file-picker"
[for]="'media-file-' + section.usageKey"
>
<span class="file-picker-button ui-file-picker__button"
>Scegli file</span
>
<span class="file-picker-name ui-file-picker__name">
{{
getFormState(section.usageKey).file?.name ||
"Nessun file selezionato"
}}
</span>
</label>
</div>
<div
class="preview-card form-field--wide"
*ngIf="
getFormState(section.usageKey).previewUrl as previewUrl
"
>
<img [src]="previewUrl" alt="" />
</div>
<div
class="language-toolbar form-field--wide ui-language-toolbar"
>
<div class="language-copy ui-language-toolbar__copy">
<span>Testi localizzati</span>
<p>IT / EN / DE / FR obbligatorie</p>
</div>
<div class="language-toggle ui-language-toolbar__toggle">
<button
*ngFor="let language of mediaLanguages"
type="button"
class="ui-language-toolbar__button image-language-button"
[class.active]="
getFormState(section.usageKey).activeLanguage ===
language
"
[class.complete]="
isLanguageComplete(section.usageKey, language)
"
[class.incomplete]="
isLanguageIncomplete(section.usageKey, language)
"
[class.empty]="
!isLanguageStarted(section.usageKey, language)
"
(click)="setActiveLanguage(section.usageKey, language)"
>
<span class="image-language-button__label">
{{ mediaLanguageLabels[language] }}
</span>
<span
class="image-language-button__state"
*ngIf="isLanguageComplete(section.usageKey, language)"
>
OK
</span>
<span
class="image-language-button__state"
*ngIf="isLanguageIncomplete(section.usageKey, language)"
>
...
</span>
</button>
</div>
</div>
<label class="form-field ui-form-field">
<span class="ui-form-caption">
Titolo ({{
mediaLanguageLabels[
getFormState(section.usageKey).activeLanguage
]
}})
</span>
<input
class="ui-form-control"
type="text"
[(ngModel)]="getActiveTranslation(section.usageKey).title"
placeholder="Titolo immagine"
/>
</label>
<label class="form-field ui-form-field">
<span class="ui-form-caption">
Alt text ({{
mediaLanguageLabels[
getFormState(section.usageKey).activeLanguage
]
}})
</span>
<input
class="ui-form-control"
type="text"
[(ngModel)]="getActiveTranslation(section.usageKey).altText"
placeholder="Testo alternativo"
/>
</label>
<label class="form-field ui-form-field">
<span class="ui-form-caption">Sort order</span>
<input
class="ui-form-control"
type="number"
[(ngModel)]="getFormState(section.usageKey).sortOrder"
min="0"
/>
</label>
<label class="toggle">
<input
type="checkbox"
[(ngModel)]="getFormState(section.usageKey).isPrimary"
/>
<span class="toggle-mark" aria-hidden="true"></span>
<span>Primaria</span>
</label>
</div>
<div class="upload-actions ui-row ui-row--wrap">
<button
type="button"
class="ui-button"
(click)="uploadForSection(section.usageKey)"
[disabled]="
getFormState(section.usageKey).saving ||
!getFormState(section.usageKey).file
"
>
{{
getFormState(section.usageKey).saving
? "Salvataggio..."
: getFormState(section.usageKey).replacingUsageId
? "Sostituisci immagine"
: "Carica in home"
}}
</button>
<button
type="button"
class="ui-button ui-button--ghost"
(click)="prepareAdd(section.usageKey)"
[disabled]="getFormState(section.usageKey).saving"
>
Nuova immagine
</button>
<button
type="button"
class="ui-button ui-button--ghost"
*ngIf="getFormState(section.usageKey).replacingUsageId"
(click)="cancelReplace(section.usageKey)"
[disabled]="getFormState(section.usageKey).saving"
>
Annulla sostituzione
</button>
</div>
</div>
<div class="list-panel ui-subpanel ui-subpanel--soft">
<div class="panel-heading ui-stack ui-stack--dense">
<h5>Immagini attive</h5>
</div>
<div
class="media-list ui-media-list"
*ngIf="section.items.length; else emptySectionState"
>
<article
class="media-item ui-media-item"
*ngFor="let item of section.items; trackBy: trackItem"
>
<div class="thumb-wrap">
<div class="thumb ui-thumb">
<img
*ngIf="item.previewUrl; else noPreviewTpl"
[src]="item.previewUrl"
alt=""
/>
</div>
</div>
<div class="media-copy ui-stack ui-stack--dense">
<div
class="media-copy-top ui-row ui-row--between ui-row--center ui-row--wrap"
>
<div>
<h6>
{{
getItemTranslation(
item,
getFormState(section.usageKey).activeLanguage
).title || item.originalFilename
}}
</h6>
<p class="meta">
{{ item.originalFilename }} | asset
{{ item.mediaAssetId }}
</p>
</div>
<span
class="primary-badge ui-pill ui-pill--accent"
*ngIf="item.isPrimary"
>Primaria</span
>
</div>
<p class="meta">
Alt
{{
mediaLanguageLabels[
getFormState(section.usageKey).activeLanguage
]
}}:
{{
getItemTranslation(
item,
getFormState(section.usageKey).activeLanguage
).altText || "-"
}}
</p>
<p class="meta">
Sort order: {{ item.sortOrder }} | Inserita:
{{ item.createdAt | date: "short" }}
</p>
<div class="sort-editor ui-row ui-row--wrap">
<label>
<span class="ui-form-caption">Nuovo ordine</span>
<input
class="ui-form-control"
type="number"
[(ngModel)]="item.draftSortOrder"
min="0"
/>
</label>
<button
type="button"
class="ui-button ui-button--ghost"
(click)="saveSortOrder(item)"
[disabled]="
isUsageBusy(item.usageId) ||
item.draftSortOrder === item.sortOrder
"
>
Salva ordine
</button>
</div>
<div class="item-actions ui-row ui-row--wrap">
<button
type="button"
class="ui-button ui-button--ghost"
(click)="prepareReplace(section.usageKey, item)"
[disabled]="isUsageBusy(item.usageId)"
>
Sostituisci
</button>
<button
type="button"
class="ui-button ui-button--ghost"
(click)="setPrimary(item)"
[disabled]="isUsageBusy(item.usageId) || item.isPrimary"
>
Rendi primaria
</button>
<button
type="button"
class="ui-button ui-button--ghost-danger"
(click)="removeFromHome(item)"
[disabled]="isUsageBusy(item.usageId)"
>
Rimuovi dalla home
</button>
</div>
</div>
</article>
</div>
</div>
</div>
</section>
</div>
</section>
</div>
<ng-template #emptySectionState>
<p class="empty-state ui-empty-state">
Nessuna immagine attiva collegata a questa sezione home.
</p>
</ng-template>
<ng-template #noPreviewTpl>
<div class="thumb thumb-empty ui-thumb ui-thumb--empty">
<span>Preview non disponibile</span>
</div>
</ng-template>
</section>
<ng-template #loadingTpl>
<p class="loading-state ui-empty-state">Caricamento media home...</p>
</ng-template>