compiling project documentation
This commit is contained in:
331
docs/__temp/FRONTEND/FRONTEND_ALPINE_PAGE_TEMPLATE.md
Normal file
331
docs/__temp/FRONTEND/FRONTEND_ALPINE_PAGE_TEMPLATE.md
Normal file
@@ -0,0 +1,331 @@
|
||||
# Alpine.js Page Template - Quick Reference
|
||||
|
||||
## ✅ Correct Page Structure
|
||||
|
||||
```javascript
|
||||
// static/admin/js/your-page.js
|
||||
|
||||
// 1. Setup logging (optional but recommended)
|
||||
const YOUR_PAGE_LOG_LEVEL = 3;
|
||||
|
||||
const yourPageLog = {
|
||||
error: (...args) => YOUR_PAGE_LOG_LEVEL >= 1 && console.error('❌ [YOUR_PAGE ERROR]', ...args),
|
||||
warn: (...args) => YOUR_PAGE_LOG_LEVEL >= 2 && console.warn('⚠️ [YOUR_PAGE WARN]', ...args),
|
||||
info: (...args) => YOUR_PAGE_LOG_LEVEL >= 3 && console.info('ℹ️ [YOUR_PAGE INFO]', ...args),
|
||||
debug: (...args) => YOUR_PAGE_LOG_LEVEL >= 4 && console.log('🔍 [YOUR_PAGE DEBUG]', ...args)
|
||||
};
|
||||
|
||||
// 2. Create your Alpine.js component
|
||||
function yourPageComponent() {
|
||||
return {
|
||||
// ✅ CRITICAL: Inherit base layout functionality
|
||||
...data(),
|
||||
|
||||
// ✅ CRITICAL: Set page identifier
|
||||
currentPage: 'your-page',
|
||||
|
||||
// Your page-specific state
|
||||
items: [],
|
||||
loading: false,
|
||||
error: null,
|
||||
|
||||
// ✅ CRITICAL: Proper initialization with guard
|
||||
async init() {
|
||||
yourPageLog.info('=== YOUR PAGE INITIALIZING ===');
|
||||
|
||||
// Prevent multiple initializations
|
||||
if (window._yourPageInitialized) {
|
||||
yourPageLog.warn('Page already initialized, skipping...');
|
||||
return;
|
||||
}
|
||||
window._yourPageInitialized = true;
|
||||
|
||||
// Load your data
|
||||
await this.loadData();
|
||||
|
||||
yourPageLog.info('=== YOUR PAGE INITIALIZATION COMPLETE ===');
|
||||
},
|
||||
|
||||
// Your methods
|
||||
async loadData() {
|
||||
yourPageLog.info('Loading data...');
|
||||
this.loading = true;
|
||||
this.error = null;
|
||||
|
||||
try {
|
||||
const startTime = Date.now();
|
||||
// ✅ CRITICAL: Use lowercase apiClient
|
||||
const response = await apiClient.get('/your/endpoint');
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
this.items = response.items || [];
|
||||
|
||||
yourPageLog.info(`Data loaded in ${duration}ms`, {
|
||||
count: this.items.length
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
yourPageLog.error('Failed to load data:', error);
|
||||
this.error = error.message;
|
||||
Utils.showToast('Failed to load data', 'error');
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
// Format date helper (if needed)
|
||||
formatDate(dateString) {
|
||||
if (!dateString) return '-';
|
||||
return Utils.formatDate(dateString);
|
||||
},
|
||||
|
||||
// Your other methods...
|
||||
};
|
||||
}
|
||||
|
||||
yourPageLog.info('Your page module loaded');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Checklist for New Pages
|
||||
|
||||
### HTML Template
|
||||
```jinja2
|
||||
{# app/templates/admin/your-page.html #}
|
||||
{% extends "admin/base.html" %}
|
||||
|
||||
{% block title %}Your Page{% endblock %}
|
||||
|
||||
{# ✅ CRITICAL: Link to your Alpine.js component #}
|
||||
{% block alpine_data %}yourPageComponent(){% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Your page content -->
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
{# ✅ CRITICAL: Load your JavaScript file #}
|
||||
<script src="{{ url_for('static', path='admin/js/your-page.js') }}"></script>
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
### JavaScript File Checklist
|
||||
|
||||
- [ ] ✅ Logging setup (optional)
|
||||
- [ ] ✅ Function name matches `alpine_data` in template
|
||||
- [ ] ✅ `...data(),` at start of return object
|
||||
- [ ] ✅ `currentPage: 'your-page'` set
|
||||
- [ ] ✅ Initialization guard in `init()`
|
||||
- [ ] ✅ Use lowercase `apiClient` for API calls
|
||||
- [ ] ✅ Use your custom logger (not `Logger`)
|
||||
- [ ] ✅ Performance tracking with `Date.now()` (optional)
|
||||
- [ ] ✅ Module loaded log at end
|
||||
|
||||
---
|
||||
|
||||
## ❌ Common Mistakes to Avoid
|
||||
|
||||
### 1. Missing Base Inheritance
|
||||
```javascript
|
||||
// ❌ WRONG
|
||||
function myPage() {
|
||||
return {
|
||||
items: [],
|
||||
// Missing ...data()
|
||||
};
|
||||
}
|
||||
|
||||
// ✅ CORRECT
|
||||
function myPage() {
|
||||
return {
|
||||
...data(), // Must be first!
|
||||
items: [],
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Wrong API Client Name
|
||||
```javascript
|
||||
// ❌ WRONG - Capital letters
|
||||
await ApiClient.get('/endpoint');
|
||||
await API_CLIENT.get('/endpoint');
|
||||
|
||||
// ✅ CORRECT - lowercase
|
||||
await apiClient.get('/endpoint');
|
||||
```
|
||||
|
||||
### 3. Missing Init Guard
|
||||
```javascript
|
||||
// ❌ WRONG
|
||||
async init() {
|
||||
await this.loadData();
|
||||
}
|
||||
|
||||
// ✅ CORRECT
|
||||
async init() {
|
||||
if (window._myPageInitialized) return;
|
||||
window._myPageInitialized = true;
|
||||
await this.loadData();
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Missing currentPage
|
||||
```javascript
|
||||
// ❌ WRONG
|
||||
return {
|
||||
...data(),
|
||||
items: [],
|
||||
// Missing currentPage
|
||||
};
|
||||
|
||||
// ✅ CORRECT
|
||||
return {
|
||||
...data(),
|
||||
currentPage: 'my-page', // Must set this!
|
||||
items: [],
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 API Client Pattern
|
||||
|
||||
### GET Request
|
||||
```javascript
|
||||
try {
|
||||
const response = await apiClient.get('/endpoint');
|
||||
this.data = response;
|
||||
} catch (error) {
|
||||
console.error('Failed:', error);
|
||||
Utils.showToast('Failed to load', 'error');
|
||||
}
|
||||
```
|
||||
|
||||
### POST Request
|
||||
```javascript
|
||||
try {
|
||||
const response = await apiClient.post('/endpoint', {
|
||||
name: 'value',
|
||||
// ... data
|
||||
});
|
||||
Utils.showToast('Created successfully', 'success');
|
||||
} catch (error) {
|
||||
console.error('Failed:', error);
|
||||
Utils.showToast('Failed to create', 'error');
|
||||
}
|
||||
```
|
||||
|
||||
### PUT Request
|
||||
```javascript
|
||||
try {
|
||||
const response = await apiClient.put('/endpoint/123', {
|
||||
name: 'updated value'
|
||||
});
|
||||
Utils.showToast('Updated successfully', 'success');
|
||||
} catch (error) {
|
||||
console.error('Failed:', error);
|
||||
Utils.showToast('Failed to update', 'error');
|
||||
}
|
||||
```
|
||||
|
||||
### DELETE Request
|
||||
```javascript
|
||||
try {
|
||||
await apiClient.delete('/endpoint/123');
|
||||
Utils.showToast('Deleted successfully', 'success');
|
||||
await this.reloadData();
|
||||
} catch (error) {
|
||||
console.error('Failed:', error);
|
||||
Utils.showToast('Failed to delete', 'error');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Common UI Patterns
|
||||
|
||||
### Loading State
|
||||
```javascript
|
||||
async loadData() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const data = await apiClient.get('/endpoint');
|
||||
this.items = data;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
```javascript
|
||||
async loadData() {
|
||||
this.loading = true;
|
||||
this.error = null;
|
||||
try {
|
||||
const data = await apiClient.get('/endpoint');
|
||||
this.items = data;
|
||||
} catch (error) {
|
||||
this.error = error.message;
|
||||
Utils.showToast('Failed to load', 'error');
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Refresh/Reload
|
||||
```javascript
|
||||
async refresh() {
|
||||
console.info('Refreshing...');
|
||||
await this.loadData();
|
||||
Utils.showToast('Refreshed successfully', 'success');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Available Utilities
|
||||
|
||||
### From `init-alpine.js` (via `...data()`)
|
||||
- `this.dark` - Dark mode state
|
||||
- `this.toggleTheme()` - Toggle theme
|
||||
- `this.isSideMenuOpen` - Side menu state
|
||||
- `this.toggleSideMenu()` - Toggle side menu
|
||||
- `this.closeSideMenu()` - Close side menu
|
||||
- `this.isNotificationsMenuOpen` - Notifications menu state
|
||||
- `this.toggleNotificationsMenu()` - Toggle notifications
|
||||
- `this.closeNotificationsMenu()` - Close notifications
|
||||
- `this.isProfileMenuOpen` - Profile menu state
|
||||
- `this.toggleProfileMenu()` - Toggle profile menu
|
||||
- `this.closeProfileMenu()` - Close profile menu
|
||||
- `this.isPagesMenuOpen` - Pages menu state
|
||||
- `this.togglePagesMenu()` - Toggle pages menu
|
||||
|
||||
### From `Utils` (global)
|
||||
- `Utils.showToast(message, type, duration)` - Show toast notification
|
||||
- `Utils.formatDate(dateString)` - Format date for display
|
||||
- `Utils.confirm(message, title)` - Show confirmation dialog (if available)
|
||||
|
||||
### From `apiClient` (global)
|
||||
- `apiClient.get(url)` - GET request
|
||||
- `apiClient.post(url, data)` - POST request
|
||||
- `apiClient.put(url, data)` - PUT request
|
||||
- `apiClient.delete(url)` - DELETE request
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start Template Files
|
||||
|
||||
Copy these to create a new page:
|
||||
|
||||
1. Copy `dashboard.js` → rename to `your-page.js`
|
||||
2. Replace function name: `adminDashboard()` → `yourPageComponent()`
|
||||
3. Update logging prefix: `dashLog` → `yourPageLog`
|
||||
4. Update init flag: `_dashboardInitialized` → `_yourPageInitialized`
|
||||
5. Update `currentPage`: `'dashboard'` → `'your-page'`
|
||||
6. Replace data loading logic with your endpoints
|
||||
7. Update HTML template to use your function name
|
||||
|
||||
Done! ✅
|
||||
Reference in New Issue
Block a user