--- name: ng-alain-component-development description: "Create components using ng-alain (@delon/abc) and ng-zorro-antd UI libraries. Use this skill when building enterprise UI features with ST (Simple Table), SF (Schema Form), ACL (Access Control), PageHeader, ReuseTab, and other @delon components. Ensures proper integration with ng-alain architecture, theming system, responsive layouts, and accessibility standards while following Angular 20 patterns." license: "MIT" --- # ng-alain Component Development Skill This skill helps create enterprise UI components using ng-alain and ng-zorro-antd. ## Core Libraries ### @delon Packages - **@delon/abc**: Business components (ST, SV, SEModule, etc.) - **@delon/form**: Dynamic schema-based forms (SF) - **@delon/auth**: Authentication and authorization - **@delon/acl**: Access Control List - **@delon/theme**: Theming and layout system - **@delon/util**: Utility functions ### ng-zorro-antd - Complete Ant Design component library - Icons, layouts, forms, tables, modals, etc. ## Common Patterns ### 1. ST (Simple Table) Component ```typescript import { Component, signal, inject } from '@angular/core'; import { STColumn, STData, STComponent } from '@delon/abc/st'; import { SHARED_IMPORTS } from '@shared'; @Component({ selector: 'app-task-table', standalone: true, imports: [SHARED_IMPORTS, STComponent], template: ` ` }) export class TaskTableComponent { private taskService = inject(TaskService); loading = signal(false); tasks = signal([]); columns: STColumn[] = [ { title: 'ID', index: 'id', width: 80, fixed: 'left' }, { title: 'Title', index: 'title', width: 200 }, { title: 'Status', index: 'status', type: 'badge', badge: { pending: { text: 'Pending', color: 'processing' }, 'in-progress': { text: 'In Progress', color: 'warning' }, completed: { text: 'Completed', color: 'success' } } }, { title: 'Assignee', index: 'assigneeName', width: 150 }, { title: 'Due Date', index: 'dueDate', type: 'date', dateFormat: 'yyyy-MM-dd' }, { title: 'Actions', buttons: [ { text: 'Edit', icon: 'edit', click: (record: any) => this.edit(record) }, { text: 'Delete', icon: 'delete', type: 'del', pop: { title: 'Confirm delete?', okType: 'danger' }, click: (record: any) => this.delete(record) } ] } ]; ngOnInit(): void { this.loadTasks(); } async loadTasks(): Promise { this.loading.set(true); try { const tasks = await this.taskService.getTasks(); this.tasks.set(tasks); } finally { this.loading.set(false); } } handleChange(event: any): void { console.log('Table change:', event); } edit(record: any): void { console.log('Edit:', record); } delete(record: any): void { console.log('Delete:', record); } } ``` ### 2. SF (Schema Form) Component ```typescript import { Component, signal, inject, output } from '@angular/core'; import { SFSchema, SFComponent } from '@delon/form'; import { SHARED_IMPORTS } from '@shared'; @Component({ selector: 'app-task-form', standalone: true, imports: [SHARED_IMPORTS, SFComponent], template: ` ` }) export class TaskFormComponent { loading = signal(false); taskSubmit = output(); schema: SFSchema = { properties: { title: { type: 'string', title: 'Task Title', maxLength: 200, ui: { placeholder: 'Enter task title', grid: { span: 24 } } }, description: { type: 'string', title: 'Description', ui: { widget: 'textarea', autosize: { minRows: 3, maxRows: 6 }, grid: { span: 24 } } }, status: { type: 'string', title: 'Status', enum: [ { label: 'Pending', value: 'pending' }, { label: 'In Progress', value: 'in-progress' }, { label: 'Completed', value: 'completed' } ], default: 'pending', ui: { widget: 'select', grid: { span: 12 } } }, priority: { type: 'string', title: 'Priority', enum: [ { label: 'Low', value: 'low' }, { label: 'Medium', value: 'medium' }, { label: 'High', value: 'high' } ], default: 'medium', ui: { widget: 'radio', grid: { span: 12 } } }, assignee: { type: 'string', title: 'Assignee', ui: { widget: 'select', asyncData: () => this.loadUsers(), grid: { span: 12 } } }, dueDate: { type: 'string', title: 'Due Date', format: 'date', ui: { widget: 'date', grid: { span: 12 } } }, tags: { type: 'array', title: 'Tags', items: { type: 'string' }, ui: { widget: 'select', mode: 'tags', grid: { span: 24 } } } }, required: ['title', 'assignee'], ui: { grid: { gutter: 16 } } }; handleSubmit(value: any): void { console.log('Form submitted:', value); this.taskSubmit.emit(value); } handleChange(value: any): void { console.log('Form changed:', value); } private async loadUsers(): Promise { // Load users for assignee dropdown return [ { label: 'User 1', value: 'user1' }, { label: 'User 2', value: 'user2' } ]; } } ``` ### 3. Page Header with Actions ```typescript import { Component } from '@angular/core'; import { PageHeaderComponent } from '@delon/abc/page-header'; import { SHARED_IMPORTS } from '@shared'; @Component({ selector: 'app-task-page', standalone: true, imports: [SHARED_IMPORTS, PageHeaderComponent], template: ` ` }) export class TaskPageComponent { blueprintName = signal('My Blueprint'); breadcrumb = [ { title: 'Home', link: '/' }, { title: 'Blueprints', link: '/blueprints' }, { title: 'Tasks' } ]; createTask(): void { console.log('Create new task'); } refresh(): void { console.log('Refresh tasks'); } } ``` ### 4. ACL (Access Control) ```typescript import { Component, inject } from '@angular/core'; import { ACLService } from '@delon/acl'; import { SHARED_IMPORTS } from '@shared'; @Component({ selector: 'app-task-actions', standalone: true, imports: [SHARED_IMPORTS], template: ` @if (canEdit()) { } ` }) export class TaskActionsComponent { private aclService = inject(ACLService); canEdit = signal(false); ngOnInit(): void { // Check permission programmatically this.canEdit.set(this.aclService.can('task:edit')); } create(): void { console.log('Create task'); } edit(): void { console.log('Edit task'); } delete(): void { console.log('Delete task'); } } ``` ### 5. Responsive Layout ```typescript import { Component } from '@angular/core'; import { SHARED_IMPORTS } from '@shared'; @Component({ selector: 'app-dashboard', standalone: true, imports: [SHARED_IMPORTS], template: `
` }) export class DashboardComponent { totalTasks = signal(100); completedTasks = signal(60); inProgressTasks = signal(25); pendingTasks = signal(15); } ``` ### 6. Modal and Drawer ```typescript import { Component, inject } from '@angular/core'; import { NzModalService } from 'ng-zorro-antd/modal'; import { NzDrawerService } from 'ng-zorro-antd/drawer'; import { SHARED_IMPORTS } from '@shared'; import { TaskFormComponent } from './task-form.component'; @Component({ selector: 'app-task-manager', standalone: true, imports: [SHARED_IMPORTS], template: ` ` }) export class TaskManagerComponent { private modal = inject(NzModalService); private drawer = inject(NzDrawerService); openModal(): void { const modalRef = this.modal.create({ nzTitle: 'Create Task', nzContent: TaskFormComponent, nzWidth: 720, nzFooter: null }); // Listen to form submission modalRef.componentInstance!.taskSubmit.subscribe((task: any) => { console.log('Task submitted:', task); modalRef.close(); }); } openDrawer(): void { const drawerRef = this.drawer.create({ nzTitle: 'Task Details', nzContent: TaskFormComponent, nzWidth: 640, nzClosable: true }); drawerRef.afterClose.subscribe(() => { console.log('Drawer closed'); }); } } ``` ## ng-alain Theming ### Using Theme Variables ```scss // Use ng-alain theme variables @import '@delon/theme/system/index'; .task-card { background: var(--bg-color); border: 1px solid var(--border-color); padding: var(--padding-lg); .title { color: var(--text-color); font-size: var(--font-size-lg); } } ``` ### Dark Mode Support ```typescript import { Component, inject } from '@angular/core'; import { SettingsService } from '@delon/theme'; @Component({ selector: 'app-theme-toggle', template: ` ` }) export class ThemeToggleComponent { private settings = inject(SettingsService); isDark = signal(false); ngOnInit(): void { this.isDark.set(this.settings.layout.theme === 'dark'); } toggleTheme(): void { const newTheme = this.isDark() ? 'light' : 'dark'; this.settings.setLayout('theme', newTheme); this.isDark.set(newTheme === 'dark'); } } ``` ## Best Practices ### 1. Use SHARED_IMPORTS ```typescript // Define in shared module export const SHARED_IMPORTS = [ CommonModule, ReactiveFormsModule, // ng-zorro-antd NzButtonModule, NzCardModule, NzFormModule, NzInputModule, // @delon STComponent, SFComponent, PageHeaderComponent ]; ``` ### 2. Responsive Design ```typescript // Use ng-zorro responsive utilities
Content
``` ### 3. Accessibility ```html Task Title ``` ## Checklist When creating ng-alain components: - [ ] Use standalone components - [ ] Import SHARED_IMPORTS - [ ] Use STComponent for data tables - [ ] Use SFComponent for complex forms - [ ] Implement responsive layout - [ ] Add ACL permissions where needed - [ ] Use PageHeader for page titles - [ ] Implement proper loading states - [ ] Add error handling - [ ] Follow ng-alain theming system - [ ] Support dark mode - [ ] Ensure accessibility (ARIA) - [ ] Test on mobile devices ## References - [ng-alain Documentation](https://ng-alain.com) - [ng-zorro-antd Documentation](https://ng.ant.design) - [@delon/abc Components](https://ng-alain.com/components) - [ng-alain Instructions](.github/instructions/ng-alain-delon.instructions.md) - [Angular Component Skill](./angular-component/SKILL.md)