diff --git a/docs/guides/media-library.md b/docs/guides/media-library.md new file mode 100644 index 00000000..d44991cb --- /dev/null +++ b/docs/guides/media-library.md @@ -0,0 +1,182 @@ +# Media Library + +The media library provides centralized management of uploaded files (images, documents) for vendors. Each vendor has their own isolated media storage. + +## Overview + +- **Storage Location**: `uploads/vendors/{vendor_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 vendor: + +``` +GET /api/v1/admin/media/vendors/{vendor_id} # List vendor's media +POST /api/v1/admin/media/vendors/{vendor_id}/upload # Upload file +GET /api/v1/admin/media/vendors/{vendor_id}/{id} # Get media details +DELETE /api/v1/admin/media/vendors/{vendor_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/vendors/1/products/abc123.jpg", + "url": "/uploads/vendors/1/products/abc123.jpg", + "thumbnail_url": "/uploads/vendors/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', + vendor_id_var='vendorId', + title='Select Image' +) }} + +{# Multiple image selection #} +{{ media_picker_modal( + id='media-picker-additional', + show_var='showMediaPickerAdditional', + vendor_id_var='vendorId', + 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.vendorId, false), + + vendorId: 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/ +└── vendors/ + └── {vendor_id}/ + ├── products/ # Product images + ├── general/ # General uploads + └── thumbnails/ # Auto-generated thumbnails +``` + +### URL Paths + +Files are served from `/uploads/` path: +- Full image: `/uploads/vendors/1/products/image.jpg` +- Thumbnail: `/uploads/vendors/1/thumbnails/thumb_image.jpg` + +## Database Model + +```python +class MediaFile(Base): + id: int + vendor_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 vendor's media library +- Uploading new images directly +- Entering external URLs manually diff --git a/mkdocs.yml b/mkdocs.yml index 2483bc26..1a6d3fb8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -218,6 +218,7 @@ nav: - User Guides: - User Management: guides/user-management.md - Product Management: guides/product-management.md + - Media Library: guides/media-library.md - Inventory Management: guides/inventory-management.md - Subscription Tier Management: guides/subscription-tier-management.md - Email Settings: guides/email-settings.md