- 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>
574 lines
17 KiB
TypeScript
574 lines
17 KiB
TypeScript
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);
|
|
}
|
|
} |