refactor: migrate vendor APIs to token-based context and consolidate architecture
## Vendor-in-Token Architecture (Complete Migration) - Migrate all vendor API endpoints from require_vendor_context() to token_vendor_id - Update permission dependencies to extract vendor from JWT token - Add vendor exceptions: VendorAccessDeniedException, VendorOwnerOnlyException, InsufficientVendorPermissionsException - Shop endpoints retain require_vendor_context() for URL-based detection - Add AUTH-004 architecture rule enforcing vendor context patterns - Fix marketplace router missing /marketplace prefix ## Exception Pattern Fixes (API-003/API-004) - Services raise domain exceptions, endpoints let them bubble up - Add code_quality and content_page exception modules - Move business logic from endpoints to services (admin, auth, content_page) - Fix exception handling in admin, shop, and vendor endpoints ## Tailwind CSS Consolidation - Consolidate CSS to per-area files (admin, vendor, shop, platform) - Remove shared/cdn-fallback.html and shared/css/tailwind.min.css - Update all templates to use area-specific Tailwind output files - Remove Node.js config (package.json, postcss.config.js, tailwind.config.js) ## Documentation & Cleanup - Update vendor-in-token-architecture.md with completed migration status - Update architecture-rules.md with new rules - Move migration docs to docs/development/migration/ - Remove duplicate/obsolete documentation files - Merge pytest.ini settings into pyproject.toml 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,131 +1,158 @@
|
||||
# Complete Implementation Guide - Testing Hub, Components & Icons
|
||||
# Admin Sidebar Navigation
|
||||
|
||||
## 🎉 What's Been Created
|
||||
## Overview
|
||||
|
||||
### ✅ All Files Follow Your Alpine.js Architecture Perfectly!
|
||||
The admin sidebar provides navigation across all admin pages. It features collapsible sections with state persistence, active page indicators, and responsive mobile support.
|
||||
|
||||
1. **Testing Hub** - Manual QA tools
|
||||
2. **Components Library** - UI component reference with navigation
|
||||
3. **Icons Browser** - Searchable icon library with copy-to-clipboard
|
||||
4. **Sidebar Fix** - Active menu indicator for all pages
|
||||
**File Location:** `app/templates/admin/partials/sidebar.html`
|
||||
|
||||
---
|
||||
|
||||
## 📦 Files Created
|
||||
## Sidebar Structure
|
||||
|
||||
### JavaScript Files (Alpine.js Components)
|
||||
1. **[testing-hub.js](computer:///mnt/user-data/outputs/testing-hub.js)** - Testing hub component
|
||||
2. **[components.js](computer:///mnt/user-data/outputs/components.js)** - Components library component
|
||||
3. **[icons-page.js](computer:///mnt/user-data/outputs/icons-page.js)** - Icons browser component
|
||||
The sidebar is organized into the following sections:
|
||||
|
||||
### HTML Templates
|
||||
1. **[testing-hub.html](computer:///mnt/user-data/outputs/testing-hub.html)** - Testing hub page
|
||||
2. **[components.html](computer:///mnt/user-data/outputs/components.html)** - Components library page
|
||||
3. **[icons.html](computer:///mnt/user-data/outputs/icons.html)** - Icons browser page
|
||||
|
||||
### Sidebar Update
|
||||
1. **[sidebar-fixed.html](computer:///mnt/user-data/outputs/sidebar-fixed.html)** - Fixed sidebar with active indicators
|
||||
|
||||
### Documentation
|
||||
1. **[ARCHITECTURE_CONFIRMATION.md](computer:///mnt/user-data/outputs/ARCHITECTURE_CONFIRMATION.md)** - Architecture confirmation
|
||||
| Section | Collapsible | Pages |
|
||||
|---------|-------------|-------|
|
||||
| Dashboard | No | Dashboard |
|
||||
| Platform Administration | Yes | Companies, Vendors, Users, Customers, Marketplace |
|
||||
| Content Management | Yes | Platform Homepage, Content Pages, Vendor Themes |
|
||||
| Developer Tools | Yes | Components, Icons, Testing Hub, Code Quality |
|
||||
| Platform Monitoring | Yes | Import Jobs, Application Logs |
|
||||
| Settings | No | Settings |
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Installation Steps
|
||||
## Collapsible Sections
|
||||
|
||||
### Step 1: Install JavaScript Files
|
||||
### How It Works
|
||||
|
||||
```bash
|
||||
# Copy to your static directory
|
||||
cp outputs/testing-hub.js static/admin/js/testing-hub.js
|
||||
cp outputs/components.js static/admin/js/components.js
|
||||
cp outputs/icons-page.js static/admin/js/icons-page.js
|
||||
Sections can be expanded/collapsed by clicking the section header. The state is persisted to `localStorage` so sections remain open/closed across page navigation and browser sessions.
|
||||
|
||||
### State Management
|
||||
|
||||
**File:** `static/admin/js/init-alpine.js`
|
||||
|
||||
```javascript
|
||||
// Default state: Platform Administration open, others closed
|
||||
const defaultSections = {
|
||||
platformAdmin: true,
|
||||
contentMgmt: false,
|
||||
devTools: false,
|
||||
monitoring: false
|
||||
};
|
||||
|
||||
// State stored in localStorage under this key
|
||||
const SIDEBAR_STORAGE_KEY = 'admin_sidebar_sections';
|
||||
```
|
||||
|
||||
### Step 2: Install HTML Templates
|
||||
### Available Methods
|
||||
|
||||
```bash
|
||||
# Copy to your templates directory
|
||||
cp outputs/testing-hub.html app/templates/admin/testing-hub.html
|
||||
cp outputs/components.html app/templates/admin/components.html
|
||||
cp outputs/icons.html app/templates/admin/icons.html
|
||||
```
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `toggleSection(section)` | Toggle a section open/closed |
|
||||
| `expandSectionForCurrentPage()` | Auto-expand section containing current page |
|
||||
| `openSections.platformAdmin` | Check if Platform Administration is open |
|
||||
| `openSections.contentMgmt` | Check if Content Management is open |
|
||||
| `openSections.devTools` | Check if Developer Tools is open |
|
||||
| `openSections.monitoring` | Check if Platform Monitoring is open |
|
||||
|
||||
### Step 3: Fix Sidebar (IMPORTANT!)
|
||||
### CSS Transitions
|
||||
|
||||
```bash
|
||||
# Replace your current sidebar
|
||||
cp outputs/sidebar-fixed.html app/templates/partials/sidebar.html
|
||||
```
|
||||
|
||||
### Step 4: Add Icons Route
|
||||
|
||||
Update `app/api/v1/admin/pages.py` - add this route:
|
||||
|
||||
```python
|
||||
@router.get("/icons", response_class=HTMLResponse, include_in_schema=False)
|
||||
async def admin_icons_page(
|
||||
request: Request,
|
||||
current_user: User = Depends(get_current_admin_from_cookie_or_header),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
Render icons browser page.
|
||||
Browse and search all available icons.
|
||||
"""
|
||||
return templates.TemplateResponse(
|
||||
"admin/icons.html",
|
||||
{
|
||||
"request": request,
|
||||
"user": current_user,
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
### Step 5: Verify Icons Are Updated
|
||||
|
||||
Make sure you're using the updated `icons-updated.js` from earlier:
|
||||
|
||||
```bash
|
||||
cp outputs/icons-updated.js static/shared/js/icons.js
|
||||
```
|
||||
|
||||
### Step 6: Restart Server
|
||||
|
||||
```bash
|
||||
# Stop current server (Ctrl+C)
|
||||
# Start again
|
||||
uvicorn app.main:app --reload
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Sidebar Active Indicator Fix
|
||||
|
||||
### The Problem
|
||||
|
||||
You noticed that only the Dashboard menu item showed the vertical purple bar on the left when active. Other menu items didn't show this indicator.
|
||||
|
||||
### The Root Cause
|
||||
|
||||
Each page's JavaScript component needs to set `currentPage` correctly, and the sidebar HTML needs to check for that value.
|
||||
|
||||
**Before (Only Dashboard worked):**
|
||||
```html
|
||||
<!-- Only dashboard had the x-show condition -->
|
||||
<span x-show="currentPage === 'dashboard'" class="absolute inset-y-0 left-0 w-1 bg-purple-600 rounded-tr-lg rounded-br-lg"></span>
|
||||
```
|
||||
|
||||
### The Fix
|
||||
|
||||
**1. Sidebar HTML** - Add the indicator `<span>` to EVERY menu item:
|
||||
Sections animate smoothly using CSS transitions (no plugins required):
|
||||
|
||||
```html
|
||||
<ul
|
||||
x-show="openSections.platformAdmin"
|
||||
x-transition:enter="transition-all duration-200 ease-out"
|
||||
x-transition:enter-start="opacity-0 -translate-y-2"
|
||||
x-transition:enter-end="opacity-100 translate-y-0"
|
||||
x-transition:leave="transition-all duration-150 ease-in"
|
||||
x-transition:leave-start="opacity-100 translate-y-0"
|
||||
x-transition:leave-end="opacity-0 -translate-y-2"
|
||||
class="mt-1 overflow-hidden"
|
||||
>
|
||||
```
|
||||
|
||||
### Chevron Icon Rotation
|
||||
|
||||
The chevron icon rotates 180 degrees when a section is expanded:
|
||||
|
||||
```html
|
||||
<span
|
||||
x-html="$icon('chevron-down', 'w-4 h-4 transition-transform duration-200')"
|
||||
:class="{ 'rotate-180': openSections.platformAdmin }"
|
||||
></span>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Page-to-Section Mapping
|
||||
|
||||
Pages are mapped to their parent sections for auto-expansion:
|
||||
|
||||
```javascript
|
||||
const pageSectionMap = {
|
||||
// Platform Administration
|
||||
companies: 'platformAdmin',
|
||||
vendors: 'platformAdmin',
|
||||
users: 'platformAdmin',
|
||||
customers: 'platformAdmin',
|
||||
marketplace: 'platformAdmin',
|
||||
// Content Management
|
||||
'platform-homepage': 'contentMgmt',
|
||||
'content-pages': 'contentMgmt',
|
||||
'vendor-theme': 'contentMgmt',
|
||||
// Developer Tools
|
||||
components: 'devTools',
|
||||
icons: 'devTools',
|
||||
testing: 'devTools',
|
||||
'code-quality': 'devTools',
|
||||
// Platform Monitoring
|
||||
imports: 'monitoring',
|
||||
logs: 'monitoring'
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Page Mapping
|
||||
|
||||
| Page | `currentPage` Value | Section | URL |
|
||||
|------|---------------------|---------|-----|
|
||||
| Dashboard | `'dashboard'` | (always visible) | `/admin/dashboard` |
|
||||
| Companies | `'companies'` | Platform Administration | `/admin/companies` |
|
||||
| Vendors | `'vendors'` | Platform Administration | `/admin/vendors` |
|
||||
| Users | `'users'` | Platform Administration | `/admin/users` |
|
||||
| Customers | `'customers'` | Platform Administration | `/admin/customers` |
|
||||
| Marketplace | `'marketplace'` | Platform Administration | `/admin/marketplace` |
|
||||
| Platform Homepage | `'platform-homepage'` | Content Management | `/admin/platform-homepage` |
|
||||
| Content Pages | `'content-pages'` | Content Management | `/admin/content-pages` |
|
||||
| Vendor Themes | `'vendor-theme'` | Content Management | `/admin/vendor-themes` |
|
||||
| Components | `'components'` | Developer Tools | `/admin/components` |
|
||||
| Icons | `'icons'` | Developer Tools | `/admin/icons` |
|
||||
| Testing Hub | `'testing'` | Developer Tools | `/admin/testing` |
|
||||
| Code Quality | `'code-quality'` | Developer Tools | `/admin/code-quality` |
|
||||
| Import Jobs | `'imports'` | Platform Monitoring | `/admin/imports` |
|
||||
| Application Logs | `'logs'` | Platform Monitoring | `/admin/logs` |
|
||||
| Settings | `'settings'` | (always visible) | `/admin/settings` |
|
||||
|
||||
---
|
||||
|
||||
## Active Page Indicator
|
||||
|
||||
Each menu item shows a purple vertical bar when active:
|
||||
|
||||
```html
|
||||
<!-- Vendors -->
|
||||
<li class="relative px-6 py-3">
|
||||
<!-- ✅ Add this span for the purple bar -->
|
||||
<span x-show="currentPage === 'vendors'" class="absolute inset-y-0 left-0 w-1 bg-purple-600 rounded-tr-lg rounded-br-lg"></span>
|
||||
<a :class="currentPage === 'vendors' ? 'text-gray-800 dark:text-gray-100' : ''"
|
||||
<!-- Purple bar indicator (shows when page is active) -->
|
||||
<span x-show="currentPage === 'vendors'"
|
||||
class="absolute inset-y-0 left-0 w-1 bg-purple-600 rounded-tr-lg rounded-br-lg"
|
||||
aria-hidden="true"></span>
|
||||
|
||||
<!-- Link with active text styling -->
|
||||
<a class="inline-flex items-center w-full text-sm font-semibold transition-colors duration-150 hover:text-gray-800 dark:hover:text-gray-200"
|
||||
:class="currentPage === 'vendors' ? 'text-gray-800 dark:text-gray-100' : ''"
|
||||
href="/admin/vendors">
|
||||
<span x-html="$icon('shopping-bag')"></span>
|
||||
<span class="ml-4">Vendors</span>
|
||||
@@ -133,329 +160,179 @@ Each page's JavaScript component needs to set `currentPage` correctly, and the s
|
||||
</li>
|
||||
```
|
||||
|
||||
**2. JavaScript Files** - Each component must set `currentPage`:
|
||||
### Setting currentPage in Components
|
||||
|
||||
Each page component must set `currentPage` to match the sidebar:
|
||||
|
||||
```javascript
|
||||
// vendors.js
|
||||
function adminVendors() {
|
||||
return {
|
||||
...data(),
|
||||
currentPage: 'vendors', // ✅ Must match sidebar check
|
||||
// ... rest of component
|
||||
};
|
||||
}
|
||||
|
||||
// users.js
|
||||
function adminUsers() {
|
||||
return {
|
||||
...data(),
|
||||
currentPage: 'users', // ✅ Must match sidebar check
|
||||
...data(), // Inherit base (includes openSections)
|
||||
currentPage: 'vendors', // Must match sidebar check
|
||||
// ... rest of component
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Complete Page Mapping
|
||||
|
||||
| Page | JavaScript `currentPage` | Sidebar Check | URL |
|
||||
|------|--------------------------|---------------|-----|
|
||||
| Dashboard | `'dashboard'` | `x-show="currentPage === 'dashboard'"` | `/admin/dashboard` |
|
||||
| Companies | `'companies'` | `x-show="currentPage === 'companies'"` | `/admin/companies` |
|
||||
| Vendors | `'vendors'` | `x-show="currentPage === 'vendors'"` | `/admin/vendors` |
|
||||
| Users | `'users'` | `x-show="currentPage === 'users'"` | `/admin/users` |
|
||||
| Customers | `'customers'` | `x-show="currentPage === 'customers'"` | `/admin/customers` |
|
||||
| Marketplace | `'marketplace'` | `x-show="currentPage === 'marketplace'"` | `/admin/marketplace` |
|
||||
| Imports | `'imports'` | `x-show="currentPage === 'imports'"` | `/admin/imports` |
|
||||
| Components | `'components'` | `x-show="currentPage === 'components'"` | `/admin/components` |
|
||||
| Icons | `'icons'` | `x-show="currentPage === 'icons'"` | `/admin/icons` |
|
||||
| Testing | `'testing'` | `x-show="currentPage === 'testing'"` | `/admin/testing` |
|
||||
| Settings | `'settings'` | `x-show="currentPage === 'settings'"` | `/admin/settings` |
|
||||
|
||||
### Updated Sidebar Structure
|
||||
|
||||
The sidebar is organized into the following sections:
|
||||
|
||||
**Dashboard:**
|
||||
- Dashboard
|
||||
|
||||
**Platform Administration:**
|
||||
- Companies
|
||||
- Vendors
|
||||
- Users
|
||||
- Customers
|
||||
- Marketplace
|
||||
|
||||
**Content Management:**
|
||||
- Platform Homepage
|
||||
- Content Pages
|
||||
- Vendor Themes
|
||||
|
||||
**Developer Tools:**
|
||||
- Components
|
||||
- Icons
|
||||
- Testing Hub
|
||||
- Code Quality
|
||||
|
||||
**Platform Monitoring:**
|
||||
- Import Jobs
|
||||
- Application Logs
|
||||
|
||||
**Settings:**
|
||||
- Settings
|
||||
|
||||
Each section is properly separated with dividers and all menu items have active indicators.
|
||||
|
||||
---
|
||||
|
||||
## ✨ New Features
|
||||
## Jinja2 Macros
|
||||
|
||||
### Testing Hub
|
||||
- **2 Test Suites**: Auth Flow and Data Migration
|
||||
- **Stats Cards**: Quick metrics overview
|
||||
- **Interactive Cards**: Click to run tests
|
||||
- **Best Practices**: Testing guidelines
|
||||
- **Resource Links**: To Components and Icons pages
|
||||
The sidebar uses Jinja2 macros for DRY code:
|
||||
|
||||
### Components Library
|
||||
- **Sticky Section Navigation**: Jump to Forms, Buttons, Cards, etc.
|
||||
- **Hash-based URLs**: Bookmarkable sections (#forms, #buttons)
|
||||
- **Copy to Clipboard**: Click to copy component code
|
||||
- **Live Examples**: All components with real Alpine.js
|
||||
- **Dark Mode**: All examples support dark mode
|
||||
### section_header
|
||||
|
||||
### Icons Browser
|
||||
- **Search Functionality**: Filter icons by name
|
||||
- **Category Navigation**: Browse by category
|
||||
- **Live Preview**: See icons in multiple sizes
|
||||
- **Copy Icon Name**: Quick copy to clipboard
|
||||
- **Copy Usage Code**: Copy Alpine.js usage code
|
||||
- **Selected Icon Details**: Full preview and size examples
|
||||
- **Auto-categorization**: Icons organized automatically
|
||||
Creates a collapsible section header with chevron:
|
||||
|
||||
---
|
||||
|
||||
## 🎯 How Each Feature Works
|
||||
|
||||
### Components Library Navigation
|
||||
|
||||
1. **Click a section** in the left sidebar
|
||||
2. **Page scrolls** to that section smoothly
|
||||
3. **URL updates** with hash (#forms)
|
||||
4. **Active section** is highlighted in purple
|
||||
5. **Bookmarkable**: Share URL with #section
|
||||
|
||||
```javascript
|
||||
// How it works
|
||||
goToSection(sectionId) {
|
||||
this.activeSection = sectionId;
|
||||
window.location.hash = sectionId;
|
||||
// Smooth scroll
|
||||
document.getElementById(sectionId).scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
```jinja2
|
||||
{% macro section_header(title, section_key) %}
|
||||
<button
|
||||
@click="toggleSection('{{ section_key }}')"
|
||||
class="flex items-center justify-between w-full px-6 py-2 ..."
|
||||
>
|
||||
<span>{{ title }}</span>
|
||||
<span x-html="$icon('chevron-down', '...')"
|
||||
:class="{ 'rotate-180': openSections.{{ section_key }} }"></span>
|
||||
</button>
|
||||
{% endmacro %}
|
||||
```
|
||||
|
||||
### Icons Browser Search
|
||||
### section_content
|
||||
|
||||
1. **Type in search box** - filters as you type
|
||||
2. **Click category pill** - filters by category
|
||||
3. **Click any icon** - shows details panel
|
||||
4. **Hover icon** - shows copy buttons
|
||||
5. **Click copy** - copies to clipboard
|
||||
Wraps section items with collapse animation:
|
||||
|
||||
```javascript
|
||||
// How it works
|
||||
filterIcons() {
|
||||
let icons = this.allIcons;
|
||||
|
||||
// Filter by category
|
||||
if (this.activeCategory !== 'all') {
|
||||
icons = icons.filter(icon => icon.category === this.activeCategory);
|
||||
}
|
||||
|
||||
// Filter by search
|
||||
if (this.searchQuery.trim()) {
|
||||
const query = this.searchQuery.toLowerCase();
|
||||
icons = icons.filter(icon => icon.name.toLowerCase().includes(query));
|
||||
}
|
||||
|
||||
this.filteredIcons = icons;
|
||||
}
|
||||
```jinja2
|
||||
{% macro section_content(section_key) %}
|
||||
<ul x-show="openSections.{{ section_key }}" x-transition:...>
|
||||
{{ caller() }}
|
||||
</ul>
|
||||
{% endmacro %}
|
||||
```
|
||||
|
||||
### Testing Hub Navigation
|
||||
### menu_item
|
||||
|
||||
1. **View stats** at the top
|
||||
2. **Read test suite cards** with features
|
||||
3. **Click "Run Tests"** to go to test page
|
||||
4. **Read best practices** before testing
|
||||
Creates a menu item with active indicator:
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing Checklist
|
||||
|
||||
After installation, verify:
|
||||
|
||||
### General
|
||||
- [ ] Server starts without errors
|
||||
- [ ] All routes load successfully
|
||||
- [ ] Icons display correctly everywhere
|
||||
- [ ] Dark mode works on all pages
|
||||
|
||||
### Sidebar
|
||||
- [ ] Dashboard shows purple bar when active
|
||||
- [ ] Vendors shows purple bar when active
|
||||
- [ ] Users shows purple bar when active
|
||||
- [ ] Components shows purple bar when active
|
||||
- [ ] Icons shows purple bar when active
|
||||
- [ ] Testing shows purple bar when active
|
||||
- [ ] Text is bold/highlighted on active page
|
||||
|
||||
### Testing Hub
|
||||
- [ ] Page loads at `/admin/testing`
|
||||
- [ ] Stats cards display correctly
|
||||
- [ ] Test suite cards are clickable
|
||||
- [ ] Icons render properly
|
||||
- [ ] Links to other pages work
|
||||
|
||||
### Components Library
|
||||
- [ ] Page loads at `/admin/components`
|
||||
- [ ] Section navigation works
|
||||
- [ ] Clicking section scrolls to it
|
||||
- [ ] URL hash updates (#forms, etc.)
|
||||
- [ ] Copy buttons work
|
||||
- [ ] All form examples render
|
||||
- [ ] Toast examples work
|
||||
|
||||
### Icons Browser
|
||||
- [ ] Page loads at `/admin/icons`
|
||||
- [ ] Shows correct icon count
|
||||
- [ ] Search filters icons
|
||||
- [ ] Category pills filter icons
|
||||
- [ ] Clicking icon shows details
|
||||
- [ ] Copy name button works
|
||||
- [ ] Copy usage button works
|
||||
- [ ] Preview shows multiple sizes
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Customization
|
||||
|
||||
### Adding More Test Suites
|
||||
|
||||
Edit `testing-hub.js`:
|
||||
|
||||
```javascript
|
||||
testSuites: [
|
||||
// ... existing suites
|
||||
{
|
||||
id: 'new-suite',
|
||||
name: 'New Test Suite',
|
||||
description: 'Description here',
|
||||
url: '/admin/test/new-suite',
|
||||
icon: 'icon-name',
|
||||
color: 'blue', // blue, orange, green, purple
|
||||
testCount: 5,
|
||||
features: [
|
||||
'Feature 1',
|
||||
'Feature 2'
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Adding More Component Sections
|
||||
|
||||
Edit `components.js`:
|
||||
|
||||
```javascript
|
||||
sections: [
|
||||
// ... existing sections
|
||||
{ id: 'new-section', name: 'New Section', icon: 'icon-name' }
|
||||
]
|
||||
```
|
||||
|
||||
Then add the section HTML in `components.html`:
|
||||
|
||||
```html
|
||||
<section id="new-section">
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6">
|
||||
<h2>New Section</h2>
|
||||
<!-- Your components here -->
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
### Adding More Icon Categories
|
||||
|
||||
Edit `icons-page.js`:
|
||||
|
||||
```javascript
|
||||
categories: [
|
||||
// ... existing categories
|
||||
{ id: 'new-category', name: 'New Category', icon: 'icon-name' }
|
||||
]
|
||||
```
|
||||
|
||||
And update the `categorizeIcon()` function:
|
||||
|
||||
```javascript
|
||||
categoryMap: {
|
||||
// ... existing mappings
|
||||
'new-category': ['keyword1', 'keyword2']
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 Quick Reference
|
||||
|
||||
### Alpine.js Component Pattern
|
||||
|
||||
```javascript
|
||||
function yourPageComponent() {
|
||||
return {
|
||||
...data(), // ✅ Inherit base
|
||||
currentPage: 'name', // ✅ Set page ID
|
||||
|
||||
async init() {
|
||||
if (window._yourPageInitialized) return;
|
||||
window._yourPageInitialized = true;
|
||||
// Your init code
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Sidebar Menu Item Pattern
|
||||
|
||||
```html
|
||||
```jinja2
|
||||
{% macro menu_item(page_id, url, icon, label) %}
|
||||
<li class="relative px-6 py-3">
|
||||
<!-- Active indicator -->
|
||||
<span x-show="currentPage === 'page-name'"
|
||||
class="absolute inset-y-0 left-0 w-1 bg-purple-600 rounded-tr-lg rounded-br-lg">
|
||||
</span>
|
||||
|
||||
<!-- Link -->
|
||||
<a :class="currentPage === 'page-name' ? 'text-gray-800 dark:text-gray-100' : ''"
|
||||
href="/admin/page-name">
|
||||
<span x-html="$icon('icon-name')"></span>
|
||||
<span class="ml-4">Page Name</span>
|
||||
<span x-show="currentPage === '{{ page_id }}'" class="..."></span>
|
||||
<a href="{{ url }}">
|
||||
<span x-html="$icon('{{ icon }}')"></span>
|
||||
<span class="ml-4">{{ label }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endmacro %}
|
||||
```
|
||||
|
||||
### Usage Example
|
||||
|
||||
```jinja2
|
||||
{{ section_header('Platform Administration', 'platformAdmin') }}
|
||||
{% call section_content('platformAdmin') %}
|
||||
{{ menu_item('companies', '/admin/companies', 'office-building', 'Companies') }}
|
||||
{{ menu_item('vendors', '/admin/vendors', 'shopping-bag', 'Vendors') }}
|
||||
{% endcall %}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Summary
|
||||
## Adding a New Page
|
||||
|
||||
**Architecture:** ✅ All files follow your Alpine.js patterns perfectly
|
||||
**Sidebar:** ✅ Fixed - all menu items now show active indicator
|
||||
**Testing Hub:** ✅ Complete with test suites and navigation
|
||||
**Components:** ✅ Complete with section navigation and copy feature
|
||||
**Icons:** ✅ Complete with search, categories, and copy features
|
||||
### Step 1: Add Route
|
||||
|
||||
**Total Files:** 7 (3 JS + 3 HTML + 1 Sidebar)
|
||||
**Lines of Code:** ~2000+
|
||||
**Features Added:** 20+
|
||||
Add the route in `app/routes/admin_pages.py`:
|
||||
|
||||
Everything is ready to install! 🚀
|
||||
```python
|
||||
@router.get("/new-page", response_class=HTMLResponse, include_in_schema=False)
|
||||
async def admin_new_page(
|
||||
request: Request,
|
||||
current_user: User = Depends(get_current_admin_from_cookie_or_header),
|
||||
):
|
||||
return templates.TemplateResponse(
|
||||
"admin/new-page.html",
|
||||
{"request": request, "user": current_user},
|
||||
)
|
||||
```
|
||||
|
||||
### Step 2: Create Template
|
||||
|
||||
Create `app/templates/admin/new-page.html`:
|
||||
|
||||
```jinja2
|
||||
{% extends "admin/base.html" %}
|
||||
{% block title %}New Page{% endblock %}
|
||||
{% block alpine_data %}adminNewPage(){% endblock %}
|
||||
{% block content %}
|
||||
<!-- Your content -->
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
### Step 3: Create JavaScript Component
|
||||
|
||||
Create `static/admin/js/new-page.js`:
|
||||
|
||||
```javascript
|
||||
function adminNewPage() {
|
||||
return {
|
||||
...data(),
|
||||
currentPage: 'new-page', // Must match sidebar
|
||||
// ...
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Add to Sidebar
|
||||
|
||||
Edit `app/templates/admin/partials/sidebar.html`:
|
||||
|
||||
```jinja2
|
||||
{# Add to appropriate section #}
|
||||
{{ menu_item('new-page', '/admin/new-page', 'icon-name', 'New Page') }}
|
||||
```
|
||||
|
||||
### Step 5: Update Page-Section Map (if in collapsible section)
|
||||
|
||||
Edit `static/admin/js/init-alpine.js`:
|
||||
|
||||
```javascript
|
||||
const pageSectionMap = {
|
||||
// ... existing mappings
|
||||
'new-page': 'platformAdmin', // Add mapping
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mobile Sidebar
|
||||
|
||||
The sidebar has a mobile version that slides in from the left:
|
||||
|
||||
- **Toggle:** Click hamburger menu in header
|
||||
- **Close:** Click outside, press Escape, or navigate
|
||||
- **State:** Controlled by `isSideMenuOpen`
|
||||
|
||||
```javascript
|
||||
// In base data()
|
||||
isSideMenuOpen: false,
|
||||
toggleSideMenu() {
|
||||
this.isSideMenuOpen = !this.isSideMenuOpen
|
||||
},
|
||||
closeSideMenu() {
|
||||
this.isSideMenuOpen = false
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [ ] Sections expand/collapse on header click
|
||||
- [ ] Chevron rotates when section opens/closes
|
||||
- [ ] Section state persists after page reload
|
||||
- [ ] Section state persists across different pages
|
||||
- [ ] Active page shows purple bar indicator
|
||||
- [ ] Active page text is highlighted
|
||||
- [ ] Mobile sidebar opens/closes correctly
|
||||
- [ ] Collapsible sections work on mobile
|
||||
- [ ] All navigation links work correctly
|
||||
|
||||
Reference in New Issue
Block a user