Agent Skills by ALSEL
Anthropic Claudeデータ・分析⭐ リポ 0品質スコア 50/100

angular-ui-patterns

ローディング状態、エラーハンドリング、データ表示に関するモダンなAngular UIパターンを提供します。UIコンポーネントの構築、非同期データの処理、コンポーネント状態の管理が必要な場面で活用してください。

description の原文を見る

Modern Angular UI patterns for loading states, error handling, and data display. Use when building UI components, handling async data, or managing component states.

SKILL.md 本文

Angular UI パターン

コア原則

  1. 古いUIを決して表示しない - 実際にロード中の場合のみロード状態を表示
  2. 常にエラーを表示する - ユーザーは何か失敗したことを知る必要があります
  3. 楽観的な更新 - UIを瞬時に感じさせる
  4. 段階的な情報開示 - @defer を使用して利用可能な内容を表示
  5. 段階的な機能低下 - 部分的なデータはデータがないよりは良い

ロード状態パターン

黄金ルール

表示するデータがない場合に限り、ロード指示器を表示してください。

@Component({
  template: `
    @if (error()) {
      <app-error-state [error]="error()" (retry)="load()" />
    } @else if (loading() && !items().length) {
      <app-skeleton-list />
    } @else if (!items().length) {
      <app-empty-state message="No items found" />
    } @else {
      <app-item-list [items]="items()" />
    }
  `,
})
export class ItemListComponent {
  private store = inject(ItemStore);

  items = this.store.items;
  loading = this.store.loading;
  error = this.store.error;
}

ロード状態判定フロー図

エラーが発生していますか?
  → はい: リトライオプション付きのエラー状態を表示
  → いいえ: 続行

ロード中で、かつデータがありませんか?
  → はい: ロード指示器(スピナー/スケルトン)を表示
  → いいえ: 続行

データがありますか?
  → はい、アイテムあり: データを表示
  → はい、ただし空: 空状態を表示
  → いいえ: ロード状態を表示(フォールバック)

スケルトン vs スピナー

スケルトンを使用する場合スピナーを使用する場合
既知のコンテンツ形状未知のコンテンツ形状
リスト/カードレイアウトモーダルアクション
初期ページロードボタン送信
コンテンツプレースホルダーインライン操作

制御フローパターン

条件付きレンダリング用 @if/@else

@if (user(); as user) {
<span>Welcome, {{ user.name }}</span>
} @else if (loading()) {
<app-spinner size="small" />
} @else {
<a routerLink="/login">Sign In</a>
}

@for とトラック

@for (item of items(); track item.id) {
<app-item-card [item]="item" (delete)="remove(item.id)" />
} @empty {
<app-empty-state
  icon="inbox"
  message="No items yet"
  actionLabel="Create Item"
  (action)="create()"
/>
}

段階的なロード用 @defer

<!-- 重要なコンテンツは即座にロード -->
<app-header />
<app-hero-section />

<!-- 重要でないコンテンツは遅延ロード -->
@defer (on viewport) {
<app-comments [postId]="postId()" />
} @placeholder {
<div class="h-32 bg-gray-100 animate-pulse"></div>
} @loading (minimum 200ms) {
<app-spinner />
} @error {
<app-error-state message="Failed to load comments" />
}

エラーハンドリングパターン

エラーハンドリング階層

1. インラインエラー(フィールドレベル) → フォーム検証エラー
2. トースト通知 → 回復可能なエラー、ユーザーが再試行可能
3. エラーバナー → ページレベルのエラー、データは部分的に使用可能
4. 全画面エラー → 回復不可、ユーザーアクションが必要

常にエラーを表示

重要: エラーを黙ったまま飲み込まないでください。

// 正しい - エラーは常にユーザーに表示される
@Component({...})
export class CreateItemComponent {
  private store = inject(ItemStore);
  private toast = inject(ToastService);

  async create(data: CreateItemDto) {
    try {
      await this.store.create(data);
      this.toast.success('Item created successfully');
      this.router.navigate(['/items']);
    } catch (error) {
      console.error('createItem failed:', error);
      this.toast.error('Failed to create item. Please try again.');
    }
  }
}

