# Media Library The media library provides centralized management of uploaded files (images, documents) for stores. Each store has their own isolated media storage. ## Overview - **Storage Location**: `uploads/stores/{store_id}/{folder}/` - **Supported Types**: Images (JPG, PNG, GIF, WebP), Documents (PDF) - **Max File Size**: 10MB per file - **Automatic Thumbnails**: Generated for images (200x200px) ## API Endpoints ### Admin Media Management Admins can manage media for any store: ``` GET /api/v1/admin/media/stores/{store_id} # List store's media POST /api/v1/admin/media/stores/{store_id}/upload # Upload file GET /api/v1/admin/media/stores/{store_id}/{id} # Get media details DELETE /api/v1/admin/media/stores/{store_id}/{id} # Delete media ``` ### Query Parameters | Parameter | Type | Description | |-----------|------|-------------| | `skip` | int | Pagination offset (default: 0) | | `limit` | int | Items per page (default: 100, max: 1000) | | `media_type` | string | Filter by type: `image`, `video`, `document` | | `folder` | string | Filter by folder: `products`, `general`, etc. | | `search` | string | Search by filename | ### Upload Response ```json { "success": true, "message": "File uploaded successfully", "media": { "id": 1, "filename": "product-image.jpg", "file_url": "/uploads/stores/1/products/abc123.jpg", "url": "/uploads/stores/1/products/abc123.jpg", "thumbnail_url": "/uploads/stores/1/thumbnails/thumb_abc123.jpg", "media_type": "image", "file_size": 245760, "width": 1200, "height": 800 } } ``` ## Media Picker Component A reusable Alpine.js component for selecting images from the media library. ### Usage in Templates ```jinja2 {% from 'shared/macros/modals.html' import media_picker_modal %} {# Single image selection #} {{ media_picker_modal( id='media-picker-main', show_var='showMediaPicker', store_id_var='storeId', title='Select Image' ) }} {# Multiple image selection #} {{ media_picker_modal( id='media-picker-additional', show_var='showMediaPickerAdditional', store_id_var='storeId', multi_select=true, title='Select Additional Images' ) }} ``` ### JavaScript Integration Include the media picker mixin in your Alpine.js component: ```javascript function myComponent() { return { ...data(), // Include media picker functionality ...mediaPickerMixin(() => this.storeId, false), storeId: null, // Override to handle selected image setMainImage(media) { this.form.image_url = media.url; }, // Override for multiple images addAdditionalImages(mediaList) { const urls = mediaList.map(m => m.url); this.form.additional_images.push(...urls); } }; } ``` ### Media Picker Mixin API | Property/Method | Description | |-----------------|-------------| | `showMediaPicker` | Boolean to show/hide main image picker modal | | `showMediaPickerAdditional` | Boolean to show/hide additional images picker | | `mediaPickerState` | Object containing loading, media array, selected items | | `openMediaPickerMain()` | Open picker for main image | | `openMediaPickerAdditional()` | Open picker for additional images | | `loadMediaLibrary()` | Fetch media from API | | `uploadMediaFile(event)` | Handle file upload | | `toggleMediaSelection(media)` | Select/deselect a media item | | `confirmMediaSelection()` | Confirm selection and call callbacks | | `setMainImage(media)` | Override to handle main image selection | | `addAdditionalImages(mediaList)` | Override to handle multiple selections | ## File Storage ### Directory Structure ``` uploads/ └── stores/ └── {store_id}/ ├── products/ # Product images ├── general/ # General uploads └── thumbnails/ # Auto-generated thumbnails ``` ### URL Paths Files are served from `/uploads/` path: - Full image: `/uploads/stores/1/products/image.jpg` - Thumbnail: `/uploads/stores/1/thumbnails/thumb_image.jpg` ## Database Model ```python class MediaFile(Base): id: int store_id: int filename: str # Stored filename (UUID-based) original_filename: str # Original upload name file_path: str # Relative path from uploads/ thumbnail_path: str # Thumbnail relative path media_type: str # image, video, document mime_type: str # image/jpeg, etc. file_size: int # Bytes width: int # Image width height: int # Image height folder: str # products, general, etc. ``` ## Product Images Products support both a main image and additional images: ```python class Product(Base): primary_image_url: str # Main product image additional_images: list[str] # Array of additional image URLs ``` ### In Product Forms The product create/edit forms include: 1. **Main Image**: Single image with preview and media picker 2. **Additional Images**: Grid of images with add/remove functionality Both support: - Browsing the store's media library - Uploading new images directly - Entering external URLs manually