Skip to content

Commit bac0a4d

Browse files
authored
Merge pull request #274 from objectstack-ai/copilot/implement-app-schema-ui
2 parents f65ada1 + 705a623 commit bac0a4d

23 files changed

+5905
-5
lines changed

content/docs/blocks/block-schema.mdx

Lines changed: 459 additions & 0 deletions
Large diffs are not rendered by default.

content/docs/core/app-schema.mdx

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
---
2+
title: "Application Schema (AppSchema)"
3+
description: "Configure your entire application with navigation, branding, and global settings"
4+
---
5+
6+
# Application Schema
7+
8+
The `AppSchema` defines the top-level configuration for your entire ObjectUI application, including navigation menus, branding, layout strategies, and global actions.
9+
10+
## Overview
11+
12+
AppSchema provides a declarative way to configure:
13+
- **Navigation menus** - Hierarchical menu structures with icons and badges
14+
- **Branding** - Logo, title, favicon
15+
- **Layout strategies** - Sidebar, header, or empty layout
16+
- **Global actions** - User menu, global toolbar buttons
17+
18+
## Basic Usage
19+
20+
```typescript
21+
import type { AppSchema } from '@object-ui/types';
22+
23+
const app: AppSchema = {
24+
type: 'app',
25+
name: 'my-crm',
26+
title: 'My CRM Application',
27+
logo: '/logo.svg',
28+
favicon: '/favicon.ico',
29+
layout: 'sidebar',
30+
31+
menu: [
32+
{
33+
type: 'item',
34+
label: 'Dashboard',
35+
icon: 'LayoutDashboard',
36+
path: '/dashboard'
37+
}
38+
],
39+
40+
actions: [
41+
{
42+
type: 'user',
43+
label: 'John Doe',
44+
avatar: '/avatar.jpg'
45+
}
46+
]
47+
};
48+
```
49+
50+
## Properties
51+
52+
### Basic Configuration
53+
54+
| Property | Type | Description |
55+
|----------|------|-------------|
56+
| `type` | `'app'` | Component type identifier (required) |
57+
| `name` | `string` | Application system identifier |
58+
| `title` | `string` | Display title shown in browser |
59+
| `description` | `string` | Application description |
60+
| `logo` | `string` | Logo URL or icon name |
61+
| `favicon` | `string` | Favicon URL |
62+
63+
### Layout Configuration
64+
65+
| Property | Type | Default | Description |
66+
|----------|------|---------|-------------|
67+
| `layout` | `'sidebar' \| 'header' \| 'empty'` | `'sidebar'` | Global layout strategy |
68+
69+
**Layout Options:**
70+
- **`sidebar`** - Standard admin layout with left sidebar navigation
71+
- **`header`** - Top navigation bar only
72+
- **`empty`** - No layout, pages handle their own structure
73+
74+
### Navigation Menu
75+
76+
The `menu` property accepts an array of `MenuItem` objects:
77+
78+
```typescript
79+
interface MenuItem {
80+
type?: 'item' | 'group' | 'separator';
81+
label?: string;
82+
icon?: string; // Lucide icon name
83+
path?: string; // Route path
84+
href?: string; // External link
85+
children?: MenuItem[]; // Submenu items
86+
badge?: string | number;
87+
hidden?: boolean | string; // Visibility condition
88+
}
89+
```
90+
91+
#### Menu Types
92+
93+
**Item** - Single navigation link
94+
```json
95+
{
96+
"type": "item",
97+
"label": "Dashboard",
98+
"icon": "LayoutDashboard",
99+
"path": "/dashboard",
100+
"badge": "New"
101+
}
102+
```
103+
104+
**Group** - Collapsible menu group
105+
```json
106+
{
107+
"type": "group",
108+
"label": "Sales",
109+
"icon": "DollarSign",
110+
"children": [
111+
{ "type": "item", "label": "Leads", "path": "/leads" },
112+
{ "type": "item", "label": "Deals", "path": "/deals" }
113+
]
114+
}
115+
```
116+
117+
**Separator** - Visual separator
118+
```json
119+
{
120+
"type": "separator"
121+
}
122+
```
123+
124+
### Global Actions
125+
126+
The `actions` property defines global toolbar buttons:
127+
128+
```typescript
129+
interface AppAction {
130+
type: 'button' | 'dropdown' | 'user';
131+
label?: string;
132+
icon?: string;
133+
onClick?: string;
134+
avatar?: string; // For type='user'
135+
description?: string; // For type='user'
136+
items?: MenuItem[]; // For type='dropdown' or 'user'
137+
shortcut?: string; // Keyboard shortcut
138+
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';
139+
size?: 'default' | 'sm' | 'lg' | 'icon';
140+
}
141+
```
142+
143+
## Complete Example
144+
145+
```typescript
146+
const crm: AppSchema = {
147+
type: 'app',
148+
name: 'acme-crm',
149+
title: 'Acme CRM',
150+
description: 'Customer Relationship Management System',
151+
logo: '/acme-logo.svg',
152+
favicon: '/favicon.ico',
153+
layout: 'sidebar',
154+
155+
menu: [
156+
{
157+
type: 'item',
158+
label: 'Dashboard',
159+
icon: 'LayoutDashboard',
160+
path: '/dashboard'
161+
},
162+
{
163+
type: 'separator'
164+
},
165+
{
166+
type: 'group',
167+
label: 'Sales',
168+
icon: 'DollarSign',
169+
children: [
170+
{
171+
type: 'item',
172+
label: 'Leads',
173+
icon: 'Users',
174+
path: '/leads',
175+
badge: 12
176+
},
177+
{
178+
type: 'item',
179+
label: 'Opportunities',
180+
icon: 'Target',
181+
path: '/opportunities'
182+
},
183+
{
184+
type: 'item',
185+
label: 'Quotes',
186+
icon: 'FileText',
187+
path: '/quotes'
188+
}
189+
]
190+
},
191+
{
192+
type: 'group',
193+
label: 'Marketing',
194+
icon: 'Megaphone',
195+
children: [
196+
{
197+
type: 'item',
198+
label: 'Campaigns',
199+
path: '/campaigns'
200+
},
201+
{
202+
type: 'item',
203+
label: 'Email Templates',
204+
path: '/templates'
205+
}
206+
]
207+
},
208+
{
209+
type: 'separator'
210+
},
211+
{
212+
type: 'item',
213+
label: 'Settings',
214+
icon: 'Settings',
215+
path: '/settings',
216+
hidden: '${user.role !== "admin"}'
217+
}
218+
],
219+
220+
actions: [
221+
{
222+
type: 'button',
223+
label: 'Quick Actions',
224+
icon: 'Zap',
225+
variant: 'outline',
226+
onClick: 'openQuickActions'
227+
},
228+
{
229+
type: 'user',
230+
label: 'John Doe',
231+
avatar: '/avatars/john.jpg',
232+
description: 'john@acme.com',
233+
items: [
234+
{
235+
type: 'item',
236+
label: 'Profile',
237+
icon: 'User',
238+
path: '/profile'
239+
},
240+
{
241+
type: 'item',
242+
label: 'Settings',
243+
icon: 'Settings',
244+
path: '/settings'
245+
},
246+
{
247+
type: 'separator'
248+
},
249+
{
250+
type: 'item',
251+
label: 'Logout',
252+
icon: 'LogOut',
253+
path: '/logout'
254+
}
255+
]
256+
}
257+
]
258+
};
259+
```
260+
261+
## Runtime Validation
262+
263+
Use Zod validation to ensure your app configuration is correct:
264+
265+
```typescript
266+
import { AppSchema } from '@object-ui/types/zod';
267+
268+
const result = AppSchema.safeParse(myAppConfig);
269+
270+
if (result.success) {
271+
console.log('Valid app configuration');
272+
} else {
273+
console.error('Validation errors:', result.error);
274+
}
275+
```
276+
277+
## Conditional Navigation
278+
279+
Use expression syntax to show/hide menu items based on user permissions:
280+
281+
```json
282+
{
283+
"type": "item",
284+
"label": "Admin Panel",
285+
"path": "/admin",
286+
"hidden": "${user.role !== 'admin'}"
287+
}
288+
```
289+
290+
## Best Practices
291+
292+
1. **Use semantic icons** - Choose Lucide icons that clearly represent the section
293+
2. **Group related items** - Use menu groups to organize navigation
294+
3. **Limit top-level items** - Keep the main menu concise (5-7 items)
295+
4. **Add badges for notifications** - Show counts or status indicators
296+
5. **Hide admin features** - Use conditional visibility for role-based access
297+
6. **Provide keyboard shortcuts** - Add shortcuts for frequently used actions
298+
299+
## Related
300+
301+
- [Layout Schema](/docs/guide/layout) - Page layout configuration
302+
- [Navigation Components](/docs/components/basic/navigation-menu) - Navigation UI components
303+
- [Theme Schema](/docs/core/theme-schema) - Application theming

0 commit comments

Comments
 (0)