// 間違い - エラーが黙ったまま処理される
async create(data: CreateItemDto) {
  try {
    await this.store.create(data);
  } catch (error) {
    console.error(error); // ユーザーには何も見えない!
  }
}

エラー状態コンポーネントパターン

@Component({
  selector: "app-error-state",
  standalone: true,
  imports: [NgOptimizedImage],
  template: `
    <div class="error-state">
      <img ngSrc="/assets/error-icon.svg" width="64" height="64" alt="" />
      <h3>{{ title() }}</h3>
      <p>{{ message() }}</p>
      @if (retry.observed) {
        <button (click)="retry.emit()" class="btn-primary">Try Again</button>
      }
    </div>
  `,
})
export class ErrorStateComponent {
  title = input("Something went wrong");
  message = input("An unexpected error occurred");
  retry = output<void>();
}

ボタン状態パターン

ボタンロード状態

<button
  (click)="handleSubmit()"
  [disabled]="isSubmitting() || !form.valid"
  class="btn-primary"
>
  @if (isSubmitting()) {
  <app-spinner size="small" class="mr-2" />
  Saving... } @else { Save Changes }
</button>

非同期操作中の無効化

重要: 非同期操作中は常にトリガーを無効にしてください。

// 正しい - ロード中はボタンが無効
@Component({
  template: `
    <button
      [disabled]="saving()"
      (click)="save()"
    >
      @if (saving()) {
        <app-spinner size="sm" /> Saving...
      } @else {
        Save
      }
    </button>
  `
})
export class SaveButtonComponent {
  saving = signal(false);

  async save() {
    this.saving.set(true);
    try {
      await this.service.save();
    } finally {
      this.saving.set(false);
    }
  }
}

// 間違い - ユーザーは複数回クリック可能
<button (click)="save()">
  {{ saving() ? 'Saving...' : 'Save' }}
</button>

空状態

空状態の要件

すべてのリスト/コレクションには空状態が必須です:

@for (item of items(); track item.id) {
<app-item-card [item]="item" />
} @empty {
<app-empty-state
  icon="folder-open"
  title="No items yet"
  description="Create your first item to get started"
  actionLabel="Create Item"
  (action)="openCreateDialog()"
/>
}

コンテキストに応じた空状態

@Component({
  selector: "app-empty-state",
  template: `
    <div class="empty-state">
      <span class="icon" [class]="icon()"></span>
      <h3>{{ title() }}</h3>
      <p>{{ description() }}</p>
      @if (actionLabel()) {
        <button (click)="action.emit()" class="btn-primary">
          {{ actionLabel() }}
        </button>
      }
    </div>
  `,
})
export class EmptyStateComponent {
  icon = input("inbox");
  title = input.required<string>();
  description = input("");
  actionLabel = input<string | null>(null);
  action = output<void>();
}

フォームパターン

ロードと検証を含むフォーム

@Component({
  template: `
    <form [formGroup]="form" (ngSubmit)="onSubmit()">
      <div class="form-field">
        <label for="name">Name</label>
        <input
          id="name"
          formControlName="name"
          [class.error]="isFieldInvalid('name')"
        />
        @if (isFieldInvalid("name")) {
          <span class="error-text">
            {{ getFieldError("name") }}
          </span>
        }
      </div>

      <div class="form-field">
        <label for="email">Email</label>
        <input id="email" type="email" formControlName="email" />
        @if (isFieldInvalid("email")) {
          <span class="error-text">
            {{ getFieldError("email") }}
          </span>
        }
      </div>

      <button type="submit" [disabled]="form.invalid || submitting()">
        @if (submitting()) {
          <app-spinner size="sm" /> Submitting...
        } @else {
          Submit
        }
      </button>
    </form>
  `,
})
export class UserFormComponent {
  private fb = inject(FormBuilder);

  submitting = signal(false);

  form = this.fb.group({
    name: ["", [Validators.required, Validators.minLength(2)]],
    email: ["", [Validators.required, Validators.email]],
  });

