Media dashboard (real total/images/SVG/logos/unused/storage/alt-coverage, computed from actual assets + a bootstrap usage scan, no fabricated stats); gallery gets grid/list toggle, type filter, sort, drag-and-drop + multi-file upload with cancel/retry and friendly error mapping, lazy thumbnails, multi-select with bulk delete/download/export-metadata; asset details drawer shows real dimensions/size/format/date/usage locations (walks bootstrap config for exact URL matches, reports not-used rather than guessing) plus editable alt text/caption/description/decorative flag with missing-alt warning; shared MediaPickerComponent (already the one reusable picker used by content management) gains type filter, a recent shortcut, and keyboard grid navigation.
Sprint 22.
- MediaAsset gains folder (flat) and MediaListParams gains folder/tag
filters; MediaRepository.listFolders() derives the folder list from
existing records
- upload validation: 10MB size cap, mime allow-list (jpeg/png/webp/gif/
svg+xml/pdf), real error messages surfaced through MediaLibraryFacade
instead of a generic swallowed string
- SVG uploads are sanitized (script tags and on*= attributes stripped)
before storage
- raster images (excl. gif) are downscaled to a 2000px max dimension and
re-encoded via canvas before storage - compression, not a crop UI
- tag editing (window.prompt, comma-separated) via
MediaLibraryFacade.updateTags()
- MediaPickerComponent wired into Project Editor branding (logo, compact
logo, favicon) alongside its existing category/product usage - confirmed
no image fields exist on Static Pages or as a dedicated hero field to
wire
docs/ADMIN.md updated with the new Sprint 22 section including the storage
abstraction note (MediaRepository was already the abstraction).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.