feat(media): add reusable MediaPickerComponent
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Standalone dialog (app-dialog, size lg) reusing MediaLibraryFacade so it shares the exact same asset list/search/pagination/upload state as the Media Manager page. Emits (selected) with the chosen MediaAsset and (closed) to dismiss - selecting a tile emits both. Completes Sprint 4 (Media Manager): ADR-0002 contract, MediaRepository + mock IndexedDB adapter, Media Manager UI, reusable Media Picker. Not yet wired into Product Editor or Static Pages editor - that's the next natural step when those features gain image fields, not part of this sprint's scope.
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
<app-dialog
|
||||
[open]="open()"
|
||||
[titleText]="'mediaLibrary.title' | translate"
|
||||
size="lg"
|
||||
(closed)="requestClose()"
|
||||
>
|
||||
<div class="media-picker">
|
||||
<div class="media-picker__toolbar">
|
||||
<app-input
|
||||
[ngModel]="facade.search()"
|
||||
(ngModelChange)="facade.setSearch($event)"
|
||||
[placeholder]="'mediaLibrary.searchPlaceholder' | translate"
|
||||
/>
|
||||
<input
|
||||
#fileInput
|
||||
type="file"
|
||||
accept="image/*,application/pdf"
|
||||
hidden
|
||||
(change)="onFileSelected($event)"
|
||||
/>
|
||||
<app-button variant="secondary" [loading]="facade.uploading()" (click)="triggerFileInput()">
|
||||
{{ (facade.uploading() ? 'mediaLibrary.uploading' : 'mediaLibrary.upload') | translate }}
|
||||
</app-button>
|
||||
</div>
|
||||
|
||||
@if (facade.loading()) {
|
||||
<div class="media-picker__grid">
|
||||
@for (i of [1, 2, 3, 4]; track i) {
|
||||
<app-skeleton shape="rect" height="110px" />
|
||||
}
|
||||
</div>
|
||||
} @else if (facade.items().length === 0) {
|
||||
<app-empty-state
|
||||
[title]="'mediaLibrary.emptyTitle' | translate"
|
||||
[description]="'mediaLibrary.emptyDescription' | translate"
|
||||
/>
|
||||
} @else {
|
||||
<div class="media-picker__grid">
|
||||
@for (asset of facade.items(); track asset.id) {
|
||||
<app-card padding="sm" [interactive]="true" (click)="pick(asset)">
|
||||
@if (asset.mimeType.startsWith('image/')) {
|
||||
<img class="media-picker__preview" [src]="asset.url" [alt]="asset.filename" />
|
||||
} @else {
|
||||
<div class="media-picker__preview media-picker__preview--file">{{ asset.mimeType }}</div>
|
||||
}
|
||||
<span class="media-picker__filename">{{ asset.filename }}</span>
|
||||
</app-card>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (totalPages() > 1) {
|
||||
<app-pagination [currentPage]="facade.page()" [totalPages]="totalPages()" (pageChange)="facade.setPage($event)" />
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</app-dialog>
|
||||
Reference in New Issue
Block a user