400 lines
15 KiB
HTML
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>
|