203
docs/FRAMEWORK_README.md
Normal file
203
docs/FRAMEWORK_README.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# SPORE UI Framework
|
||||
|
||||
A clean, component-based frontend framework with pub/sub communication and view models.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
The framework follows a clean architecture pattern with the following layers:
|
||||
|
||||
1. **Components** - Handle UI rendering and user interactions
|
||||
2. **View Models** - Hold data and business logic
|
||||
3. **API Client** - Communicate with the backend
|
||||
4. **Event Bus** - Pub/sub communication between components
|
||||
5. **Framework Core** - Base classes and application management
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Component-based architecture** - Reusable, self-contained UI components
|
||||
- **View Models** - Data flows from backend → view model → UI rendering
|
||||
- **Pub/Sub system** - Components communicate through events
|
||||
- **Automatic cleanup** - Event listeners and subscriptions are automatically cleaned up
|
||||
- **Type-safe property access** - View models provide get/set methods with change notifications
|
||||
- **Routing** - Built-in navigation between views
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
public/
|
||||
├── framework.js # Core framework classes
|
||||
├── api-client.js # Backend API communication
|
||||
├── view-models.js # View models for each component
|
||||
├── components.js # UI components
|
||||
├── app.js # Main application setup
|
||||
├── index.html # HTML template
|
||||
└── styles.css # Styling
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### 1. Creating a View Model
|
||||
|
||||
```javascript
|
||||
class MyViewModel extends ViewModel {
|
||||
constructor() {
|
||||
super();
|
||||
this.setMultiple({
|
||||
data: [],
|
||||
isLoading: false,
|
||||
error: null
|
||||
});
|
||||
}
|
||||
|
||||
async loadData() {
|
||||
try {
|
||||
this.set('isLoading', true);
|
||||
const data = await window.apiClient.getData();
|
||||
this.set('data', data);
|
||||
} catch (error) {
|
||||
this.set('error', error.message);
|
||||
} finally {
|
||||
this.set('isLoading', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Creating a Component
|
||||
|
||||
```javascript
|
||||
class MyComponent extends Component {
|
||||
constructor(container, viewModel, eventBus) {
|
||||
super(container, viewModel, eventBus);
|
||||
}
|
||||
|
||||
setupEventListeners() {
|
||||
const button = this.findElement('.my-button');
|
||||
if (button) {
|
||||
this.addEventListener(button, 'click', this.handleClick.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
setupViewModelListeners() {
|
||||
this.subscribeToProperty('data', this.render.bind(this));
|
||||
this.subscribeToProperty('isLoading', this.render.bind(this));
|
||||
this.subscribeToProperty('error', this.render.bind(this));
|
||||
}
|
||||
|
||||
render() {
|
||||
const data = this.viewModel.get('data');
|
||||
const isLoading = this.viewModel.get('isLoading');
|
||||
const error = this.viewModel.get('error');
|
||||
|
||||
if (isLoading) {
|
||||
this.setHTML('', '<div>Loading...</div>');
|
||||
return;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
this.setHTML('', `<div class="error">${error}</div>`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setHTML('', `<div>${this.renderData(data)}</div>`);
|
||||
}
|
||||
|
||||
renderData(data) {
|
||||
return data.map(item => `<div>${item.name}</div>`).join('');
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
// Handle user interaction
|
||||
this.viewModel.loadData();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Using the Event Bus
|
||||
|
||||
```javascript
|
||||
// Subscribe to events
|
||||
this.subscribeToEvent('user-logged-in', (userData) => {
|
||||
console.log('User logged in:', userData);
|
||||
});
|
||||
|
||||
// Publish events
|
||||
this.viewModel.publish('data-updated', { timestamp: Date.now() });
|
||||
```
|
||||
|
||||
### 4. Component Helper Methods
|
||||
|
||||
The framework provides several helper methods for common DOM operations:
|
||||
|
||||
```javascript
|
||||
// Find elements
|
||||
const element = this.findElement('.my-class');
|
||||
const elements = this.findAllElements('.my-class');
|
||||
|
||||
// Update content
|
||||
this.setHTML('.my-container', '<div>New content</div>');
|
||||
this.setText('.my-text', 'New text');
|
||||
|
||||
// Manage classes
|
||||
this.setClass('.my-element', 'active', true);
|
||||
this.setClass('.my-element', 'hidden', false);
|
||||
|
||||
// Show/hide elements
|
||||
this.setVisible('.my-element', false);
|
||||
this.setEnabled('.my-button', false);
|
||||
|
||||
// Manage styles
|
||||
this.setStyle('.my-element', 'color', 'red');
|
||||
```
|
||||
|
||||
### 5. Registering Routes
|
||||
|
||||
```javascript
|
||||
// In app.js
|
||||
window.app.registerRoute('my-view', MyComponent, 'my-view-container');
|
||||
```
|
||||
|
||||
### 6. Navigation
|
||||
|
||||
```javascript
|
||||
// Navigate to a route
|
||||
window.app.navigateTo('my-view');
|
||||
```
|
||||
|
||||
## Data Flow
|
||||
|
||||
1. **User Interaction** → Component handles event
|
||||
2. **Component** → Calls view model method
|
||||
3. **View Model** → Makes API call or processes data
|
||||
4. **View Model** → Updates properties (triggers change notifications)
|
||||
5. **Component** → Receives change notification and re-renders
|
||||
6. **UI** → Updates to reflect new data
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Keep components focused** - Each component should have a single responsibility
|
||||
2. **Use view models for business logic** - Don't put API calls or data processing in components
|
||||
3. **Subscribe to specific properties** - Only listen to properties your component needs
|
||||
4. **Use the event bus sparingly** - Prefer direct view model communication for related components
|
||||
5. **Clean up resources** - The framework handles most cleanup automatically, but be mindful of custom event listeners
|
||||
6. **Error handling** - Always handle errors in async operations and update the view model accordingly
|
||||
|
||||
## Migration from Old Code
|
||||
|
||||
The old monolithic `script.js` has been broken down into:
|
||||
|
||||
- **API calls** → `api-client.js`
|
||||
- **Data management** → `view-models.js`
|
||||
- **UI logic** → `components.js`
|
||||
- **Application setup** → `app.js`
|
||||
|
||||
Each piece is now more focused, testable, and maintainable.
|
||||
|
||||
## Benefits
|
||||
|
||||
- **Maintainability** - Smaller, focused files are easier to understand and modify
|
||||
- **Testability** - View models can be tested independently of UI
|
||||
- **Reusability** - Components can be reused across different views
|
||||
- **Scalability** - Easy to add new features without affecting existing code
|
||||
- **Debugging** - Clear separation of concerns makes issues easier to track down
|
||||
- **Performance** - Components only re-render when their specific data changes
|
||||
Reference in New Issue
Block a user