  isFieldInvalid(field: string): boolean {
    const control = this.form.get(field);
    return control ? control.invalid && control.touched : false;
  }

  getFieldError(field: string): string {
    const control = this.form.get(field);
    if (control?.hasError("required")) return "This field is required";
    if (control?.hasError("email")) return "Invalid email format";
    if (control?.hasError("minlength")) return "Too short";
    return "";
  }

  async onSubmit() {
    if (this.form.invalid) return;

    this.submitting.set(true);
    try {
      await this.service.submit(this.form.value);
      this.toast.success("Submitted successfully");
    } catch {
      this.toast.error("Submission failed");
    } finally {
      this.submitting.set(false);
    }
  }
}

ダイアログ/モーダルパターン

確認ダイアログ

// dialog.service.ts
@Injectable({ providedIn: 'root' })
export class DialogService {
  private dialog = inject(Dialog); // CDK Dialog またはカスタム

  async confirm(options: {
    title: string;
    message: string;
    confirmText?: string;
    cancelText?: string;
  }): Promise<boolean> {
    const dialogRef = this.dialog.open(ConfirmDialogComponent, {
      data: options,
    });

    return await firstValueFrom(dialogRef.closed) ?? false;
  }
}

// 使用方法
async deleteItem(item: Item) {
  const confirmed = await this.dialog.confirm({
    title: 'Delete Item',
    message: `Are you sure you want to delete "${item.name}"?`,
    confirmText: 'Delete',
  });

  if (confirmed) {
    await this.store.delete(item.id);
  }
}

アンチパターン

ロード状態

// 間違い - データが存在する時にスピナーを表示(リフェッチ時にフラッシュが発生)
@if (loading()) {
  <app-spinner />
}

// 正しい - データがない場合のみロード状態を表示
@if (loading() && !items().length) {
  <app-spinner />
}

エラーハンドリング

// 間違い - エラーが無視される
try {
  await this.service.save();
} catch (e) {
  console.log(e); // ユーザーは何も知らない!
}

// 正しい - エラーが表示される
try {
  await this.service.save();
} catch (e) {
  console.error("Save failed:", e);
  this.toast.error("Failed to save. Please try again.");
}

ボタン状態

<!-- 間違い - 送信中にボタンが無効にされていない -->
<button (click)="submit()">Submit</button>

<!-- 正しい - 無効で、ロード中を表示 -->
<button (click)="submit()" [disabled]="loading()">
  @if (loading()) {
  <app-spinner size="sm" />
  } Submit
</button>

UI 状態チェックリスト

コンポーネント完成前に確認してください:

UI 状態

  • エラー状態が処理され、ユーザーに表示される
  • ロード状態はデータが存在しない場合のみ表示される
  • コレクション用に空状態が提供されている(@empty ブロック)
  • 非同期操作中はボタンが無効になる
  • 必要に応じてボタンがロード指示器を表示する

データと変更

  • すべての非同期操作にエラーハンドリングがある
  • すべてのユーザーアクションにフィードバックがある(トースト/ビジュアル)
  • 楽観的な更新は失敗時にロールバックする

アクセシビリティ

  • ロード状態がスクリーンリーダーにアナウンスされる
  • エラーメッセージがフォームフィールドにリンクされている
  • 状態変更後のフォーカス管理が行われている

他のスキルとの統合

  • angular-state-management: State管理用に Signal ストアを使用
  • angular: モダンパターン(Signals、@defer)を適用
  • testing-patterns: すべての UI 状態をテスト

使用する場合

このスキルは概要に記載されたワークフローまたはアクションを実行する際に適用されます。

制限事項

  • このスキルは上記の説明に明確に合致するタスクのみで使用してください。
  • 出力を環境固有の検証、テスト、または専門家のレビューの代替として扱わないでください。
  • 必要な入力、権限、安全境界、または成功基準が不足している場合は、立ち止まって明確化を求めてください。

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
sickn33
リポジトリ
sickn33/antigravity-awesome-skills
ライセンス
MIT
最終更新
不明

