feat: Add mobile responsive theme editor and documentation
- ThemesPage: Custom dropdown with theme cards for mobile - ThemesPage: Collapsible variables section - ThemePreview: Responsive grid and compact layout - VariableEditor: Separate radius preview with border-radius - ColorPicker: Mobile-friendly dropdown positioning - README: Complete theme system documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
224
README.md
224
README.md
@@ -367,6 +367,230 @@ frontend/src/services/dynamicComponents.ts (~300 lines)
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
# Theme System
|
||||
|
||||
Agent UI includes a powerful theming engine with visual editor, presets, and design tokens for consistent styling across dynamic components.
|
||||
|
||||
## Overview
|
||||
|
||||
The theme system provides:
|
||||
|
||||
- **Visual Editor**: Edit CSS variables with live preview
|
||||
- **Presets**: System themes (Dark/Light) + custom user themes
|
||||
- **Persistence**: Themes saved to SQLite database
|
||||
- **Export/Import**: Share themes as JSON files
|
||||
- **Design Tokens**: Structured guide for LLM agents to follow
|
||||
|
||||
## Accessing the Theme Editor
|
||||
|
||||
Navigate to `/themes` in the UI or click the palette icon in the sidebar.
|
||||
|
||||
## Theme Structure
|
||||
|
||||
Themes are organized by categories:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"colors": {
|
||||
"bg-primary": "#0f0f14",
|
||||
"bg-secondary": "#16161d",
|
||||
"bg-hover": "#1e1e28",
|
||||
"bg-tertiary": "#252530",
|
||||
"border-color": "#2a2a3a"
|
||||
},
|
||||
"text": {
|
||||
"text-primary": "#e4e4e7",
|
||||
"text-secondary": "#a1a1aa",
|
||||
"text-muted": "#52525b"
|
||||
},
|
||||
"accent": {
|
||||
"accent": "#6366f1",
|
||||
"accent-hover": "#818cf8",
|
||||
"accent-muted": "rgba(99, 102, 241, 0.2)",
|
||||
"accent-text": "#ffffff"
|
||||
},
|
||||
"semantic": {
|
||||
"success": "#22c55e",
|
||||
"success-bg": "rgba(34, 197, 94, 0.15)",
|
||||
"warning": "#eab308",
|
||||
"warning-bg": "rgba(234, 179, 8, 0.15)",
|
||||
"error": "#ef4444",
|
||||
"error-bg": "rgba(239, 68, 68, 0.15)",
|
||||
"info": "#3b82f6",
|
||||
"info-bg": "rgba(59, 130, 246, 0.15)"
|
||||
},
|
||||
"spacing": {
|
||||
"radius-sm": "4px",
|
||||
"radius-md": "8px",
|
||||
"radius-lg": "12px",
|
||||
"radius-full": "9999px"
|
||||
},
|
||||
"typography": {
|
||||
"font-sans": "Inter, system-ui, sans-serif",
|
||||
"font-mono": "JetBrains Mono, monospace"
|
||||
},
|
||||
"effects": {
|
||||
"shadow-sm": "0 1px 2px rgba(0,0,0,0.3)",
|
||||
"shadow-md": "0 4px 12px rgba(0,0,0,0.4)",
|
||||
"transition-fast": "0.15s ease"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## MCP Tools
|
||||
|
||||
### `get_design_tokens`
|
||||
|
||||
Returns design tokens for the active theme. Use this to create components with consistent styling.
|
||||
|
||||
```javascript
|
||||
{
|
||||
category: "all" | "colors" | "text" | "accent" | "semantic" | "spacing" | "typography" | "effects"
|
||||
}
|
||||
```
|
||||
|
||||
**Response example:**
|
||||
|
||||
```
|
||||
Design Tokens del tema "Dark":
|
||||
|
||||
[COLORS]
|
||||
--bg-primary: #0f0f14
|
||||
--bg-secondary: #16161d
|
||||
...
|
||||
|
||||
GUÍA DE USO:
|
||||
- Usa var(--nombre-variable) en CSS
|
||||
- Los componentes dinámicos tienen acceso a $theme.getVariable('nombre')
|
||||
- Colores semánticos: success, warning, error, info (con -bg para fondos)
|
||||
- Radius: radius-sm (4px), radius-md (8px), radius-lg (12px), radius-full (9999px)
|
||||
```
|
||||
|
||||
## Theme API in Dynamic Components
|
||||
|
||||
Components have access to `$theme` helper:
|
||||
|
||||
```javascript
|
||||
// Get CSS variable value
|
||||
$theme.getVariable('accent') // "#6366f1"
|
||||
|
||||
// Set variable temporarily (runtime only)
|
||||
$theme.setVariable('accent', '#ff0000')
|
||||
|
||||
// Get all design tokens
|
||||
$theme.getTokens()
|
||||
|
||||
// Get active theme object
|
||||
$theme.getActiveTheme()
|
||||
|
||||
// Get current variables
|
||||
$theme.getVariables()
|
||||
```
|
||||
|
||||
### Example: Theme-Aware Component
|
||||
|
||||
```javascript
|
||||
{
|
||||
id: "themed-card",
|
||||
name: "ThemedCard",
|
||||
template: `
|
||||
<div class="card">
|
||||
<h3>{{ title }}</h3>
|
||||
<p>Current accent: {{ accentColor }}</p>
|
||||
<button @click="randomizeAccent">Randomize Accent</button>
|
||||
</div>
|
||||
`,
|
||||
setup: `
|
||||
const accentColor = ref($theme.getVariable('accent'));
|
||||
|
||||
const randomizeAccent = () => {
|
||||
const hue = Math.floor(Math.random() * 360);
|
||||
const newColor = \`hsl(\${hue}, 70%, 60%)\`;
|
||||
$theme.setVariable('accent', newColor);
|
||||
accentColor.value = newColor;
|
||||
};
|
||||
|
||||
return { title: props.title, accentColor, randomizeAccent };
|
||||
`,
|
||||
style: `
|
||||
.card {
|
||||
padding: var(--radius-lg);
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
.card h3 { color: var(--text-primary); }
|
||||
.card p { color: var(--text-secondary); }
|
||||
.card button {
|
||||
background: var(--accent);
|
||||
color: var(--accent-text);
|
||||
border: none;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
}
|
||||
.card button:hover { background: var(--accent-hover); }
|
||||
`,
|
||||
props: ["title"],
|
||||
imports: ["ref"],
|
||||
componentProps: { title: "Themed Card" }
|
||||
}
|
||||
```
|
||||
|
||||
## API Endpoints (Themes)
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/api/themes` | GET | List all themes |
|
||||
| `/api/themes` | POST | Create/update theme |
|
||||
| `/api/themes/active` | GET | Get active (default) theme |
|
||||
| `/api/themes/:id` | GET | Get theme by ID |
|
||||
| `/api/themes/:id` | DELETE | Delete theme |
|
||||
| `/api/themes/:id/default` | POST | Set as default theme |
|
||||
| `/api/themes/export/:id` | GET | Export theme as JSON |
|
||||
| `/api/design-tokens` | GET | Get design tokens guide |
|
||||
|
||||
## Theme Editor Features
|
||||
|
||||
### Desktop View
|
||||
|
||||
- **Sidebar**: List of system and custom themes
|
||||
- **Editor**: Category tabs (Colors, Text, Accent, etc.)
|
||||
- **Variables Grid**: Color pickers and input fields
|
||||
- **Live Preview**: Buttons, cards, badges, inputs
|
||||
|
||||
### Mobile View
|
||||
|
||||
- **Compact Header**: Theme dropdown + action buttons
|
||||
- **Collapsible Variables**: Toggle to show/hide editors
|
||||
- **Responsive Preview**: Adapts to screen size
|
||||
|
||||
### Actions
|
||||
|
||||
- **Save**: Saves current changes (creates copy if editing system theme)
|
||||
- **Reset**: Reverts unsaved changes
|
||||
- **Export**: Downloads theme as JSON file
|
||||
- **Clone**: Creates a copy of any theme
|
||||
- **Set Default**: Makes theme load on startup
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
frontend/src/
|
||||
├── stores/theme.ts # Pinia store
|
||||
├── services/themeService.ts # API client + utilities
|
||||
├── pages/ThemesPage.vue # Main editor page
|
||||
└── components/themes/
|
||||
├── ColorPicker.vue # HSL color picker
|
||||
├── VariableEditor.vue # Variable input (color/size/text)
|
||||
├── ThemePreview.vue # Live preview component
|
||||
└── ThemeListItem.vue # Theme list item with actions
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- **Frontend**: Vue 3, Vite, Pinia, TypeScript
|
||||
|
||||
Reference in New Issue
Block a user