[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6JB29HGCJ472B12ZTTWMS8N":3,"skill-same:01M6JB29HGCJ472B12ZTTWMS8N":70},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":38,"linkOnly":39,"markdownContent":40,"markdownBody":41,"frontMatter":42,"refName":43,"commitSha":44,"skillDirectory":45,"forksCount":13,"repositoryHtmlUrl":46,"repositoryHomepageUrl":6,"ownerHtmlUrl":47,"ownerBlogUrl":6,"ownerDescription":48,"updatedAt":49,"install":50,"resources":63},"01M6JB29HGCJ472B12ZTTWMS8N","ng-alain-component-development",null,"Create components using ng-alain (@delon\u002Fabc) 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.","superhealth\u002Fskills-hub","superhealth","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6292112?v=4","01M6JA6E7F21BYK5W3E4P270TT","01M6JA6EC0W8MPHKDJVBZDSEZ0",0,"MIT","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002F7spade\u002Fng-alain-component-development\u002FSKILL.md",[],[18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37],"component","component development","development","ng","ng alain component development","features","components","form","Access Control","responsive","patterns","standards","table","system","access","angular","ui","create","libraries","architecture","2026-11-10 10:12:30",false,"---\nname: ng-alain-component-development\ndescription: \"Create components using ng-alain (@delon\u002Fabc) 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.\"\nlicense: \"MIT\"\n---\n\n# ng-alain Component Development Skill\n\nThis skill helps create enterprise UI components using ng-alain and ng-zorro-antd.\n\n## Core Libraries\n\n### @delon Packages\n- **@delon\u002Fabc**: Business components (ST, SV, SEModule, etc.)\n- **@delon\u002Fform**: Dynamic schema-based forms (SF)\n- **@delon\u002Fauth**: Authentication and authorization\n- **@delon\u002Facl**: Access Control List\n- **@delon\u002Ftheme**: Theming and layout system\n- **@delon\u002Futil**: Utility functions\n\n### ng-zorro-antd\n- Complete Ant Design component library\n- Icons, layouts, forms, tables, modals, etc.\n\n## Common Patterns\n\n### 1. ST (Simple Table) Component\n\n```typescript\nimport { Component, signal, inject } from '@angular\u002Fcore';\nimport { STColumn, STData, STComponent } from '@delon\u002Fabc\u002Fst';\nimport { SHARED_IMPORTS } from '@shared';\n\n@Component({\n  selector: 'app-task-table',\n  standalone: true,\n  imports: [SHARED_IMPORTS, STComponent],\n  template: `\n    \u003Cst \n      [data]=\"tasks()\" \n      [columns]=\"columns\"\n      [loading]=\"loading()\"\n      [page]=\"{ show: true, showSize: true }\"\n      (change)=\"handleChange($event)\"\n    \u002F>\n  `\n})\nexport class TaskTableComponent {\n  private taskService = inject(TaskService);\n  \n  loading = signal(false);\n  tasks = signal\u003CSTData[]>([]);\n  \n  columns: STColumn[] = [\n    { \n      title: 'ID', \n      index: 'id', \n      width: 80,\n      fixed: 'left'\n    },\n    { \n      title: 'Title', \n      index: 'title',\n      width: 200\n    },\n    { \n      title: 'Status', \n      index: 'status', \n      type: 'badge',\n      badge: {\n        pending: { text: 'Pending', color: 'processing' },\n        'in-progress': { text: 'In Progress', color: 'warning' },\n        completed: { text: 'Completed', color: 'success' }\n      }\n    },\n    {\n      title: 'Assignee',\n      index: 'assigneeName',\n      width: 150\n    },\n    {\n      title: 'Due Date',\n      index: 'dueDate',\n      type: 'date',\n      dateFormat: 'yyyy-MM-dd'\n    },\n    {\n      title: 'Actions',\n      buttons: [\n        {\n          text: 'Edit',\n          icon: 'edit',\n          click: (record: any) => this.edit(record)\n        },\n        {\n          text: 'Delete',\n          icon: 'delete',\n          type: 'del',\n          pop: {\n            title: 'Confirm delete?',\n            okType: 'danger'\n          },\n          click: (record: any) => this.delete(record)\n        }\n      ]\n    }\n  ];\n  \n  ngOnInit(): void {\n    this.loadTasks();\n  }\n  \n  async loadTasks(): Promise\u003Cvoid> {\n    this.loading.set(true);\n    try {\n      const tasks = await this.taskService.getTasks();\n      this.tasks.set(tasks);\n    } finally {\n      this.loading.set(false);\n    }\n  }\n  \n  handleChange(event: any): void {\n    console.log('Table change:', event);\n  }\n  \n  edit(record: any): void {\n    console.log('Edit:', record);\n  }\n  \n  delete(record: any): void {\n    console.log('Delete:', record);\n  }\n}\n```\n\n### 2. SF (Schema Form) Component\n\n```typescript\nimport { Component, signal, inject, output } from '@angular\u002Fcore';\nimport { SFSchema, SFComponent } from '@delon\u002Fform';\nimport { SHARED_IMPORTS } from '@shared';\n\n@Component({\n  selector: 'app-task-form',\n  standalone: true,\n  imports: [SHARED_IMPORTS, SFComponent],\n  template: `\n    \u003Csf \n      [schema]=\"schema\" \n      [loading]=\"loading()\"\n      (formSubmit)=\"handleSubmit($event)\"\n      (formChange)=\"handleChange($event)\"\n    \u002F>\n  `\n})\nexport class TaskFormComponent {\n  loading = signal(false);\n  taskSubmit = output\u003Cany>();\n  \n  schema: SFSchema = {\n    properties: {\n      title: {\n        type: 'string',\n        title: 'Task Title',\n        maxLength: 200,\n        ui: {\n          placeholder: 'Enter task title',\n          grid: { span: 24 }\n        }\n      },\n      description: {\n        type: 'string',\n        title: 'Description',\n        ui: {\n          widget: 'textarea',\n          autosize: { minRows: 3, maxRows: 6 },\n          grid: { span: 24 }\n        }\n      },\n      status: {\n        type: 'string',\n        title: 'Status',\n        enum: [\n          { label: 'Pending', value: 'pending' },\n          { label: 'In Progress', value: 'in-progress' },\n          { label: 'Completed', value: 'completed' }\n        ],\n        default: 'pending',\n        ui: {\n          widget: 'select',\n          grid: { span: 12 }\n        }\n      },\n      priority: {\n        type: 'string',\n        title: 'Priority',\n        enum: [\n          { label: 'Low', value: 'low' },\n          { label: 'Medium', value: 'medium' },\n          { label: 'High', value: 'high' }\n        ],\n        default: 'medium',\n        ui: {\n          widget: 'radio',\n          grid: { span: 12 }\n        }\n      },\n      assignee: {\n        type: 'string',\n        title: 'Assignee',\n        ui: {\n          widget: 'select',\n          asyncData: () => this.loadUsers(),\n          grid: { span: 12 }\n        }\n      },\n      dueDate: {\n        type: 'string',\n        title: 'Due Date',\n        format: 'date',\n        ui: {\n          widget: 'date',\n          grid: { span: 12 }\n        }\n      },\n      tags: {\n        type: 'array',\n        title: 'Tags',\n        items: {\n          type: 'string'\n        },\n        ui: {\n          widget: 'select',\n          mode: 'tags',\n          grid: { span: 24 }\n        }\n      }\n    },\n    required: ['title', 'assignee'],\n    ui: {\n      grid: { gutter: 16 }\n    }\n  };\n  \n  handleSubmit(value: any): void {\n    console.log('Form submitted:', value);\n    this.taskSubmit.emit(value);\n  }\n  \n  handleChange(value: any): void {\n    console.log('Form changed:', value);\n  }\n  \n  private async loadUsers(): Promise\u003Cany[]> {\n    \u002F\u002F Load users for assignee dropdown\n    return [\n      { label: 'User 1', value: 'user1' },\n      { label: 'User 2', value: 'user2' }\n    ];\n  }\n}\n```\n\n### 3. Page Header with Actions\n\n```typescript\nimport { Component } from '@angular\u002Fcore';\nimport { PageHeaderComponent } from '@delon\u002Fabc\u002Fpage-header';\nimport { SHARED_IMPORTS } from '@shared';\n\n@Component({\n  selector: 'app-task-page',\n  standalone: true,\n  imports: [SHARED_IMPORTS, PageHeaderComponent],\n  template: `\n    \u003Cpage-header \n      [title]=\"'Task Management'\"\n      [subtitle]=\"'Manage tasks for ' + blueprintName()\"\n      [breadcrumb]=\"breadcrumb\"\n    >\n      \u003Cng-template #extra>\n        \u003Cbutton nz-button nzType=\"primary\" (click)=\"createTask()\">\n          \u003Ci nz-icon nzType=\"plus\">\u003C\u002Fi>\n          New Task\n        \u003C\u002Fbutton>\n        \u003Cbutton nz-button (click)=\"refresh()\">\n          \u003Ci nz-icon nzType=\"reload\">\u003C\u002Fi>\n          Refresh\n        \u003C\u002Fbutton>\n      \u003C\u002Fng-template>\n    \u003C\u002Fpage-header>\n    \n    \u003Cnz-card>\n      \u003Capp-task-table \u002F>\n    \u003C\u002Fnz-card>\n  `\n})\nexport class TaskPageComponent {\n  blueprintName = signal('My Blueprint');\n  \n  breadcrumb = [\n    { title: 'Home', link: '\u002F' },\n    { title: 'Blueprints', link: '\u002Fblueprints' },\n    { title: 'Tasks' }\n  ];\n  \n  createTask(): void {\n    console.log('Create new task');\n  }\n  \n  refresh(): void {\n    console.log('Refresh tasks');\n  }\n}\n```\n\n### 4. ACL (Access Control)\n\n```typescript\nimport { Component, inject } from '@angular\u002Fcore';\nimport { ACLService } from '@delon\u002Facl';\nimport { SHARED_IMPORTS } from '@shared';\n\n@Component({\n  selector: 'app-task-actions',\n  standalone: true,\n  imports: [SHARED_IMPORTS],\n  template: `\n    \u003Cnz-space>\n      \u003C!-- Show button only if user has permission -->\n      \u003Cbutton \n        *nzSpaceItem\n        *aclIf=\"'task:create'\"\n        nz-button \n        nzType=\"primary\"\n        (click)=\"create()\"\n      >\n        Create Task\n      \u003C\u002Fbutton>\n      \n      \u003Cbutton \n        *nzSpaceItem\n        *aclIf=\"'task:delete'\"\n        nz-button \n        nzDanger\n        (click)=\"delete()\"\n      >\n        Delete\n      \u003C\u002Fbutton>\n      \n      \u003C!-- Check permission in code -->\n      @if (canEdit()) {\n        \u003Cbutton \n          *nzSpaceItem\n          nz-button \n          (click)=\"edit()\"\n        >\n          Edit\n        \u003C\u002Fbutton>\n      }\n    \u003C\u002Fnz-space>\n  `\n})\nexport class TaskActionsComponent {\n  private aclService = inject(ACLService);\n  \n  canEdit = signal(false);\n  \n  ngOnInit(): void {\n    \u002F\u002F Check permission programmatically\n    this.canEdit.set(this.aclService.can('task:edit'));\n  }\n  \n  create(): void {\n    console.log('Create task');\n  }\n  \n  edit(): void {\n    console.log('Edit task');\n  }\n  \n  delete(): void {\n    console.log('Delete task');\n  }\n}\n```\n\n### 5. Responsive Layout\n\n```typescript\nimport { Component } from '@angular\u002Fcore';\nimport { SHARED_IMPORTS } from '@shared';\n\n@Component({\n  selector: 'app-dashboard',\n  standalone: true,\n  imports: [SHARED_IMPORTS],\n  template: `\n    \u003Cdiv nz-row [nzGutter]=\"[16, 16]\">\n      \u003C!-- Responsive columns -->\n      \u003Cdiv nz-col [nzXs]=\"24\" [nzSm]=\"12\" [nzMd]=\"8\" [nzLg]=\"6\">\n        \u003Cnz-card nzTitle=\"Total Tasks\">\n          \u003Cnz-statistic \n            [nzValue]=\"totalTasks()\" \n            [nzPrefix]=\"prefixTpl\"\n          \u002F>\n          \u003Cng-template #prefixTpl>\n            \u003Ci nz-icon nzType=\"check-circle\">\u003C\u002Fi>\n          \u003C\u002Fng-template>\n        \u003C\u002Fnz-card>\n      \u003C\u002Fdiv>\n      \n      \u003Cdiv nz-col [nzXs]=\"24\" [nzSm]=\"12\" [nzMd]=\"8\" [nzLg]=\"6\">\n        \u003Cnz-card nzTitle=\"Completed\">\n          \u003Cnz-statistic \n            [nzValue]=\"completedTasks()\" \n            [nzValueStyle]=\"{ color: '#52c41a' }\"\n          \u002F>\n        \u003C\u002Fnz-card>\n      \u003C\u002Fdiv>\n      \n      \u003Cdiv nz-col [nzXs]=\"24\" [nzSm]=\"12\" [nzMd]=\"8\" [nzLg]=\"6\">\n        \u003Cnz-card nzTitle=\"In Progress\">\n          \u003Cnz-statistic \n            [nzValue]=\"inProgressTasks()\" \n            [nzValueStyle]=\"{ color: '#faad14' }\"\n          \u002F>\n        \u003C\u002Fnz-card>\n      \u003C\u002Fdiv>\n      \n      \u003Cdiv nz-col [nzXs]=\"24\" [nzSm]=\"12\" [nzMd]=\"8\" [nzLg]=\"6\">\n        \u003Cnz-card nzTitle=\"Pending\">\n          \u003Cnz-statistic [nzValue]=\"pendingTasks()\" \u002F>\n        \u003C\u002Fnz-card>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  `\n})\nexport class DashboardComponent {\n  totalTasks = signal(100);\n  completedTasks = signal(60);\n  inProgressTasks = signal(25);\n  pendingTasks = signal(15);\n}\n```\n\n### 6. Modal and Drawer\n\n```typescript\nimport { Component, inject } from '@angular\u002Fcore';\nimport { NzModalService } from 'ng-zorro-antd\u002Fmodal';\nimport { NzDrawerService } from 'ng-zorro-antd\u002Fdrawer';\nimport { SHARED_IMPORTS } from '@shared';\nimport { TaskFormComponent } from '.\u002Ftask-form.component';\n\n@Component({\n  selector: 'app-task-manager',\n  standalone: true,\n  imports: [SHARED_IMPORTS],\n  template: `\n    \u003Cbutton nz-button nzType=\"primary\" (click)=\"openModal()\">\n      Open Modal\n    \u003C\u002Fbutton>\n    \u003Cbutton nz-button (click)=\"openDrawer()\">\n      Open Drawer\n    \u003C\u002Fbutton>\n  `\n})\nexport class TaskManagerComponent {\n  private modal = inject(NzModalService);\n  private drawer = inject(NzDrawerService);\n  \n  openModal(): void {\n    const modalRef = this.modal.create({\n      nzTitle: 'Create Task',\n      nzContent: TaskFormComponent,\n      nzWidth: 720,\n      nzFooter: null\n    });\n    \n    \u002F\u002F Listen to form submission\n    modalRef.componentInstance!.taskSubmit.subscribe((task: any) => {\n      console.log('Task submitted:', task);\n      modalRef.close();\n    });\n  }\n  \n  openDrawer(): void {\n    const drawerRef = this.drawer.create({\n      nzTitle: 'Task Details',\n      nzContent: TaskFormComponent,\n      nzWidth: 640,\n      nzClosable: true\n    });\n    \n    drawerRef.afterClose.subscribe(() => {\n      console.log('Drawer closed');\n    });\n  }\n}\n```\n\n## ng-alain Theming\n\n### Using Theme Variables\n\n```scss\n\u002F\u002F Use ng-alain theme variables\n@import '@delon\u002Ftheme\u002Fsystem\u002Findex';\n\n.task-card {\n  background: var(--bg-color);\n  border: 1px solid var(--border-color);\n  padding: var(--padding-lg);\n  \n  .title {\n    color: var(--text-color);\n    font-size: var(--font-size-lg);\n  }\n}\n```\n\n### Dark Mode Support\n\n```typescript\nimport { Component, inject } from '@angular\u002Fcore';\nimport { SettingsService } from '@delon\u002Ftheme';\n\n@Component({\n  selector: 'app-theme-toggle',\n  template: `\n    \u003Cbutton nz-button (click)=\"toggleTheme()\">\n      \u003Ci nz-icon [nzType]=\"isDark() ? 'sun' : 'moon'\">\u003C\u002Fi>\n      {{ isDark() ? 'Light' : 'Dark' }} Mode\n    \u003C\u002Fbutton>\n  `\n})\nexport class ThemeToggleComponent {\n  private settings = inject(SettingsService);\n  \n  isDark = signal(false);\n  \n  ngOnInit(): void {\n    this.isDark.set(this.settings.layout.theme === 'dark');\n  }\n  \n  toggleTheme(): void {\n    const newTheme = this.isDark() ? 'light' : 'dark';\n    this.settings.setLayout('theme', newTheme);\n    this.isDark.set(newTheme === 'dark');\n  }\n}\n```\n\n## Best Practices\n\n### 1. Use SHARED_IMPORTS\n\n```typescript\n\u002F\u002F Define in shared module\nexport const SHARED_IMPORTS = [\n  CommonModule,\n  ReactiveFormsModule,\n  \u002F\u002F ng-zorro-antd\n  NzButtonModule,\n  NzCardModule,\n  NzFormModule,\n  NzInputModule,\n  \u002F\u002F @delon\n  STComponent,\n  SFComponent,\n  PageHeaderComponent\n];\n```\n\n### 2. Responsive Design\n\n```typescript\n\u002F\u002F Use ng-zorro responsive utilities\n\u003Cdiv nz-row [nzGutter]=\"16\">\n  \u003Cdiv nz-col \n    [nzXs]=\"24\"  \u002F\u002F Mobile: full width\n    [nzSm]=\"12\"  \u002F\u002F Tablet: half width\n    [nzMd]=\"8\"   \u002F\u002F Desktop: one third\n    [nzLg]=\"6\"   \u002F\u002F Large: one quarter\n  >\n    Content\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n```\n\n### 3. Accessibility\n\n```html\n\u003C!-- Use proper ARIA attributes -->\n\u003Cbutton \n  nz-button \n  aria-label=\"Create new task\"\n  [attr.aria-disabled]=\"loading()\"\n>\n  Create\n\u003C\u002Fbutton>\n\n\u003C!-- Proper form labels -->\n\u003Cnz-form-item>\n  \u003Cnz-form-label nzFor=\"title\" nzRequired>\n    Task Title\n  \u003C\u002Fnz-form-label>\n  \u003Cnz-form-control>\n    \u003Cinput nz-input id=\"title\" name=\"title\" \u002F>\n  \u003C\u002Fnz-form-control>\n\u003C\u002Fnz-form-item>\n```\n\n## Checklist\n\nWhen creating ng-alain components:\n\n- [ ] Use standalone components\n- [ ] Import SHARED_IMPORTS\n- [ ] Use STComponent for data tables\n- [ ] Use SFComponent for complex forms\n- [ ] Implement responsive layout\n- [ ] Add ACL permissions where needed\n- [ ] Use PageHeader for page titles\n- [ ] Implement proper loading states\n- [ ] Add error handling\n- [ ] Follow ng-alain theming system\n- [ ] Support dark mode\n- [ ] Ensure accessibility (ARIA)\n- [ ] Test on mobile devices\n\n## References\n\n- [ng-alain Documentation](https:\u002F\u002Fng-alain.com)\n- [ng-zorro-antd Documentation](https:\u002F\u002Fng.ant.design)\n- [@delon\u002Fabc Components](https:\u002F\u002Fng-alain.com\u002Fcomponents)\n- [ng-alain Instructions](.github\u002Finstructions\u002Fng-alain-delon.instructions.md)\n- [Angular Component Skill](.\u002Fangular-component\u002FSKILL.md)\n","# ng-alain Component Development Skill\n\nThis skill helps create enterprise UI components using ng-alain and ng-zorro-antd.\n\n## Core Libraries\n\n### @delon Packages\n- **@delon\u002Fabc**: Business components (ST, SV, SEModule, etc.)\n- **@delon\u002Fform**: Dynamic schema-based forms (SF)\n- **@delon\u002Fauth**: Authentication and authorization\n- **@delon\u002Facl**: Access Control List\n- **@delon\u002Ftheme**: Theming and layout system\n- **@delon\u002Futil**: Utility functions\n\n### ng-zorro-antd\n- Complete Ant Design component library\n- Icons, layouts, forms, tables, modals, etc.\n\n## Common Patterns\n\n### 1. ST (Simple Table) Component\n\n```typescript\nimport { Component, signal, inject } from '@angular\u002Fcore';\nimport { STColumn, STData, STComponent } from '@delon\u002Fabc\u002Fst';\nimport { SHARED_IMPORTS } from '@shared';\n\n@Component({\n  selector: 'app-task-table',\n  standalone: true,\n  imports: [SHARED_IMPORTS, STComponent],\n  template: `\n    \u003Cst \n      [data]=\"tasks()\" \n      [columns]=\"columns\"\n      [loading]=\"loading()\"\n      [page]=\"{ show: true, showSize: true }\"\n      (change)=\"handleChange($event)\"\n    \u002F>\n  `\n})\nexport class TaskTableComponent {\n  private taskService = inject(TaskService);\n  \n  loading = signal(false);\n  tasks = signal\u003CSTData[]>([]);\n  \n  columns: STColumn[] = [\n    { \n      title: 'ID', \n      index: 'id', \n      width: 80,\n      fixed: 'left'\n    },\n    { \n      title: 'Title', \n      index: 'title',\n      width: 200\n    },\n    { \n      title: 'Status', \n      index: 'status', \n      type: 'badge',\n      badge: {\n        pending: { text: 'Pending', color: 'processing' },\n        'in-progress': { text: 'In Progress', color: 'warning' },\n        completed: { text: 'Completed', color: 'success' }\n      }\n    },\n    {\n      title: 'Assignee',\n      index: 'assigneeName',\n      width: 150\n    },\n    {\n      title: 'Due Date',\n      index: 'dueDate',\n      type: 'date',\n      dateFormat: 'yyyy-MM-dd'\n    },\n    {\n      title: 'Actions',\n      buttons: [\n        {\n          text: 'Edit',\n          icon: 'edit',\n          click: (record: any) => this.edit(record)\n        },\n        {\n          text: 'Delete',\n          icon: 'delete',\n          type: 'del',\n          pop: {\n            title: 'Confirm delete?',\n            okType: 'danger'\n          },\n          click: (record: any) => this.delete(record)\n        }\n      ]\n    }\n  ];\n  \n  ngOnInit(): void {\n    this.loadTasks();\n  }\n  \n  async loadTasks(): Promise\u003Cvoid> {\n    this.loading.set(true);\n    try {\n      const tasks = await this.taskService.getTasks();\n      this.tasks.set(tasks);\n    } finally {\n      this.loading.set(false);\n    }\n  }\n  \n  handleChange(event: any): void {\n    console.log('Table change:', event);\n  }\n  \n  edit(record: any): void {\n    console.log('Edit:', record);\n  }\n  \n  delete(record: any): void {\n    console.log('Delete:', record);\n  }\n}\n```\n\n### 2. SF (Schema Form) Component\n\n```typescript\nimport { Component, signal, inject, output } from '@angular\u002Fcore';\nimport { SFSchema, SFComponent } from '@delon\u002Fform';\nimport { SHARED_IMPORTS } from '@shared';\n\n@Component({\n  selector: 'app-task-form',\n  standalone: true,\n  imports: [SHARED_IMPORTS, SFComponent],\n  template: `\n    \u003Csf \n      [schema]=\"schema\" \n      [loading]=\"loading()\"\n      (formSubmit)=\"handleSubmit($event)\"\n      (formChange)=\"handleChange($event)\"\n    \u002F>\n  `\n})\nexport class TaskFormComponent {\n  loading = signal(false);\n  taskSubmit = output\u003Cany>();\n  \n  schema: SFSchema = {\n    properties: {\n      title: {\n        type: 'string',\n        title: 'Task Title',\n        maxLength: 200,\n        ui: {\n          placeholder: 'Enter task title',\n          grid: { span: 24 }\n        }\n      },\n      description: {\n        type: 'string',\n        title: 'Description',\n        ui: {\n          widget: 'textarea',\n          autosize: { minRows: 3, maxRows: 6 },\n          grid: { span: 24 }\n        }\n      },\n      status: {\n        type: 'string',\n        title: 'Status',\n        enum: [\n          { label: 'Pending', value: 'pending' },\n          { label: 'In Progress', value: 'in-progress' },\n          { label: 'Completed', value: 'completed' }\n        ],\n        default: 'pending',\n        ui: {\n          widget: 'select',\n          grid: { span: 12 }\n        }\n      },\n      priority: {\n        type: 'string',\n        title: 'Priority',\n        enum: [\n          { label: 'Low', value: 'low' },\n          { label: 'Medium', value: 'medium' },\n          { label: 'High', value: 'high' }\n        ],\n        default: 'medium',\n        ui: {\n          widget: 'radio',\n          grid: { span: 12 }\n        }\n      },\n      assignee: {\n        type: 'string',\n        title: 'Assignee',\n        ui: {\n          widget: 'select',\n          asyncData: () => this.loadUsers(),\n          grid: { span: 12 }\n        }\n      },\n      dueDate: {\n        type: 'string',\n        title: 'Due Date',\n        format: 'date',\n        ui: {\n          widget: 'date',\n          grid: { span: 12 }\n        }\n      },\n      tags: {\n        type: 'array',\n        title: 'Tags',\n        items: {\n          type: 'string'\n        },\n        ui: {\n          widget: 'select',\n          mode: 'tags',\n          grid: { span: 24 }\n        }\n      }\n    },\n    required: ['title', 'assignee'],\n    ui: {\n      grid: { gutter: 16 }\n    }\n  };\n  \n  handleSubmit(value: any): void {\n    console.log('Form submitted:', value);\n    this.taskSubmit.emit(value);\n  }\n  \n  handleChange(value: any): void {\n    console.log('Form changed:', value);\n  }\n  \n  private async loadUsers(): Promise\u003Cany[]> {\n    \u002F\u002F Load users for assignee dropdown\n    return [\n      { label: 'User 1', value: 'user1' },\n      { label: 'User 2', value: 'user2' }\n    ];\n  }\n}\n```\n\n### 3. Page Header with Actions\n\n```typescript\nimport { Component } from '@angular\u002Fcore';\nimport { PageHeaderComponent } from '@delon\u002Fabc\u002Fpage-header';\nimport { SHARED_IMPORTS } from '@shared';\n\n@Component({\n  selector: 'app-task-page',\n  standalone: true,\n  imports: [SHARED_IMPORTS, PageHeaderComponent],\n  template: `\n    \u003Cpage-header \n      [title]=\"'Task Management'\"\n      [subtitle]=\"'Manage tasks for ' + blueprintName()\"\n      [breadcrumb]=\"breadcrumb\"\n    >\n      \u003Cng-template #extra>\n        \u003Cbutton nz-button nzType=\"primary\" (click)=\"createTask()\">\n          \u003Ci nz-icon nzType=\"plus\">\u003C\u002Fi>\n          New Task\n        \u003C\u002Fbutton>\n        \u003Cbutton nz-button (click)=\"refresh()\">\n          \u003Ci nz-icon nzType=\"reload\">\u003C\u002Fi>\n          Refresh\n        \u003C\u002Fbutton>\n      \u003C\u002Fng-template>\n    \u003C\u002Fpage-header>\n    \n    \u003Cnz-card>\n      \u003Capp-task-table \u002F>\n    \u003C\u002Fnz-card>\n  `\n})\nexport class TaskPageComponent {\n  blueprintName = signal('My Blueprint');\n  \n  breadcrumb = [\n    { title: 'Home', link: '\u002F' },\n    { title: 'Blueprints', link: '\u002Fblueprints' },\n    { title: 'Tasks' }\n  ];\n  \n  createTask(): void {\n    console.log('Create new task');\n  }\n  \n  refresh(): void {\n    console.log('Refresh tasks');\n  }\n}\n```\n\n### 4. ACL (Access Control)\n\n```typescript\nimport { Component, inject } from '@angular\u002Fcore';\nimport { ACLService } from '@delon\u002Facl';\nimport { SHARED_IMPORTS } from '@shared';\n\n@Component({\n  selector: 'app-task-actions',\n  standalone: true,\n  imports: [SHARED_IMPORTS],\n  template: `\n    \u003Cnz-space>\n      \u003C!-- Show button only if user has permission -->\n      \u003Cbutton \n        *nzSpaceItem\n        *aclIf=\"'task:create'\"\n        nz-button \n        nzType=\"primary\"\n        (click)=\"create()\"\n      >\n        Create Task\n      \u003C\u002Fbutton>\n      \n      \u003Cbutton \n        *nzSpaceItem\n        *aclIf=\"'task:delete'\"\n        nz-button \n        nzDanger\n        (click)=\"delete()\"\n      >\n        Delete\n      \u003C\u002Fbutton>\n      \n      \u003C!-- Check permission in code -->\n      @if (canEdit()) {\n        \u003Cbutton \n          *nzSpaceItem\n          nz-button \n          (click)=\"edit()\"\n        >\n          Edit\n        \u003C\u002Fbutton>\n      }\n    \u003C\u002Fnz-space>\n  `\n})\nexport class TaskActionsComponent {\n  private aclService = inject(ACLService);\n  \n  canEdit = signal(false);\n  \n  ngOnInit(): void {\n    \u002F\u002F Check permission programmatically\n    this.canEdit.set(this.aclService.can('task:edit'));\n  }\n  \n  create(): void {\n    console.log('Create task');\n  }\n  \n  edit(): void {\n    console.log('Edit task');\n  }\n  \n  delete(): void {\n    console.log('Delete task');\n  }\n}\n```\n\n### 5. Responsive Layout\n\n```typescript\nimport { Component } from '@angular\u002Fcore';\nimport { SHARED_IMPORTS } from '@shared';\n\n@Component({\n  selector: 'app-dashboard',\n  standalone: true,\n  imports: [SHARED_IMPORTS],\n  template: `\n    \u003Cdiv nz-row [nzGutter]=\"[16, 16]\">\n      \u003C!-- Responsive columns -->\n      \u003Cdiv nz-col [nzXs]=\"24\" [nzSm]=\"12\" [nzMd]=\"8\" [nzLg]=\"6\">\n        \u003Cnz-card nzTitle=\"Total Tasks\">\n          \u003Cnz-statistic \n            [nzValue]=\"totalTasks()\" \n            [nzPrefix]=\"prefixTpl\"\n          \u002F>\n          \u003Cng-template #prefixTpl>\n            \u003Ci nz-icon nzType=\"check-circle\">\u003C\u002Fi>\n          \u003C\u002Fng-template>\n        \u003C\u002Fnz-card>\n      \u003C\u002Fdiv>\n      \n      \u003Cdiv nz-col [nzXs]=\"24\" [nzSm]=\"12\" [nzMd]=\"8\" [nzLg]=\"6\">\n        \u003Cnz-card nzTitle=\"Completed\">\n          \u003Cnz-statistic \n            [nzValue]=\"completedTasks()\" \n            [nzValueStyle]=\"{ color: '#52c41a' }\"\n          \u002F>\n        \u003C\u002Fnz-card>\n      \u003C\u002Fdiv>\n      \n      \u003Cdiv nz-col [nzXs]=\"24\" [nzSm]=\"12\" [nzMd]=\"8\" [nzLg]=\"6\">\n        \u003Cnz-card nzTitle=\"In Progress\">\n          \u003Cnz-statistic \n            [nzValue]=\"inProgressTasks()\" \n            [nzValueStyle]=\"{ color: '#faad14' }\"\n          \u002F>\n        \u003C\u002Fnz-card>\n      \u003C\u002Fdiv>\n      \n      \u003Cdiv nz-col [nzXs]=\"24\" [nzSm]=\"12\" [nzMd]=\"8\" [nzLg]=\"6\">\n        \u003Cnz-card nzTitle=\"Pending\">\n          \u003Cnz-statistic [nzValue]=\"pendingTasks()\" \u002F>\n        \u003C\u002Fnz-card>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n  `\n})\nexport class DashboardComponent {\n  totalTasks = signal(100);\n  completedTasks = signal(60);\n  inProgressTasks = signal(25);\n  pendingTasks = signal(15);\n}\n```\n\n### 6. Modal and Drawer\n\n```typescript\nimport { Component, inject } from '@angular\u002Fcore';\nimport { NzModalService } from 'ng-zorro-antd\u002Fmodal';\nimport { NzDrawerService } from 'ng-zorro-antd\u002Fdrawer';\nimport { SHARED_IMPORTS } from '@shared';\nimport { TaskFormComponent } from '.\u002Ftask-form.component';\n\n@Component({\n  selector: 'app-task-manager',\n  standalone: true,\n  imports: [SHARED_IMPORTS],\n  template: `\n    \u003Cbutton nz-button nzType=\"primary\" (click)=\"openModal()\">\n      Open Modal\n    \u003C\u002Fbutton>\n    \u003Cbutton nz-button (click)=\"openDrawer()\">\n      Open Drawer\n    \u003C\u002Fbutton>\n  `\n})\nexport class TaskManagerComponent {\n  private modal = inject(NzModalService);\n  private drawer = inject(NzDrawerService);\n  \n  openModal(): void {\n    const modalRef = this.modal.create({\n      nzTitle: 'Create Task',\n      nzContent: TaskFormComponent,\n      nzWidth: 720,\n      nzFooter: null\n    });\n    \n    \u002F\u002F Listen to form submission\n    modalRef.componentInstance!.taskSubmit.subscribe((task: any) => {\n      console.log('Task submitted:', task);\n      modalRef.close();\n    });\n  }\n  \n  openDrawer(): void {\n    const drawerRef = this.drawer.create({\n      nzTitle: 'Task Details',\n      nzContent: TaskFormComponent,\n      nzWidth: 640,\n      nzClosable: true\n    });\n    \n    drawerRef.afterClose.subscribe(() => {\n      console.log('Drawer closed');\n    });\n  }\n}\n```\n\n## ng-alain Theming\n\n### Using Theme Variables\n\n```scss\n\u002F\u002F Use ng-alain theme variables\n@import '@delon\u002Ftheme\u002Fsystem\u002Findex';\n\n.task-card {\n  background: var(--bg-color);\n  border: 1px solid var(--border-color);\n  padding: var(--padding-lg);\n  \n  .title {\n    color: var(--text-color);\n    font-size: var(--font-size-lg);\n  }\n}\n```\n\n### Dark Mode Support\n\n```typescript\nimport { Component, inject } from '@angular\u002Fcore';\nimport { SettingsService } from '@delon\u002Ftheme';\n\n@Component({\n  selector: 'app-theme-toggle',\n  template: `\n    \u003Cbutton nz-button (click)=\"toggleTheme()\">\n      \u003Ci nz-icon [nzType]=\"isDark() ? 'sun' : 'moon'\">\u003C\u002Fi>\n      {{ isDark() ? 'Light' : 'Dark' }} Mode\n    \u003C\u002Fbutton>\n  `\n})\nexport class ThemeToggleComponent {\n  private settings = inject(SettingsService);\n  \n  isDark = signal(false);\n  \n  ngOnInit(): void {\n    this.isDark.set(this.settings.layout.theme === 'dark');\n  }\n  \n  toggleTheme(): void {\n    const newTheme = this.isDark() ? 'light' : 'dark';\n    this.settings.setLayout('theme', newTheme);\n    this.isDark.set(newTheme === 'dark');\n  }\n}\n```\n\n## Best Practices\n\n### 1. Use SHARED_IMPORTS\n\n```typescript\n\u002F\u002F Define in shared module\nexport const SHARED_IMPORTS = [\n  CommonModule,\n  ReactiveFormsModule,\n  \u002F\u002F ng-zorro-antd\n  NzButtonModule,\n  NzCardModule,\n  NzFormModule,\n  NzInputModule,\n  \u002F\u002F @delon\n  STComponent,\n  SFComponent,\n  PageHeaderComponent\n];\n```\n\n### 2. Responsive Design\n\n```typescript\n\u002F\u002F Use ng-zorro responsive utilities\n\u003Cdiv nz-row [nzGutter]=\"16\">\n  \u003Cdiv nz-col \n    [nzXs]=\"24\"  \u002F\u002F Mobile: full width\n    [nzSm]=\"12\"  \u002F\u002F Tablet: half width\n    [nzMd]=\"8\"   \u002F\u002F Desktop: one third\n    [nzLg]=\"6\"   \u002F\u002F Large: one quarter\n  >\n    Content\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n```\n\n### 3. Accessibility\n\n```html\n\u003C!-- Use proper ARIA attributes -->\n\u003Cbutton \n  nz-button \n  aria-label=\"Create new task\"\n  [attr.aria-disabled]=\"loading()\"\n>\n  Create\n\u003C\u002Fbutton>\n\n\u003C!-- Proper form labels -->\n\u003Cnz-form-item>\n  \u003Cnz-form-label nzFor=\"title\" nzRequired>\n    Task Title\n  \u003C\u002Fnz-form-label>\n  \u003Cnz-form-control>\n    \u003Cinput nz-input id=\"title\" name=\"title\" \u002F>\n  \u003C\u002Fnz-form-control>\n\u003C\u002Fnz-form-item>\n```\n\n## Checklist\n\nWhen creating ng-alain components:\n\n- [ ] Use standalone components\n- [ ] Import SHARED_IMPORTS\n- [ ] Use STComponent for data tables\n- [ ] Use SFComponent for complex forms\n- [ ] Implement responsive layout\n- [ ] Add ACL permissions where needed\n- [ ] Use PageHeader for page titles\n- [ ] Implement proper loading states\n- [ ] Add error handling\n- [ ] Follow ng-alain theming system\n- [ ] Support dark mode\n- [ ] Ensure accessibility (ARIA)\n- [ ] Test on mobile devices\n\n## References\n\n- [ng-alain Documentation](https:\u002F\u002Fng-alain.com)\n- [ng-zorro-antd Documentation](https:\u002F\u002Fng.ant.design)\n- [@delon\u002Fabc Components](https:\u002F\u002Fng-alain.com\u002Fcomponents)\n- [ng-alain Instructions](.github\u002Finstructions\u002Fng-alain-delon.instructions.md)\n- [Angular Component Skill](.\u002Fangular-component\u002FSKILL.md)\n",{"name":5,"license":14,"description":7},"master","08cc2532077058aa50e6e18f54695bc256c88152","skills\u002F7spade\u002Fng-alain-component-development","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub","https:\u002F\u002Fgithub.com\u002Fsuperhealth","java engineer","2026-04-06 22:07:23",{"source":8,"skillName":5,"commands":51,"prompt":61,"zipAvailable":62},[52,55,58],{"tool":53,"command":54},"npx","npx skills add superhealth\u002Fskills-hub --skill ng-alain-component-development",{"tool":56,"command":57},"bunx","bunx skills add superhealth\u002Fskills-hub --skill ng-alain-component-development",{"tool":59,"command":60},"pnpm","pnpm dlx skills add superhealth\u002Fskills-hub --skill ng-alain-component-development","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002F7spade\u002Fng-alain-component-development\u002FSKILL.md",true,[64],{"path":65,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":68,"sourceHtmlUrl":69},"skill-report.json","REFERENCE","参考文档",12869,"https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002F7spade\u002Fng-alain-component-development\u002Fskill-report.json",[71,101,128,141,157,181],{"skillNo":72,"name":73,"nameZh":6,"description":74,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":75,"categories":76,"keywords":82,"publishedAt":38},"01M6MC9F3WHV8S8FZ2W4TRB0FE","vercel-react-best-practices","React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React\u002FNext.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002Fzhanlincui\u002Fvercel-react-best-practices\u002FSKILL.md",[77],{"categoryNo":78,"categoryName":79,"taxonomyType":80,"taxonomyTypeDesc":81},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",[83,84,85,86,87,88,89,90,91,92,28,93,94,95,96,97,98,24,99,100],"react","vercel react best practices","best practices","vercel","react best practices","data fetching","code","triggers","pages","next","refactoring","data","Optimization","tasks","guidelines","react components","performance","writing",{"skillNo":102,"name":103,"nameZh":6,"description":104,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":105,"categories":106,"keywords":111,"publishedAt":38},"01M6MB8KWE1Q5A5KERR7RFTQWP","vue-testing-best-practices","Use for Vue.js testing. Covers Vitest, Vue Test Utils, component testing, mocking, testing patterns, and Playwright for E2E testing.","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002Fvuejs-ai\u002Fvue-testing-best-practices\u002FSKILL.md",[107,110],{"categoryNo":108,"categoryName":109,"taxonomyType":80,"taxonomyTypeDesc":81},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":78,"categoryName":79,"taxonomyType":80,"taxonomyTypeDesc":81},[112,113,114,85,115,116,117,118,119,120,18,28,121,122,123,124,125,126,127],"vue testing best practices","testing best practices","vue","testing","testing patterns","js","e2e","vitest","use","test","mocking","for","utils","e2e testing","github","playwright",{"skillNo":129,"name":130,"nameZh":6,"description":131,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":132,"categories":133,"keywords":135,"publishedAt":38},"01M6MB8GK06M6GA4KVYNDV1BZP","vue-router-best-practices","Vue Router 4 patterns, navigation guards, route params, and route-component lifecycle interactions.","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002Fvuejs-ai\u002Fvue-router-best-practices\u002FSKILL.md",[134],{"categoryNo":78,"categoryName":79,"taxonomyType":80,"taxonomyTypeDesc":81},[85,114,136,137,138,28,139,140,18,126],"router","vue router best practices","route","navigation","lifecycle",{"skillNo":142,"name":143,"nameZh":6,"description":144,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":145,"categories":146,"keywords":148,"publishedAt":38},"01M6MB8DQF21TZMQ9XC3745ERW","vue-pinia-best-practices","Pinia stores, state management patterns, store setup, and reactivity with stores.","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002Fvuejs-ai\u002Fvue-pinia-best-practices\u002FSKILL.md",[147],{"categoryNo":78,"categoryName":79,"taxonomyType":80,"taxonomyTypeDesc":81},[149,150,114,85,151,152,28,153,154,155,156,126],"vue pinia best practices","pinia","with","store","management","state","state management","setup",{"skillNo":158,"name":159,"nameZh":6,"description":160,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":161,"categories":162,"keywords":172,"publishedAt":38},"01M6MB8A7MC08747J9TV4GWQ9A","vue-options-api-best-practices","Vue 3 Options API style (data(), methods, this context). Each reference shows Options API solution only.","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002Fvuejs-ai\u002Fvue-options-api-best-practices\u002FSKILL.md",[163,164,167],{"categoryNo":78,"categoryName":79,"taxonomyType":80,"taxonomyTypeDesc":81},{"categoryNo":165,"categoryName":166,"taxonomyType":80,"taxonomyTypeDesc":81},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":168,"categoryName":169,"taxonomyType":170,"taxonomyTypeDesc":171},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[114,173,174,175,85,176,177,178,179,94,126,180],"options","vue options api best practices","api","methods","reference","only","context","style",{"skillNo":182,"name":183,"nameZh":6,"description":184,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":9,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":185,"categories":186,"keywords":188,"publishedAt":38},"01M6MB85ZTQC24Q04X49MM4YXN","vue-development-guides","A collection of best practices and tips for developing applications using Vue.js. This skill MUST be apply when developing, refactoring or reviewing Vue.js or Nuxt projects.","https:\u002F\u002Fgithub.com\u002Fsuperhealth\u002Fskills-hub\u002Fblob\u002Fmaster\u002Fskills\u002Fvuejs-ai\u002Fvue-development-guides\u002FSKILL.md",[187],{"categoryNo":78,"categoryName":79,"taxonomyType":80,"taxonomyTypeDesc":81},[20,114,189,190,126,191,192,123,193,194,195,117,93,196,197,85],"guides","vue development guides","tips","apply","project","nuxt","projects","collection","applications"]