Source: https://github.com/sickn33/antigravity-awesome-skills / ライセンス: MIT

関連スキル

OpenAIデータ・分析⭐ リポ 1,451

hugging-face-trackio

Trackioを使用してMLトレーニング実験を追跡・可視化できます。トレーニング中のメトリクスログ記録(Python API)、トレーニング診断のアラート発火、ログされたメトリクスの取得・分析(CLI)が必要な場合に活用してください。リアルタイムダッシュボード表示、Webhookを使用したアラート、HF Space同期、自動化向けのJSON出力に対応しています。

by gradio-app
汎用データ・分析⭐ リポ 855

btc-bottom-model

ビットコインのサイクルタイミングモデルで、加重スコアリングシステムを搭載しています。日次パルス(4指標、32ポイント)とウィークリー構造(9指標、68ポイント)の2カテゴリーにわたる13の指標を追跡し、0~100のマーケットヒートスコアを算出します。ETFフロー、ファンディングレート、ロング/ショート比率、恐怖・貪欲指数、LTH-MVRV、NUPL、SOPR(LTH+STH)、LTH供給率、移動平均倍率(365日MA、200週MA)、週次RSI、出来高トレンドに対応します。市場サイクル全体を通じて買いと売りの両方の推奨を提供します。ビットコインの底値拾い、BTCサイクルポジション、買い時・売り時、オンチェーン指標、MVRV、NUPL、SOPR、LTH動向、ETFの流出入、ファンディングレート、恐怖指数、ビットコインが過熱状態か、マイナーコスト、暗号資産市場のセンチメント、BTCのポジションサイジング、「今ビットコインを買うべきか」「BTCが天井をつけているか」「オンチェーン指標は何を示しているか」といった質問の際にこのスキルを活用します。

by star23
Anthropic Claudeデータ・分析⭐ リポ 380

protein_solubility_optimization

タンパク質の溶解性最適化 - タンパク質の溶解性を最適化します。タンパク質の特性を計算し、溶解性と親水性を予測し、有効な変異を提案します。タンパク質配列の特性計算、タンパク質機能の予測、親水性計算、ゼロショット配列予測を含むタンパク質エンジニアリング業務に使用できます。3つのSCPサーバーから4つのツールを統合しています。

by SpectrAI-Initiative
Anthropic Claudeデータ・分析⭐ リポ 1,743

research-lookup

Parallel Chat APIまたはPerplexity sonar-pro-searchを使用して、最新の研究情報を検索できます。学術論文の検索にも対応しています。クエリは自動的に最適なバックエンドにルーティングされるため、論文の検索、研究データの収集、科学情報の検証に活用できます。

by K-Dense-AI
Anthropic Claudeデータ・分析⭐ リポ 299

tree-formatting

ggtree(R)またはiTOL(ウェブ)を使用して、系統樹の可視化とフォーマットを行います。系統樹を図として描画する際、ツリーレイアウトの選択、分類学に基づく枝やラベルの色付け、クレードの折りたたみ、サポート値の表示、またはツリーへのオーバーレイ追加が必要な場合に使用してください。系統推定(protein-phylogenyスキルを使用)やドメイン注釈(今後の独立したスキル)には使用しないでください。

by majiayu000
汎用データ・分析⭐ リポ 145

querying-indonesian-gov-data

インドネシア政府の50以上のAPIとデータソースに接続できます。BPJPH(ハラール認証)、BOM(食品安全)、OJK(金融適正性)、BPS(統計)、BMKG(気象・地震)、インドネシア中央銀行(為替レート)、IDX(株式)、CKAN公開データポータル、pasal.id(第三者法MCP)に対応しています。インドネシア政府データを活用したアプリ開発、.go.idウェブサイトのスクレイピング、ハラール認証の確認、企業の法的適正性の検証、金融機関ステータスの照会、またはインドネシアMCPサーバーへの接続時に使用できます。CSRF処理、CKAN API使用方法、IP制限回避など、すぐに実行可能なPythonパターンを含んでいます。

by suryast
本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: sickn33 · sickn33/antigravity-awesome-skills · ライセンス: MIT