609 lines
19 KiB
TypeScript
609 lines
19 KiB
TypeScript
import { html, css, DeesElement, customElement, state } from '@design.estate/dees-element';
|
|
import type { DeesAppuiBase } from './dees-appui-base.js';
|
|
import type { IAppConfig, IViewActivationContext } from '../../interfaces/appconfig.js';
|
|
import '@design.estate/dees-wcctools/demotools';
|
|
|
|
// Demo view component with lifecycle hooks
|
|
@customElement('demo-dashboard-view')
|
|
class DemoDashboardView extends DeesElement {
|
|
@state()
|
|
accessor activated: boolean = false;
|
|
|
|
onActivate(context: IViewActivationContext) {
|
|
this.activated = true;
|
|
console.log('Dashboard activated with context:', context);
|
|
|
|
// Set view-specific secondary menu
|
|
context.appui.setSecondaryMenu({
|
|
heading: 'Dashboard',
|
|
groups: [
|
|
{
|
|
name: 'Quick Access',
|
|
iconName: 'lucide:zap',
|
|
items: [
|
|
{ key: 'overview', iconName: 'layoutDashboard', action: () => console.log('Overview') },
|
|
{ key: 'recent', iconName: 'clock', badge: 5, action: () => console.log('Recent') },
|
|
]
|
|
},
|
|
{
|
|
name: 'Analytics',
|
|
iconName: 'lucide:barChart3',
|
|
items: [
|
|
{ key: 'metrics', iconName: 'activity', action: () => console.log('Metrics') },
|
|
{ key: 'reports', iconName: 'fileText', badge: 'new', badgeVariant: 'success', action: () => console.log('Reports') },
|
|
]
|
|
}
|
|
]
|
|
});
|
|
|
|
// Set content tabs for dashboard
|
|
context.appui.setContentTabs([
|
|
{ key: 'Overview', iconName: 'lucide:layoutDashboard', action: () => console.log('Overview tab') },
|
|
{ key: 'Analytics', iconName: 'lucide:barChart', action: () => console.log('Analytics tab') },
|
|
{ key: 'Reports', iconName: 'lucide:fileText', action: () => console.log('Reports tab') },
|
|
]);
|
|
}
|
|
|
|
onDeactivate() {
|
|
this.activated = false;
|
|
console.log('Dashboard deactivated');
|
|
}
|
|
|
|
render() {
|
|
return html`
|
|
<style>
|
|
:host {
|
|
display: block;
|
|
padding: 40px;
|
|
color: #a3a3a3;
|
|
font-family: 'Geist Sans', 'Inter', -apple-system, sans-serif;
|
|
}
|
|
h1 { color: #fafafa; font-weight: 600; font-size: 24px; margin-bottom: 8px; }
|
|
p { color: #737373; margin-bottom: 32px; }
|
|
.grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
gap: 16px;
|
|
}
|
|
.card {
|
|
background: rgba(255,255,255,0.03);
|
|
border: 1px solid rgba(255,255,255,0.08);
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
}
|
|
.card h3 { color: #fafafa; font-size: 14px; font-weight: 600; margin-bottom: 8px; }
|
|
.metric { font-size: 32px; font-weight: 700; color: #fafafa; }
|
|
.status { display: inline-block; padding: 2px 8px; border-radius: 9px; font-size: 12px; }
|
|
.status.active { background: #14532d; color: #4ade80; }
|
|
</style>
|
|
<h1>Dashboard</h1>
|
|
<p>Welcome back! Here's an overview of your system.</p>
|
|
<div class="grid">
|
|
<div class="card">
|
|
<h3>Active Users</h3>
|
|
<div class="metric">1,234</div>
|
|
<span class="status active">Online</span>
|
|
</div>
|
|
<div class="card">
|
|
<h3>API Calls</h3>
|
|
<div class="metric">45.2K</div>
|
|
<p style="color: #4ade80; font-size: 12px; margin: 0;">+12% from last hour</p>
|
|
</div>
|
|
<div class="card">
|
|
<h3>System Health</h3>
|
|
<div class="metric">99.9%</div>
|
|
<p style="color: #737373; font-size: 12px; margin: 0;">All systems operational</p>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
// Settings view with route params and canDeactivate guard
|
|
@customElement('demo-settings-view')
|
|
class DemoSettingsView extends DeesElement {
|
|
@state()
|
|
accessor section: string = 'general';
|
|
|
|
@state()
|
|
accessor hasChanges: boolean = false;
|
|
|
|
private appui: DeesAppuiBase;
|
|
|
|
onActivate(context: IViewActivationContext) {
|
|
this.appui = context.appui as any;
|
|
console.log('Settings activated with params:', context.params);
|
|
|
|
if (context.params?.section) {
|
|
this.section = context.params.section;
|
|
}
|
|
|
|
// Set settings-specific secondary menu
|
|
context.appui.setSecondaryMenu({
|
|
heading: 'Settings',
|
|
groups: [
|
|
{
|
|
name: 'Account',
|
|
iconName: 'lucide:user',
|
|
items: [
|
|
{ key: 'general', iconName: 'settings', action: () => this.showSection('general') },
|
|
{ key: 'profile', iconName: 'user', action: () => this.showSection('profile') },
|
|
{ key: 'security', iconName: 'shield', action: () => this.showSection('security') },
|
|
]
|
|
},
|
|
{
|
|
name: 'Preferences',
|
|
iconName: 'lucide:sliders',
|
|
items: [
|
|
{ key: 'notifications', iconName: 'bell', badge: 3, action: () => this.showSection('notifications') },
|
|
{ key: 'appearance', iconName: 'palette', action: () => this.showSection('appearance') },
|
|
]
|
|
}
|
|
]
|
|
});
|
|
|
|
context.appui.setSecondaryMenuSelection(this.section);
|
|
|
|
// Clear content tabs for settings
|
|
context.appui.setContentTabs([]);
|
|
}
|
|
|
|
onDeactivate() {
|
|
console.log('Settings deactivated');
|
|
this.hasChanges = false;
|
|
}
|
|
|
|
canDeactivate(): boolean | string {
|
|
if (this.hasChanges) {
|
|
return 'You have unsaved changes. Leave anyway?';
|
|
}
|
|
return true;
|
|
}
|
|
|
|
showSection(section: string) {
|
|
this.section = section;
|
|
this.appui?.setSecondaryMenuSelection(section);
|
|
}
|
|
|
|
simulateChange() {
|
|
this.hasChanges = true;
|
|
}
|
|
|
|
render() {
|
|
return html`
|
|
<style>
|
|
:host {
|
|
display: block;
|
|
padding: 40px;
|
|
color: #a3a3a3;
|
|
font-family: 'Geist Sans', 'Inter', -apple-system, sans-serif;
|
|
}
|
|
h1 { color: #fafafa; font-weight: 600; font-size: 24px; margin-bottom: 8px; }
|
|
p { color: #737373; margin-bottom: 24px; }
|
|
.section-name {
|
|
background: rgba(255,255,255,0.05);
|
|
border: 1px solid rgba(255,255,255,0.1);
|
|
border-radius: 8px;
|
|
padding: 24px;
|
|
font-size: 18px;
|
|
color: #fafafa;
|
|
margin-bottom: 16px;
|
|
}
|
|
.actions {
|
|
display: flex;
|
|
gap: 12px;
|
|
}
|
|
button {
|
|
background: #3b82f6;
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 16px;
|
|
border-radius: 6px;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
}
|
|
button:hover {
|
|
background: #2563eb;
|
|
}
|
|
.warning {
|
|
color: #fbbf24;
|
|
font-size: 13px;
|
|
margin-top: 16px;
|
|
}
|
|
</style>
|
|
<h1>Settings</h1>
|
|
<p>Manage your account and application preferences.</p>
|
|
<div class="section-name">
|
|
Current section: <strong>${this.section}</strong>
|
|
</div>
|
|
<div class="actions">
|
|
<button @click=${() => this.simulateChange()}>Make Changes</button>
|
|
</div>
|
|
${this.hasChanges ? html`<p class="warning">You have unsaved changes. Navigation will prompt for confirmation.</p>` : ''}
|
|
`;
|
|
}
|
|
}
|
|
|
|
// Projects view
|
|
@customElement('demo-projects-view')
|
|
class DemoProjectsView extends DeesElement {
|
|
onActivate(context: IViewActivationContext) {
|
|
context.appui.setSecondaryMenu({
|
|
heading: 'Projects',
|
|
groups: [
|
|
{
|
|
name: 'My Projects',
|
|
items: [
|
|
{ key: 'active', iconName: 'folder', badge: 3, action: () => console.log('Active') },
|
|
{ key: 'archived', iconName: 'archive', action: () => console.log('Archived') },
|
|
{ key: 'shared', iconName: 'users', badge: 2, badgeVariant: 'warning', action: () => console.log('Shared') },
|
|
]
|
|
}
|
|
]
|
|
});
|
|
|
|
context.appui.setContentTabs([
|
|
{ key: 'Grid', iconName: 'lucide:grid', action: () => console.log('Grid view') },
|
|
{ key: 'List', iconName: 'lucide:list', action: () => console.log('List view') },
|
|
{ key: 'Board', iconName: 'lucide:kanban', action: () => console.log('Board view') },
|
|
]);
|
|
}
|
|
|
|
render() {
|
|
return html`
|
|
<style>
|
|
:host {
|
|
display: block;
|
|
padding: 40px;
|
|
color: #a3a3a3;
|
|
font-family: 'Geist Sans', 'Inter', -apple-system, sans-serif;
|
|
}
|
|
h1 { color: #fafafa; font-weight: 600; font-size: 24px; margin-bottom: 24px; }
|
|
.projects {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: 16px;
|
|
}
|
|
.project {
|
|
background: rgba(255,255,255,0.03);
|
|
border: 1px solid rgba(255,255,255,0.08);
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
cursor: pointer;
|
|
transition: border-color 0.2s;
|
|
}
|
|
.project:hover {
|
|
border-color: rgba(255,255,255,0.2);
|
|
}
|
|
.project h3 { color: #fafafa; margin: 0 0 8px 0; font-size: 16px; }
|
|
.project p { color: #737373; margin: 0; font-size: 13px; }
|
|
.badge {
|
|
display: inline-block;
|
|
background: #14532d;
|
|
color: #4ade80;
|
|
padding: 2px 8px;
|
|
border-radius: 9px;
|
|
font-size: 11px;
|
|
margin-left: 8px;
|
|
}
|
|
</style>
|
|
<h1>Projects</h1>
|
|
<div class="projects">
|
|
<div class="project">
|
|
<h3>Frontend App <span class="badge">Active</span></h3>
|
|
<p>React-based dashboard application</p>
|
|
</div>
|
|
<div class="project">
|
|
<h3>API Server <span class="badge">Active</span></h3>
|
|
<p>Node.js REST API backend</p>
|
|
</div>
|
|
<div class="project">
|
|
<h3>Mobile App <span class="badge">Active</span></h3>
|
|
<p>React Native iOS/Android app</p>
|
|
</div>
|
|
<div class="project">
|
|
<h3>Documentation</h3>
|
|
<p>Technical documentation site</p>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
// Tasks view showing inline template content
|
|
@customElement('demo-tasks-view')
|
|
class DemoTasksView extends DeesElement {
|
|
onActivate(context: IViewActivationContext) {
|
|
context.appui.setSecondaryMenu({
|
|
heading: 'Tasks',
|
|
groups: [
|
|
{
|
|
name: 'Filters',
|
|
items: [
|
|
{ key: 'all', iconName: 'list', badge: 12, action: () => console.log('All') },
|
|
{ key: 'today', iconName: 'calendar', badge: 3, action: () => console.log('Today') },
|
|
{ key: 'upcoming', iconName: 'clock', action: () => console.log('Upcoming') },
|
|
{ key: 'completed', iconName: 'checkCircle', action: () => console.log('Completed') },
|
|
]
|
|
}
|
|
]
|
|
});
|
|
|
|
context.appui.setContentTabs([
|
|
{ key: 'List', iconName: 'lucide:list', action: () => console.log('List') },
|
|
{ key: 'Calendar', iconName: 'lucide:calendar', action: () => console.log('Calendar') },
|
|
]);
|
|
}
|
|
|
|
render() {
|
|
return html`
|
|
<style>
|
|
:host {
|
|
display: block;
|
|
padding: 40px;
|
|
color: #a3a3a3;
|
|
font-family: 'Geist Sans', 'Inter', -apple-system, sans-serif;
|
|
}
|
|
h1 { color: #fafafa; font-weight: 600; font-size: 24px; margin-bottom: 24px; }
|
|
.task-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
}
|
|
.task {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
background: rgba(255,255,255,0.03);
|
|
border: 1px solid rgba(255,255,255,0.08);
|
|
border-radius: 8px;
|
|
padding: 12px 16px;
|
|
}
|
|
.checkbox {
|
|
width: 18px;
|
|
height: 18px;
|
|
border: 2px solid #525252;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
}
|
|
.task-text { color: #fafafa; flex: 1; }
|
|
.due-date { color: #737373; font-size: 12px; }
|
|
.priority {
|
|
padding: 2px 8px;
|
|
border-radius: 4px;
|
|
font-size: 11px;
|
|
}
|
|
.priority.high { background: #450a0a; color: #f87171; }
|
|
.priority.medium { background: #451a03; color: #fbbf24; }
|
|
</style>
|
|
<h1>Tasks</h1>
|
|
<div class="task-list">
|
|
<div class="task">
|
|
<div class="checkbox"></div>
|
|
<span class="task-text">Review pull request #42</span>
|
|
<span class="due-date">Today</span>
|
|
<span class="priority high">High</span>
|
|
</div>
|
|
<div class="task">
|
|
<div class="checkbox"></div>
|
|
<span class="task-text">Update documentation</span>
|
|
<span class="due-date">Tomorrow</span>
|
|
<span class="priority medium">Medium</span>
|
|
</div>
|
|
<div class="task">
|
|
<div class="checkbox"></div>
|
|
<span class="task-text">Write unit tests</span>
|
|
<span class="due-date">Dec 20</span>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
export const demoFunc = () => {
|
|
// App configuration using the new unified API
|
|
const appConfig: IAppConfig = {
|
|
branding: {
|
|
logoIcon: 'lucide:box',
|
|
logoText: 'Acme App'
|
|
},
|
|
|
|
appBar: {
|
|
menuItems: [
|
|
{
|
|
name: 'File',
|
|
action: async () => {},
|
|
submenu: [
|
|
{ name: 'New Project', shortcut: 'Cmd+N', iconName: 'filePlus', action: async () => console.log('New') },
|
|
{ name: 'Open...', shortcut: 'Cmd+O', iconName: 'folderOpen', action: async () => console.log('Open') },
|
|
{ name: 'Recent Projects', action: async () => {}, submenu: [
|
|
{ name: 'my-app', action: async () => console.log('Open my-app') },
|
|
{ name: 'component-lib', action: async () => console.log('Open component-lib') },
|
|
]},
|
|
{ divider: true },
|
|
{ name: 'Save All', shortcut: 'Cmd+S', iconName: 'save', action: async () => console.log('Save') },
|
|
]
|
|
},
|
|
{
|
|
name: 'Edit',
|
|
action: async () => {},
|
|
submenu: [
|
|
{ name: 'Undo', shortcut: 'Cmd+Z', iconName: 'undo', action: async () => console.log('Undo') },
|
|
{ name: 'Redo', shortcut: 'Cmd+Shift+Z', iconName: 'redo', action: async () => console.log('Redo') },
|
|
{ divider: true },
|
|
{ name: 'Cut', shortcut: 'Cmd+X', iconName: 'scissors', action: async () => console.log('Cut') },
|
|
{ name: 'Copy', shortcut: 'Cmd+C', iconName: 'copy', action: async () => console.log('Copy') },
|
|
{ name: 'Paste', shortcut: 'Cmd+V', iconName: 'clipboard', action: async () => console.log('Paste') },
|
|
]
|
|
},
|
|
{
|
|
name: 'View',
|
|
action: async () => {},
|
|
submenu: [
|
|
{ name: 'Toggle Sidebar', shortcut: 'Cmd+B', action: async () => console.log('Toggle sidebar') },
|
|
{ name: 'Toggle Activity Log', shortcut: 'Cmd+Shift+A', action: async () => console.log('Toggle activity') },
|
|
]
|
|
},
|
|
{
|
|
name: 'Help',
|
|
action: async () => {},
|
|
submenu: [
|
|
{ name: 'Documentation', iconName: 'book', action: async () => console.log('Docs') },
|
|
{ name: 'Keyboard Shortcuts', iconName: 'keyboard', shortcut: 'Cmd+/', action: async () => console.log('Shortcuts') },
|
|
{ divider: true },
|
|
{ name: 'About', iconName: 'info', action: async () => console.log('About') },
|
|
]
|
|
}
|
|
],
|
|
breadcrumbs: 'Dashboard',
|
|
showWindowControls: true,
|
|
showSearch: true,
|
|
user: {
|
|
name: 'Jane Smith',
|
|
email: 'jane.smith@example.com',
|
|
status: 'online'
|
|
},
|
|
profileMenuItems: [
|
|
{ name: 'Profile', iconName: 'user', action: async () => console.log('Profile') },
|
|
{ name: 'Account Settings', iconName: 'settings', action: async () => console.log('Settings') },
|
|
{ divider: true },
|
|
{ name: 'Help & Support', iconName: 'helpCircle', action: async () => console.log('Help') },
|
|
{ divider: true },
|
|
{ name: 'Sign Out', iconName: 'logOut', action: async () => console.log('Sign out') }
|
|
]
|
|
},
|
|
|
|
views: [
|
|
{
|
|
id: 'dashboard',
|
|
name: 'Dashboard',
|
|
iconName: 'lucide:home',
|
|
content: 'demo-dashboard-view',
|
|
route: 'dashboard'
|
|
},
|
|
{
|
|
id: 'projects',
|
|
name: 'Projects',
|
|
iconName: 'lucide:folder',
|
|
content: 'demo-projects-view',
|
|
route: 'projects',
|
|
badge: 3
|
|
},
|
|
{
|
|
id: 'tasks',
|
|
name: 'Tasks',
|
|
iconName: 'lucide:checkSquare',
|
|
content: 'demo-tasks-view',
|
|
route: 'tasks',
|
|
badge: 12
|
|
},
|
|
{
|
|
id: 'settings',
|
|
name: 'Settings',
|
|
iconName: 'lucide:settings',
|
|
content: 'demo-settings-view',
|
|
route: 'settings/:section?'
|
|
},
|
|
],
|
|
|
|
mainMenu: {
|
|
sections: [
|
|
{ name: 'Main', views: ['dashboard'] },
|
|
{ name: 'Workspace', views: ['projects', 'tasks'] },
|
|
],
|
|
bottomItems: ['settings']
|
|
},
|
|
|
|
defaultView: 'dashboard',
|
|
|
|
onViewChange: (viewId, view) => {
|
|
console.log(`View changed to: ${viewId} (${view.name})`);
|
|
},
|
|
|
|
onSearch: (query) => {
|
|
console.log('Search query:', query);
|
|
}
|
|
};
|
|
|
|
// Use a container element to properly initialize the demo
|
|
const containerElement = document.createElement('div');
|
|
containerElement.className = 'demo-container';
|
|
containerElement.style.cssText = 'position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden;';
|
|
|
|
const appuiElement = document.createElement('dees-appui-base') as DeesAppuiBase;
|
|
containerElement.appendChild(appuiElement);
|
|
|
|
// Initialize after element is connected
|
|
setTimeout(async () => {
|
|
await appuiElement.updateComplete;
|
|
|
|
// Configure using the unified API
|
|
appuiElement.configure(appConfig);
|
|
|
|
// Add demo activity entries
|
|
setTimeout(() => {
|
|
appuiElement.activityLog.addMany([
|
|
{
|
|
type: 'login',
|
|
user: 'Jane Smith',
|
|
message: 'logged in from Chrome on macOS'
|
|
},
|
|
{
|
|
type: 'create',
|
|
user: 'Jane Smith',
|
|
message: 'created project "Frontend App"'
|
|
},
|
|
{
|
|
type: 'update',
|
|
user: 'John Doe',
|
|
message: 'updated API documentation'
|
|
},
|
|
{
|
|
type: 'view',
|
|
user: 'Jane Smith',
|
|
message: 'viewed dashboard analytics'
|
|
},
|
|
{
|
|
type: 'delete',
|
|
user: 'Admin',
|
|
message: 'removed deprecated endpoint'
|
|
},
|
|
{
|
|
type: 'custom',
|
|
user: 'System',
|
|
message: 'scheduled backup completed',
|
|
iconName: 'lucide:database'
|
|
}
|
|
]);
|
|
}, 500);
|
|
|
|
// Subscribe to view changes
|
|
appuiElement.viewChanged$.subscribe((event) => {
|
|
console.log('View changed event:', event);
|
|
// Update breadcrumbs based on view
|
|
appuiElement.setBreadcrumbs(event.view.name);
|
|
});
|
|
|
|
// Subscribe to lifecycle events
|
|
appuiElement.viewLifecycle$.subscribe((event) => {
|
|
console.log('Lifecycle event:', event.type, event.viewId);
|
|
});
|
|
|
|
// Demo: Dynamically update a badge after 5 seconds
|
|
setTimeout(() => {
|
|
appuiElement.setMainMenuBadge('tasks', 15);
|
|
appuiElement.activityLog.add({
|
|
type: 'update',
|
|
user: 'System',
|
|
message: 'new tasks added'
|
|
});
|
|
}, 5000);
|
|
}, 0);
|
|
|
|
return html`
|
|
<dees-demowrapper>
|
|
${containerElement}
|
|
</dees-demowrapper>
|
|
`;
|
|
};
|