525 lines
16 KiB
Markdown
525 lines
16 KiB
Markdown
# Frontend Components Specification
|
|
|
|
## Architecture Overview
|
|
|
|
Single Page Application built with Vue.js 3 and Inertia.js, providing a responsive image gallery interface with real-time AI processing capabilities.
|
|
|
|
## Technology Stack
|
|
|
|
- **Framework**: Vue.js 3.5.18 with Composition API
|
|
- **Routing**: Inertia.js 1.3.0 (Laravel backend integration)
|
|
- **Build Tool**: Vite 5.4.19
|
|
- **Styling**: Tailwind CSS 3.4.17
|
|
- **HTTP Client**: Axios 1.11.0
|
|
- **State Management**: Vue 3 Composition API (ref, computed, reactive)
|
|
- **Real-time**: WebSocket for ComfyUI progress, polling for other providers
|
|
|
|
## Component Hierarchy
|
|
|
|
```
|
|
App.vue (Root)
|
|
└── Home.vue (Main Gallery Page)
|
|
├── GalleryGrid.vue (Image Grid Display)
|
|
├── Navigation.vue (Pagination Controls)
|
|
├── ImageContextMenu.vue (Image Actions Overlay)
|
|
│ └── StyleSelector.vue (Style Selection Interface)
|
|
├── StyledImageDisplay.vue (Result Preview)
|
|
├── LoadingSpinner.vue (Progress Indicator)
|
|
└── PrintQuantityModal.vue (Print Options)
|
|
```
|
|
|
|
## Component Specifications
|
|
|
|
### 1. Home.vue (Main Gallery Page)
|
|
|
|
**Purpose**: Primary interface displaying user's image gallery with pagination and overlay management
|
|
|
|
**Location**: `resources/js/Pages/Home.vue`
|
|
|
|
**Props**:
|
|
```typescript
|
|
interface Props {
|
|
galleryHeading: string // Page title
|
|
translations: object // Internationalization strings
|
|
}
|
|
```
|
|
|
|
**State Management**:
|
|
```typescript
|
|
const images = ref([]) // Gallery images array
|
|
const currentPage = ref(1) // Current pagination page
|
|
const currentOverlayComponent = ref(null) // Active overlay ('contextMenu', 'styleSelector', etc.)
|
|
const contextMenuPosition = ref({ x: 0, y: 0 }) // Context menu coordinates
|
|
const selectedImage = ref(null) // Currently selected image
|
|
const styledImage = ref(null) // Newly processed styled image
|
|
const processingProgress = ref(0) // AI processing progress (0-100)
|
|
const errorMessage = ref(null) // Error display state
|
|
const isLoading = ref(false) // Global loading state
|
|
const currentTheme = ref('light') // UI theme preference
|
|
```
|
|
|
|
**Key Methods**:
|
|
|
|
#### `fetchImages()`
|
|
- **Purpose**: Retrieves and synchronizes gallery images
|
|
- **Implementation**: Axios GET to `/api/images`
|
|
- **Auto-refresh**: Polls every 5 seconds (configurable interval)
|
|
- **Error Handling**: Displays user-friendly error messages
|
|
|
|
#### `applyStyle(style, imageId)`
|
|
- **Purpose**: Initiates AI style transformation process
|
|
- **Flow**:
|
|
1. Sends style change request to backend
|
|
2. Receives `prompt_id` and `plugin` type
|
|
3. Establishes appropriate progress monitoring (WebSocket vs Polling)
|
|
4. Updates UI with real-time progress
|
|
5. Displays result when complete
|
|
|
|
#### `showContextMenu(image, event)`
|
|
- **Purpose**: Displays context menu for selected image
|
|
- **Positioning**: Calculates optimal position based on click coordinates
|
|
- **Responsive**: Adapts to screen boundaries
|
|
|
|
**UI Structure**:
|
|
- **Header**: Title and theme toggle
|
|
- **Gallery**: Grid layout with pagination
|
|
- **Overlays**: Conditional rendering based on `currentOverlayComponent`
|
|
- **Notifications**: Error messages with auto-dismiss
|
|
|
|
**Styling**:
|
|
- **Layout**: Flexbox-based responsive design
|
|
- **Theme**: Light/dark mode support with CSS variables
|
|
- **Responsive**: Mobile-first approach with touch gestures
|
|
|
|
---
|
|
|
|
### 2. GalleryGrid.vue
|
|
|
|
**Purpose**: Displays images in responsive grid layout with interaction handling
|
|
|
|
**Props**:
|
|
```typescript
|
|
interface Props {
|
|
images: Image[] // Array of image objects to display
|
|
translations: object // UI text translations
|
|
}
|
|
```
|
|
|
|
**Events**:
|
|
```typescript
|
|
interface Events {
|
|
imageTapped: [image: Image, event: MouseEvent] // Image selection
|
|
}
|
|
```
|
|
|
|
**Features**:
|
|
- **Responsive Grid**: Adaptive columns based on screen size
|
|
- **Lazy Loading**: Images load as they enter viewport
|
|
- **Touch Support**: Tap gestures for mobile devices
|
|
- **Accessibility**: Proper alt text and keyboard navigation
|
|
|
|
**Image Object Structure**:
|
|
```typescript
|
|
interface Image {
|
|
image_id: number
|
|
path: string // URL to image file
|
|
name: string // Filename
|
|
is_temp: boolean // Temporary styled image flag
|
|
is_public: boolean // Visibility status
|
|
is_new: boolean // Recently uploaded flag
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 3. ImageContextMenu.vue
|
|
|
|
**Purpose**: Contextual action menu displayed when user taps/clicks an image
|
|
|
|
**Location**: `resources/js/Components/ImageContextMenu.vue`
|
|
|
|
**Props**:
|
|
```typescript
|
|
interface Props {
|
|
position: { x: number, y: number } // Menu position coordinates
|
|
image: Image // Selected image object
|
|
}
|
|
```
|
|
|
|
**Events**:
|
|
```typescript
|
|
interface Events {
|
|
close: [] // Close menu
|
|
print: [image: Image] // Print image
|
|
changeStyle: [] // Open style selector
|
|
styleSelected: [style: Style, imageId: number] // Style applied
|
|
}
|
|
```
|
|
|
|
**Layout Structure**:
|
|
```
|
|
┌─────────────────────────────────────────────────┐
|
|
│ [X] Close [Image Preview] │
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────┐ │
|
|
│ │ ▲ │ │
|
|
│ │ Image Preview │ │
|
|
│ │ ▼ │ │
|
|
│ │ (70% width) │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
│ ┌─────────────────────────────────────────────┐ │
|
|
│ │ [Print] [Change Style] [Close] │ │
|
|
│ │ (30% width) │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**Features**:
|
|
- **Dynamic Positioning**: Calculates optimal position to stay within viewport
|
|
- **Backdrop Click**: Closes menu when clicking outside
|
|
- **Nested Components**: Embeds StyleSelector when needed
|
|
- **Responsive**: Adapts layout for different screen sizes
|
|
|
|
**Styling**:
|
|
- **Overlay**: Semi-transparent backdrop with blur effect
|
|
- **Menu**: Elevated card with shadow and rounded corners
|
|
- **Responsive**: Touch-friendly button sizes on mobile
|
|
|
|
---
|
|
|
|
### 4. StyleSelector.vue
|
|
|
|
**Purpose**: Allows users to browse and select AI styles for image transformation
|
|
|
|
**Props**:
|
|
```typescript
|
|
interface Props {
|
|
image_id: number // Target image for styling
|
|
}
|
|
```
|
|
|
|
**Events**:
|
|
```typescript
|
|
interface Events {
|
|
styleSelected: [style: Style, imageId: number] // Style chosen
|
|
back: [] // Return to context menu
|
|
close: [] // Close selector
|
|
}
|
|
```
|
|
|
|
**State Management**:
|
|
```typescript
|
|
const styles = ref([]) // Available styles array
|
|
// Lazy loading management
|
|
const observer = ref(null) // IntersectionObserver instance
|
|
```
|
|
|
|
**Key Methods**:
|
|
|
|
#### `fetchStyles()`
|
|
- **Purpose**: Retrieves available styles from API
|
|
- **Implementation**: Axios GET to `/api/styles`
|
|
- **Filtering**: Only enabled styles returned
|
|
- **Lazy Loading**: Sets up IntersectionObserver for preview images
|
|
|
|
#### `selectStyle(style)`
|
|
- **Purpose**: Confirms style selection and triggers processing
|
|
- **Implementation**: Emits `styleSelected` event with style and image ID
|
|
|
|
**UI Structure**:
|
|
```
|
|
┌─────────────────────────────────────────────────┐
|
|
│ [<] Back Available Styles │
|
|
├─────────────────────────────────────────────────┤
|
|
│ ┌─────────────────────────────────────────────┐ │
|
|
│ │ [Preview] Style Name [Description] │ │
|
|
│ │ [Preview] Another Style [Description] │ │
|
|
│ │ [Preview] Third Style [Description] │ │
|
|
│ └─────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**Features**:
|
|
- **Preview Images**: Thumbnail images for each style
|
|
- **Lazy Loading**: Images load when entering viewport
|
|
- **Back Navigation**: Return to previous context menu
|
|
- **Responsive**: Scrollable list on smaller screens
|
|
|
|
**Style Object Structure**:
|
|
```typescript
|
|
interface Style {
|
|
id: number
|
|
title: string // Display name
|
|
description: string // Human-readable description
|
|
preview_image: string // Thumbnail image path
|
|
enabled: boolean // Availability status
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 5. LoadingSpinner.vue
|
|
|
|
**Purpose**: Visual indicator for AI processing progress
|
|
|
|
**Props**:
|
|
```typescript
|
|
interface Props {
|
|
progress: number // Progress percentage (0-100)
|
|
}
|
|
```
|
|
|
|
**Features**:
|
|
- **Progress Bar**: Visual representation of completion status
|
|
- **Animated**: Smooth progress updates
|
|
- **Responsive**: Adapts to different screen sizes
|
|
- **Accessible**: Screen reader compatible
|
|
|
|
**Styling**:
|
|
- **Modern Design**: Gradient progress bar with smooth animations
|
|
- **Centered**: Overlay positioning for full-screen processes
|
|
- **Theme Aware**: Adapts to light/dark theme
|
|
|
|
---
|
|
|
|
### 6. StyledImageDisplay.vue
|
|
|
|
**Purpose**: Preview and management interface for completed AI-styled images
|
|
|
|
**Props**:
|
|
```typescript
|
|
interface Props {
|
|
image: Image // Styled image object
|
|
}
|
|
```
|
|
|
|
**Events**:
|
|
```typescript
|
|
interface Events {
|
|
keep: [image: Image] // Keep styled image permanently
|
|
delete: [image: Image] // Discard styled image
|
|
}
|
|
```
|
|
|
|
**Features**:
|
|
- **Full Preview**: Large display of styled result
|
|
- **Action Buttons**: Keep/Discard options
|
|
- **Responsive**: Mobile-optimized layout
|
|
- **Loading State**: Handles image loading gracefully
|
|
|
|
---
|
|
|
|
### 7. Navigation.vue
|
|
|
|
**Purpose**: Pagination controls for gallery navigation
|
|
|
|
**Props**:
|
|
```typescript
|
|
interface Props {
|
|
currentPage: number // Current active page
|
|
totalPages: number // Total available pages
|
|
}
|
|
```
|
|
|
|
**Events**:
|
|
```typescript
|
|
interface Events {
|
|
prevPage: [] // Navigate to previous page
|
|
nextPage: [] // Navigate to next page
|
|
}
|
|
```
|
|
|
|
**Features**:
|
|
- **Page Numbers**: Visual page indicators
|
|
- **Touch Gestures**: Swipe left/right for page navigation
|
|
- **Responsive**: Touch-friendly on mobile devices
|
|
- **Keyboard**: Arrow key navigation support
|
|
|
|
---
|
|
|
|
### 8. PrintQuantityModal.vue
|
|
|
|
**Purpose**: Print options interface for physical image printing
|
|
|
|
**Props**:
|
|
```typescript
|
|
interface Props {
|
|
maxCopies: number // Maximum allowed copies
|
|
}
|
|
```
|
|
|
|
**Events**:
|
|
```typescript
|
|
interface Events {
|
|
close: [] // Close modal
|
|
printConfirmed: [quantity: number] // Print confirmed
|
|
}
|
|
```
|
|
|
|
**Features**:
|
|
- **Quantity Selection**: Number input for copy count
|
|
- **Validation**: Enforces maximum copy limits
|
|
- **Confirmation**: Clear confirmation before printing
|
|
- **Responsive**: Modal overlay with backdrop
|
|
|
|
## Component Interactions
|
|
|
|
### Image Selection Flow
|
|
```
|
|
User taps image → GalleryGrid emits imageTapped →
|
|
Home.vue shows contextMenu at tap position →
|
|
ImageContextMenu displays with image preview and options
|
|
```
|
|
|
|
### Style Application Flow
|
|
```
|
|
User selects "Change Style" → ImageContextMenu shows StyleSelector →
|
|
User browses and selects style → StyleSelector emits styleSelected →
|
|
Home.vue initiates AI processing with progress monitoring →
|
|
Real-time updates via WebSocket/Polling → Result displayed →
|
|
User can keep or discard styled image
|
|
```
|
|
|
|
### Progress Monitoring
|
|
|
|
#### ComfyUI (WebSocket)
|
|
```typescript
|
|
// Establish WebSocket connection
|
|
const wsUrl = `ws://${comfyUiHost}/ws`
|
|
const ws = new WebSocket(wsUrl)
|
|
|
|
// Monitor progress messages
|
|
ws.onmessage = (event) => {
|
|
const message = JSON.parse(event.data)
|
|
if (message.type === 'progress' && message.data.prompt_id === currentPromptId) {
|
|
processingProgress.value = (message.data.value / message.data.max) * 100
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Other Providers (Polling)
|
|
```typescript
|
|
// Poll for completion every 2 seconds
|
|
const pollForResult = () => {
|
|
axios.get(`/api/images/fetch-styled/${promptId}`)
|
|
.then(response => {
|
|
// Success - display result
|
|
styledImage.value = response.data.styled_image
|
|
currentOverlayComponent.value = 'styledImageDisplay'
|
|
})
|
|
.catch(error => {
|
|
if (error.response?.status === 404) {
|
|
// Still processing - continue polling
|
|
setTimeout(pollForResult, 2000)
|
|
} else {
|
|
// Error - display message
|
|
showError(error.response?.data?.error)
|
|
}
|
|
})
|
|
}
|
|
```
|
|
|
|
## State Management Patterns
|
|
|
|
### Overlay Management
|
|
- Single active overlay at a time
|
|
- Stack-based navigation (context menu → style selector → back)
|
|
- Proper cleanup on component unmount
|
|
|
|
### Error Handling
|
|
- Centralized error display with auto-dismiss
|
|
- User-friendly error messages
|
|
- Graceful degradation for failed operations
|
|
|
|
### Theme Management
|
|
- Persistent theme preference in localStorage
|
|
- CSS variable-based theming
|
|
- System preference detection
|
|
|
|
## Responsive Design
|
|
|
|
### Breakpoints
|
|
- **Mobile**: < 768px (single column, touch-optimized)
|
|
- **Tablet**: 768px - 1024px (2-3 columns, hybrid interaction)
|
|
- **Desktop**: > 1024px (4+ columns, mouse-optimized)
|
|
|
|
### Touch Interactions
|
|
- **Tap**: Image selection and button activation
|
|
- **Swipe**: Gallery navigation (left/right)
|
|
- **Long Press**: Context menu (mobile equivalent of right-click)
|
|
- **Pinch**: Zoom functionality (future enhancement)
|
|
|
|
## Accessibility Features
|
|
|
|
### ARIA Support
|
|
- Proper semantic HTML structure
|
|
- ARIA labels for interactive elements
|
|
- Screen reader announcements for dynamic content
|
|
|
|
### Keyboard Navigation
|
|
- Tab order for all interactive elements
|
|
- Enter/Space for button activation
|
|
- Escape key for modal dismissal
|
|
- Arrow keys for gallery navigation
|
|
|
|
### Visual Accessibility
|
|
- High contrast mode support
|
|
- Sufficient color contrast ratios
|
|
- Scalable text and UI elements
|
|
- Reduced motion preferences
|
|
|
|
## Performance Optimizations
|
|
|
|
### Image Loading
|
|
- **Lazy Loading**: IntersectionObserver for viewport detection
|
|
- **Progressive Loading**: Blur placeholder → low quality → high quality
|
|
- **Caching**: Browser cache for static assets
|
|
- **Compression**: Optimized image formats (WebP support)
|
|
|
|
### Component Optimization
|
|
- **Conditional Rendering**: Only render active overlays
|
|
- **Event Delegation**: Efficient event handling for large galleries
|
|
- **Memoization**: Computed properties for expensive operations
|
|
- **Code Splitting**: Component-based lazy loading
|
|
|
|
## Internationalization
|
|
|
|
### Translation Structure
|
|
```typescript
|
|
interface Translations {
|
|
api: {
|
|
dark_mode: string
|
|
light_mode: string
|
|
close: string
|
|
print: string
|
|
change_style: string
|
|
}
|
|
}
|
|
```
|
|
|
|
### Implementation
|
|
- Laravel backend provides translations
|
|
- Vue components use translation keys
|
|
- Runtime language switching support
|
|
|
|
## Future Enhancement Opportunities
|
|
|
|
### Component Additions
|
|
- **ImageEditor.vue**: Basic image editing tools
|
|
- **BatchProcessor.vue**: Multi-image style application
|
|
- **GalleryFilters.vue**: Search and filter functionality
|
|
- **UserProfile.vue**: User settings and preferences
|
|
- **AdminDashboard.vue**: Administrative controls
|
|
|
|
### Feature Enhancements
|
|
- **Drag & Drop**: Upload images via drag-and-drop
|
|
- **Keyboard Shortcuts**: Power user productivity features
|
|
- **Offline Support**: PWA capabilities for offline viewing
|
|
- **Social Features**: Share and discover styled images
|
|
- **Advanced Progress**: Detailed processing stage information
|
|
|
|
### Technical Improvements
|
|
- **Virtual Scrolling**: Handle very large galleries efficiently
|
|
- **Service Workers**: Background processing and caching
|
|
- **WebAssembly**: Client-side image processing
|
|
- **Real-time Collaboration**: Multiple users styling same image |