Add comprehensive UI component expansion
- Add new components: enhanced-table, fab-menu, icon-button, snackbar, select, tag-input, bottom-navigation, stepper, command-palette, floating-toolbar, transfer-list - Refactor table-actions and select components - Update component styles and exports - Add corresponding demo components 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,574 @@
|
||||
import { Component, OnInit, OnDestroy, ViewChild, inject } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Router } from '@angular/router';
|
||||
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||
import {
|
||||
faHome,
|
||||
faCog,
|
||||
faUser,
|
||||
faSearch,
|
||||
faFile,
|
||||
faEdit,
|
||||
faEye,
|
||||
faTools,
|
||||
faQuestion,
|
||||
faPlus,
|
||||
faSave,
|
||||
faCopy,
|
||||
faPaste,
|
||||
faUndo,
|
||||
faRedo,
|
||||
faKeyboard,
|
||||
faPalette,
|
||||
faRocket
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { Command, CommandCategory, CommandExecutionContext, CommandPaletteComponent, CommandPaletteService, createShortcuts, GlobalKeyboardDirective } from '../../../../../ui-essentials/src/lib/components/overlays/command-palette';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'ui-command-palette-demo',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
FontAwesomeModule,
|
||||
CommandPaletteComponent,
|
||||
GlobalKeyboardDirective
|
||||
],
|
||||
template: `
|
||||
<div class="demo-container" uiGlobalKeyboard [shortcuts]="globalShortcuts" (shortcutTriggered)="handleGlobalShortcut($event)">
|
||||
<div class="demo-header">
|
||||
<h2 class="demo-title">
|
||||
<fa-icon [icon]="faPalette" class="demo-title-icon"></fa-icon>
|
||||
Command Palette Demo
|
||||
</h2>
|
||||
<p class="demo-description">
|
||||
A powerful command palette for quick navigation and actions. Press <kbd>Ctrl+K</kbd> (or <kbd>⌘K</kbd> on Mac) to open.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Quick Start Section -->
|
||||
<section class="demo-section">
|
||||
<h3 class="demo-section-title">Quick Start</h3>
|
||||
<div class="demo-actions">
|
||||
<button
|
||||
class="demo-button demo-button--primary"
|
||||
(click)="openCommandPalette()"
|
||||
>
|
||||
<fa-icon [icon]="faKeyboard"></fa-icon>
|
||||
Open Command Palette
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="demo-button demo-button--secondary"
|
||||
(click)="registerSampleCommands()"
|
||||
>
|
||||
<fa-icon [icon]="faPlus"></fa-icon>
|
||||
Add Sample Commands
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="demo-button demo-button--outline"
|
||||
(click)="clearCommands()"
|
||||
>
|
||||
Clear Commands
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Configuration Section -->
|
||||
<section class="demo-section">
|
||||
<h3 class="demo-section-title">Configuration</h3>
|
||||
<div class="demo-config-grid">
|
||||
<div class="demo-config-item">
|
||||
<label class="demo-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
[checked]="config.showCategories"
|
||||
(change)="updateConfig('showCategories', $event)"
|
||||
class="demo-checkbox"
|
||||
/>
|
||||
Show Categories
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="demo-config-item">
|
||||
<label class="demo-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
[checked]="config.showShortcuts"
|
||||
(change)="updateConfig('showShortcuts', $event)"
|
||||
class="demo-checkbox"
|
||||
/>
|
||||
Show Shortcuts
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="demo-config-item">
|
||||
<label class="demo-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
[checked]="config.showRecent"
|
||||
(change)="updateConfig('showRecent', $event)"
|
||||
class="demo-checkbox"
|
||||
/>
|
||||
Show Recent Commands
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="demo-config-item">
|
||||
<label class="demo-label">
|
||||
Max Results:
|
||||
<input
|
||||
type="number"
|
||||
[value]="config.maxResults"
|
||||
(input)="updateConfig('maxResults', $event)"
|
||||
class="demo-input"
|
||||
min="1"
|
||||
max="50"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="demo-config-item">
|
||||
<label class="demo-label">
|
||||
Recent Limit:
|
||||
<input
|
||||
type="number"
|
||||
[value]="config.recentLimit"
|
||||
(input)="updateConfig('recentLimit', $event)"
|
||||
class="demo-input"
|
||||
min="1"
|
||||
max="20"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="demo-config-item">
|
||||
<label class="demo-label">
|
||||
Size:
|
||||
<select
|
||||
[value]="paletteSize"
|
||||
(change)="updatePaletteSize($event)"
|
||||
class="demo-select"
|
||||
>
|
||||
<option value="md">Medium</option>
|
||||
<option value="lg">Large</option>
|
||||
<option value="xl">Extra Large</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Features Section -->
|
||||
<section class="demo-section">
|
||||
<h3 class="demo-section-title">Features</h3>
|
||||
<div class="demo-features">
|
||||
<div class="demo-feature">
|
||||
<fa-icon [icon]="faKeyboard" class="demo-feature-icon"></fa-icon>
|
||||
<h4>Keyboard Navigation</h4>
|
||||
<p>Full keyboard support with arrow keys, Enter, and Escape</p>
|
||||
</div>
|
||||
|
||||
<div class="demo-feature">
|
||||
<fa-icon [icon]="faSearch" class="demo-feature-icon"></fa-icon>
|
||||
<h4>Fuzzy Search</h4>
|
||||
<p>Intelligent search with typo tolerance and keyword matching</p>
|
||||
</div>
|
||||
|
||||
<div class="demo-feature">
|
||||
<fa-icon [icon]="faRocket" class="demo-feature-icon"></fa-icon>
|
||||
<h4>Quick Actions</h4>
|
||||
<p>Execute commands instantly with global keyboard shortcuts</p>
|
||||
</div>
|
||||
|
||||
<div class="demo-feature">
|
||||
<fa-icon [icon]="faCog" class="demo-feature-icon"></fa-icon>
|
||||
<h4>Categorization</h4>
|
||||
<p>Organize commands by category for better discoverability</p>
|
||||
</div>
|
||||
|
||||
<div class="demo-feature">
|
||||
<fa-icon [icon]="faCopy" class="demo-feature-icon"></fa-icon>
|
||||
<h4>Recent Commands</h4>
|
||||
<p>Track and show recently used commands for quick access</p>
|
||||
</div>
|
||||
|
||||
<div class="demo-feature">
|
||||
<fa-icon [icon]="faEye" class="demo-feature-icon"></fa-icon>
|
||||
<h4>Context Aware</h4>
|
||||
<p>Commands can be shown or hidden based on application state</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Usage Statistics -->
|
||||
<section class="demo-section">
|
||||
<h3 class="demo-section-title">Usage Statistics</h3>
|
||||
<div class="demo-stats">
|
||||
<div class="demo-stat">
|
||||
<div class="demo-stat-value">{{ registeredCommandsCount }}</div>
|
||||
<div class="demo-stat-label">Registered Commands</div>
|
||||
</div>
|
||||
<div class="demo-stat">
|
||||
<div class="demo-stat-value">{{ recentCommandsCount }}</div>
|
||||
<div class="demo-stat-label">Recent Commands</div>
|
||||
</div>
|
||||
<div class="demo-stat">
|
||||
<div class="demo-stat-value">{{ executionCount }}</div>
|
||||
<div class="demo-stat-label">Commands Executed</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Keyboard Shortcuts Guide -->
|
||||
<section class="demo-section">
|
||||
<h3 class="demo-section-title">Keyboard Shortcuts</h3>
|
||||
<div class="demo-shortcuts">
|
||||
<div class="demo-shortcut">
|
||||
<kbd class="demo-kbd">Ctrl</kbd> + <kbd class="demo-kbd">K</kbd>
|
||||
<span>Open Command Palette</span>
|
||||
</div>
|
||||
<div class="demo-shortcut">
|
||||
<kbd class="demo-kbd">↑</kbd> / <kbd class="demo-kbd">↓</kbd>
|
||||
<span>Navigate Results</span>
|
||||
</div>
|
||||
<div class="demo-shortcut">
|
||||
<kbd class="demo-kbd">Enter</kbd>
|
||||
<span>Execute Selected Command</span>
|
||||
</div>
|
||||
<div class="demo-shortcut">
|
||||
<kbd class="demo-kbd">Esc</kbd>
|
||||
<span>Close Palette</span>
|
||||
</div>
|
||||
<div class="demo-shortcut">
|
||||
<kbd class="demo-kbd">Tab</kbd>
|
||||
<span>Navigate Results (Alternative)</span>
|
||||
</div>
|
||||
<div class="demo-shortcut">
|
||||
<kbd class="demo-kbd">/</kbd>
|
||||
<span>Quick Search</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Command Palette Component -->
|
||||
<ui-command-palette
|
||||
#commandPalette
|
||||
[size]="paletteSize"
|
||||
[showFooter]="true"
|
||||
[autoFocus]="true"
|
||||
(opened)="onPaletteOpened()"
|
||||
(closed)="onPaletteClosed()"
|
||||
(commandExecuted)="onCommandExecuted($event)"
|
||||
/>
|
||||
</div>
|
||||
`,
|
||||
styleUrl: './command-palette-demo.component.scss'
|
||||
})
|
||||
export class CommandPaletteDemoComponent implements OnInit, OnDestroy {
|
||||
@ViewChild('commandPalette') commandPalette!: CommandPaletteComponent;
|
||||
|
||||
private router = inject(Router);
|
||||
private commandService = inject(CommandPaletteService);
|
||||
|
||||
// Icons
|
||||
readonly faPalette = faPalette;
|
||||
readonly faKeyboard = faKeyboard;
|
||||
readonly faPlus = faPlus;
|
||||
readonly faSearch = faSearch;
|
||||
readonly faRocket = faRocket;
|
||||
readonly faCog = faCog;
|
||||
readonly faCopy = faCopy;
|
||||
readonly faEye = faEye;
|
||||
readonly faHome = faHome;
|
||||
readonly faUser = faUser;
|
||||
readonly faFile = faFile;
|
||||
readonly faEdit = faEdit;
|
||||
readonly faTools = faTools;
|
||||
readonly faQuestion = faQuestion;
|
||||
readonly faSave = faSave;
|
||||
readonly faUndo = faUndo;
|
||||
readonly faRedo = faRedo;
|
||||
readonly faPaste = faPaste;
|
||||
|
||||
// Component state
|
||||
paletteSize: 'md' | 'lg' | 'xl' = 'lg';
|
||||
executionCount = 0;
|
||||
|
||||
config = {
|
||||
showCategories: true,
|
||||
showShortcuts: true,
|
||||
showRecent: true,
|
||||
maxResults: 20,
|
||||
recentLimit: 5
|
||||
};
|
||||
|
||||
globalShortcuts = [
|
||||
createShortcuts().commandPalette(),
|
||||
createShortcuts().quickSearch(),
|
||||
createShortcuts().create('/', { preventDefault: true })
|
||||
];
|
||||
|
||||
get registeredCommandsCount(): number {
|
||||
return this.commandService.commands().length;
|
||||
}
|
||||
|
||||
get recentCommandsCount(): number {
|
||||
return this.commandService.recentCommands().length;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.registerSampleCommands();
|
||||
this.applyConfig();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
// Clean up registered commands
|
||||
this.commandService.clearCommands();
|
||||
}
|
||||
|
||||
openCommandPalette(): void {
|
||||
this.commandPalette.open();
|
||||
}
|
||||
|
||||
handleGlobalShortcut(event: any): void {
|
||||
const shortcut = event.shortcut;
|
||||
|
||||
if (shortcut.key === 'k' && (shortcut.ctrlKey || shortcut.metaKey)) {
|
||||
this.commandPalette.toggle();
|
||||
} else if (shortcut.key === '/') {
|
||||
this.commandPalette.open();
|
||||
}
|
||||
}
|
||||
|
||||
registerSampleCommands(): void {
|
||||
const sampleCommands: Command[] = [
|
||||
// Navigation Commands
|
||||
{
|
||||
id: 'nav-home',
|
||||
title: 'Go Home',
|
||||
description: 'Navigate to the home page',
|
||||
icon: faHome,
|
||||
category: CommandCategory.NAVIGATION,
|
||||
keywords: ['home', 'dashboard', 'main'],
|
||||
shortcut: ['Ctrl', 'H'],
|
||||
handler: () => this.showToast('Navigating to home...'),
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
id: 'nav-profile',
|
||||
title: 'View Profile',
|
||||
description: 'Go to user profile page',
|
||||
icon: faUser,
|
||||
category: CommandCategory.NAVIGATION,
|
||||
keywords: ['profile', 'user', 'account'],
|
||||
handler: () => this.showToast('Opening profile...'),
|
||||
order: 2
|
||||
},
|
||||
{
|
||||
id: 'nav-settings',
|
||||
title: 'Open Settings',
|
||||
description: 'Access application settings',
|
||||
icon: faCog,
|
||||
category: CommandCategory.SETTINGS,
|
||||
keywords: ['settings', 'preferences', 'config'],
|
||||
shortcut: ['Ctrl', ','],
|
||||
handler: () => this.showToast('Opening settings...'),
|
||||
order: 1
|
||||
},
|
||||
|
||||
// File Commands
|
||||
{
|
||||
id: 'file-new',
|
||||
title: 'New File',
|
||||
description: 'Create a new file',
|
||||
icon: faFile,
|
||||
category: CommandCategory.FILE,
|
||||
keywords: ['new', 'create', 'file', 'document'],
|
||||
shortcut: ['Ctrl', 'N'],
|
||||
handler: () => this.showToast('Creating new file...'),
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
id: 'file-save',
|
||||
title: 'Save File',
|
||||
description: 'Save the current file',
|
||||
icon: faSave,
|
||||
category: CommandCategory.FILE,
|
||||
keywords: ['save', 'file', 'document'],
|
||||
shortcut: ['Ctrl', 'S'],
|
||||
handler: () => this.showToast('Saving file...'),
|
||||
order: 2
|
||||
},
|
||||
|
||||
// Edit Commands
|
||||
{
|
||||
id: 'edit-copy',
|
||||
title: 'Copy',
|
||||
description: 'Copy selected content',
|
||||
icon: faCopy,
|
||||
category: CommandCategory.EDIT,
|
||||
keywords: ['copy', 'clipboard'],
|
||||
shortcut: ['Ctrl', 'C'],
|
||||
handler: () => this.showToast('Content copied!'),
|
||||
order: 1
|
||||
},
|
||||
{
|
||||
id: 'edit-paste',
|
||||
title: 'Paste',
|
||||
description: 'Paste from clipboard',
|
||||
icon: faPaste,
|
||||
category: CommandCategory.EDIT,
|
||||
keywords: ['paste', 'clipboard'],
|
||||
shortcut: ['Ctrl', 'V'],
|
||||
handler: () => this.showToast('Content pasted!'),
|
||||
order: 2
|
||||
},
|
||||
{
|
||||
id: 'edit-undo',
|
||||
title: 'Undo',
|
||||
description: 'Undo last action',
|
||||
icon: faUndo,
|
||||
category: CommandCategory.EDIT,
|
||||
keywords: ['undo', 'revert'],
|
||||
shortcut: ['Ctrl', 'Z'],
|
||||
handler: () => this.showToast('Action undone!'),
|
||||
order: 3
|
||||
},
|
||||
{
|
||||
id: 'edit-redo',
|
||||
title: 'Redo',
|
||||
description: 'Redo last undone action',
|
||||
icon: faRedo,
|
||||
category: CommandCategory.EDIT,
|
||||
keywords: ['redo', 'repeat'],
|
||||
shortcut: ['Ctrl', 'Y'],
|
||||
handler: () => this.showToast('Action redone!'),
|
||||
order: 4
|
||||
},
|
||||
|
||||
// Search Commands
|
||||
{
|
||||
id: 'search-global',
|
||||
title: 'Global Search',
|
||||
description: 'Search across all content',
|
||||
icon: faSearch,
|
||||
category: CommandCategory.SEARCH,
|
||||
keywords: ['search', 'find', 'global'],
|
||||
shortcut: ['Ctrl', 'Shift', 'F'],
|
||||
handler: () => this.showToast('Opening global search...'),
|
||||
order: 1
|
||||
},
|
||||
|
||||
// Tools Commands
|
||||
{
|
||||
id: 'tools-theme',
|
||||
title: 'Toggle Theme',
|
||||
description: 'Switch between light and dark theme',
|
||||
icon: faTools,
|
||||
category: CommandCategory.TOOLS,
|
||||
keywords: ['theme', 'dark', 'light', 'toggle'],
|
||||
handler: () => this.showToast('Theme toggled!'),
|
||||
order: 1
|
||||
},
|
||||
|
||||
// Help Commands
|
||||
{
|
||||
id: 'help-docs',
|
||||
title: 'Documentation',
|
||||
description: 'Open help documentation',
|
||||
icon: faQuestion,
|
||||
category: CommandCategory.HELP,
|
||||
keywords: ['help', 'docs', 'documentation'],
|
||||
handler: () => this.showToast('Opening documentation...'),
|
||||
order: 1
|
||||
},
|
||||
|
||||
// Action Commands
|
||||
{
|
||||
id: 'action-refresh',
|
||||
title: 'Refresh Page',
|
||||
description: 'Reload the current page',
|
||||
icon: faRocket,
|
||||
category: CommandCategory.ACTIONS,
|
||||
keywords: ['refresh', 'reload', 'update'],
|
||||
shortcut: ['F5'],
|
||||
handler: () => this.showToast('Page refreshed!'),
|
||||
order: 1
|
||||
}
|
||||
];
|
||||
|
||||
this.commandService.registerCommands(sampleCommands);
|
||||
}
|
||||
|
||||
clearCommands(): void {
|
||||
this.commandService.clearCommands();
|
||||
this.commandService.clearRecentCommands();
|
||||
}
|
||||
|
||||
updateConfig(key: string, event: Event): void {
|
||||
const target = event.target as HTMLInputElement;
|
||||
let value: any = target.type === 'checkbox' ? target.checked :
|
||||
target.type === 'number' ? parseInt(target.value, 10) :
|
||||
target.value;
|
||||
|
||||
(this.config as any)[key] = value;
|
||||
this.applyConfig();
|
||||
}
|
||||
|
||||
updatePaletteSize(event: Event): void {
|
||||
const target = event.target as HTMLSelectElement;
|
||||
this.paletteSize = target.value as 'md' | 'lg' | 'xl';
|
||||
}
|
||||
|
||||
private applyConfig(): void {
|
||||
this.commandService.updateConfig({
|
||||
showCategories: this.config.showCategories,
|
||||
showShortcuts: this.config.showShortcuts,
|
||||
showRecent: this.config.showRecent,
|
||||
maxResults: this.config.maxResults,
|
||||
recentLimit: this.config.recentLimit
|
||||
});
|
||||
}
|
||||
|
||||
onPaletteOpened(): void {
|
||||
console.log('Command palette opened');
|
||||
}
|
||||
|
||||
onPaletteClosed(): void {
|
||||
console.log('Command palette closed');
|
||||
}
|
||||
|
||||
onCommandExecuted(event: { commandId: string; context: CommandExecutionContext }): void {
|
||||
this.executionCount++;
|
||||
console.log('Command executed:', event);
|
||||
}
|
||||
|
||||
private showToast(message: string): void {
|
||||
// Simple toast implementation for demo
|
||||
const toast = document.createElement('div');
|
||||
toast.className = 'demo-toast';
|
||||
toast.textContent = message;
|
||||
toast.style.cssText = `
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background: #333;
|
||||
color: white;
|
||||
padding: 12px 24px;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
z-index: 10000;
|
||||
font-size: 14px;
|
||||
animation: slideIn 0.3s ease;
|
||||
`;
|
||||
|
||||
document.body.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.style.animation = 'slideOut 0.3s ease forwards';
|
||||
setTimeout(() => document.body.removeChild(toast), 300);
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user