agentsclimarketplace

Ng alain component development

Skill aiskillstore/marketplace/skills/7spade/ng-alain-component-development

Security-audited skills for Claude, Codex & Claude Code. One-click install, quality verified.

Install
npx -y skills add aiskillstore/marketplace --skill ng-alain-component-development

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.

What its author says it does

Copied from the file, not written here

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.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

14.3 KB, ~3.7k tokens by cl100k_base, as published. Nobody here has run it

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

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: `
    <st 
      [data]="tasks()" 
      [columns]="columns"
      [loading]="loading()"
      [page]="{ show: true, showSize: true }"
      (change)="handleChange($event)"
    />
  `
})
export class TaskTableComponent {
  private taskService = inject(TaskService);
  
  loading = signal(false);
  tasks = signal<STData[]>([]);
  
  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<void> {
    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

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: `
    <sf 
      [schema]="schema" 
      [loading]="loading()"
      (formSubmit)="handleSubmit($event)"
      (formChange)="handleChange($event)"
    />
  `
})
export class TaskFormComponent {
  loading = signal(false);
  taskSubmit = output<any>();
  
  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<any[]> {
    // Load users for assignee dropdown
    return [
      { label: 'User 1', value: 'user1' },
      { label: 'User 2', value: 'user2' }
    ];
  }
}

3. Page Header with Actions

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: `
    <page-header 
      [title]="'Task Management'"
      [subtitle]="'Manage tasks for ' + blueprintName()"
      [breadcrumb]="breadcrumb"
    >
      <ng-template #extra>
        <button nz-button nzType="primary" (click)="createTask()">
          <i nz-icon nzType="plus"></i>
          New Task
        </button>
        <button nz-button (click)="refresh()">
          <i nz-icon nzType="reload"></i>
          Refresh
        </button>
      </ng-template>
    </page-header>
    
    <nz-card>
      <app-task-table />
    </nz-card>
  `
})
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)

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: `
    <nz-space>
      <!-- Show button only if user has permission -->
      <button 
        *nzSpaceItem
        *aclIf="'task:create'"
        nz-button 
        nzType="primary"
        (click)="create()"
      >
        Create Task
      </button>
      
      <button 
        *nzSpaceItem
        *aclIf="'task:delete'"
        nz-button 
        nzDanger
        (click)="delete()"
      >
        Delete
      </button>
      
      <!-- Check permission in code -->
      @if (canEdit()) {
        <button 
          *nzSpaceItem
          nz-button 
          (click)="edit()"
        >
          Edit
        </button>
      }
    </nz-space>
  `
})
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

import { Component } from '@angular/core';
import { SHARED_IMPORTS } from '@shared';

@Component({
  selector: 'app-dashboard',
  standalone: true,
  imports: [SHARED_IMPORTS],
  template: `
    <div nz-row [nzGutter]="[16, 16]">
      <!-- Responsive columns -->
      <div nz-col [nzXs]="24" [nzSm]="12" [nzMd]="8" [nzLg]="6">
        <nz-card nzTitle="Total Tasks">
          <nz-statistic 
            [nzValue]="totalTasks()" 
            [nzPrefix]="prefixTpl"
          />
          <ng-template #prefixTpl>
            <i nz-icon nzType="check-circle"></i>
          </ng-template>
        </nz-card>
      </div>
      
      <div nz-col [nzXs]="24" [nzSm]="12" [nzMd]="8" [nzLg]="6">
        <nz-card nzTitle="Completed">
          <nz-statistic 
            [nzValue]="completedTasks()" 
            [nzValueStyle]="{ color: '#52c41a' }"
          />
        </nz-card>
      </div>
      
      <div nz-col [nzXs]="24" [nzSm]="12" [nzMd]="8" [nzLg]="6">
        <nz-card nzTitle="In Progress">
          <nz-statistic 
            [nzValue]="inProgressTasks()" 
            [nzValueStyle]="{ color: '#faad14' }"
          />
        </nz-card>
      </div>
      
      <div nz-col [nzXs]="24" [nzSm]="12" [nzMd]="8" [nzLg]="6">
        <nz-card nzTitle="Pending">
          <nz-statistic [nzValue]="pendingTasks()" />
        </nz-card>
      </div>
    </div>
  `
})
export class DashboardComponent {
  totalTasks = signal(100);
  completedTasks = signal(60);
  inProgressTasks = signal(25);
  pendingTasks = signal(15);
}

6. Modal and Drawer

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: `
    <button nz-button nzType="primary" (click)="openModal()">
      Open Modal
    </button>
    <button nz-button (click)="openDrawer()">
      Open Drawer
    </button>
  `
})
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

// 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

import { Component, inject } from '@angular/core';
import { SettingsService } from '@delon/theme';

@Component({
  selector: 'app-theme-toggle',
  template: `
    <button nz-button (click)="toggleTheme()">
      <i nz-icon [nzType]="isDark() ? 'sun' : 'moon'"></i>
      {{ isDark() ? 'Light' : 'Dark' }} Mode
    </button>
  `
})
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

// Define in shared module
export const SHARED_IMPORTS = [
  CommonModule,
  ReactiveFormsModule,
  // ng-zorro-antd
  NzButtonModule,
  NzCardModule,
  NzFormModule,
  NzInputModule,
  // @delon
  STComponent,
  SFComponent,
  PageHeaderComponent
];

2. Responsive Design

// Use ng-zorro responsive utilities
<div nz-row [nzGutter]="16">
  <div nz-col 
    [nzXs]="24"  // Mobile: full width
    [nzSm]="12"  // Tablet: half width
    [nzMd]="8"   // Desktop: one third
    [nzLg]="6"   // Large: one quarter
  >
    Content
  </div>
</div>

3. Accessibility

<!-- Use proper ARIA attributes -->
<button 
  nz-button 
  aria-label="Create new task"
  [attr.aria-disabled]="loading()"
>
  Create
</button>

<!-- Proper form labels -->
<nz-form-item>
  <nz-form-label nzFor="title" nzRequired>
    Task Title
  </nz-form-label>
  <nz-form-control>
    <input nz-input id="title" name="title" />
  </nz-form-control>
</nz-form-item>

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

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.