added prp
This commit is contained in:
525
prp/frontend-components.md
Normal file
525
prp/frontend-components.md
Normal file
@@ -0,0 +1,525 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user