{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "case-study-filterable-list",
  "title": "Case Studies — Filterable List",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/case-study-filterable-list/case-study-filterable-list.component.ts",
      "content": "// Filterable index of customer stories: industry chips narrow rows carrying the headline\n// result, stack, and read time, with an empty state covering no matches. Port of the React\n// block 1:1.\nimport { ChangeDetectionStrategy, Component, Input, computed, signal } from '@angular/core'\nimport { ArrowUpRight, LucideAngularModule } from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport { UiCardComponent, UiCardContentComponent } from '@/ui/card/card.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\nimport { UiToggleGroupComponent, UiToggleGroupItemComponent } from '@/ui/toggle-group/toggle-group.component'\n\nexport interface CaseStudyListStudy {\n  company: string\n  industry: string\n  result: string\n  stack: string\n  readTime: string\n}\n\nconst defaultStudies: CaseStudyListStudy[] = [\n  {\n    company: 'Northwind Logistics',\n    industry: 'Logistics',\n    result: '5 days off the monthly close',\n    stack: 'Snowflake · dbt · Okta',\n    readTime: '8 min',\n  },\n  {\n    company: 'Halden Health',\n    industry: 'Healthcare',\n    result: '71% fewer ad-hoc data requests',\n    stack: 'BigQuery · Airflow',\n    readTime: '6 min',\n  },\n  {\n    company: 'Verity Retail Group',\n    industry: 'Retail',\n    result: '2.4pp tighter forecast band',\n    stack: 'Redshift · dbt',\n    readTime: '7 min',\n  },\n  {\n    company: 'Calder Manufacturing',\n    industry: 'Manufacturing',\n    result: '11 spreadsheets retired',\n    stack: 'Postgres · Dagster',\n    readTime: '5 min',\n  },\n  {\n    company: 'Ridgeway Freight',\n    industry: 'Logistics',\n    result: 'Per-shipment landed cost',\n    stack: 'Snowflake · Fivetran',\n    readTime: '9 min',\n  },\n  {\n    company: 'Ashford Clinics',\n    industry: 'Healthcare',\n    result: 'PHI-scoped self-serve reporting',\n    stack: 'BigQuery · Entra ID',\n    readTime: '6 min',\n  },\n]\n\nconst ALL = 'All'\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-case-study-filterable-list, [ui-case-study-filterable-list]',\n  standalone: true,\n  // React renders the root <section> itself: the host stays out of layout and `class` goes to the root.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiSeparatorComponent,\n    UiToggleGroupComponent,\n    UiToggleGroupItemComponent,\n  ],\n  template: `\n    <section data-slot=\"case-study-filterable-list\" [class]=\"rootClass\">\n      <div class=\"mx-auto max-w-4xl px-6 py-20 lg:py-28\">\n        <div class=\"flex flex-wrap items-end justify-between gap-6\">\n          <div>\n            <span ui-badge variant=\"secondary\">Customer stories</span>\n            <h2 class=\"mt-4 text-3xl font-semibold tracking-tight sm:text-4xl\">Read one close to your own</h2>\n          </div>\n\n          <div\n            ui-toggle-group\n            type=\"single\"\n            variant=\"outline\"\n            size=\"sm\"\n            class=\"flex-nowrap overflow-x-auto\"\n            aria-label=\"Filter case studies by industry\"\n            [value]=\"active()\"\n            (valueChange)=\"onFilterChange($event)\"\n          >\n            @for (industry of industries(); track industry) {\n              <button ui-toggle-group-item [value]=\"industry\">{{ industry }}</button>\n            }\n          </div>\n        </div>\n\n        <div ui-card class=\"mt-8\">\n          <div ui-card-content class=\"p-2\">\n            @if (visible().length === 0) {\n              <div class=\"px-4 py-16 text-center\">\n                <p class=\"text-sm font-medium\">No stories in that industry yet.</p>\n                <button ui-button variant=\"outline\" size=\"sm\" class=\"mt-4\" (click)=\"showAll()\">Show all</button>\n              </div>\n            } @else {\n              <ul>\n                @for (study of visible(); track study.company; let last = $last) {\n                  <li>\n                    <a\n                      href=\"#\"\n                      class=\"hover:bg-muted focus-visible:ring-ring group flex items-center gap-4 rounded-lg p-4 transition-colors focus-visible:ring-2 focus-visible:outline-none\"\n                      (click)=\"$event.preventDefault()\"\n                    >\n                      <div class=\"min-w-0 flex-1\">\n                        <div class=\"flex flex-wrap items-center gap-2\">\n                          <p class=\"text-sm font-semibold\">{{ study.company }}</p>\n                          <span ui-badge variant=\"outline\">{{ study.industry }}</span>\n                        </div>\n                        <p class=\"mt-1 text-sm\">{{ study.result }}</p>\n                        <p class=\"text-muted-foreground mt-1 font-mono text-xs\">{{ study.stack }}</p>\n                      </div>\n                      <span class=\"text-muted-foreground shrink-0 text-xs\">{{ study.readTime }}</span>\n                      <lucide-icon\n                        [img]=\"ArrowUpRight\"\n                        class=\"text-muted-foreground size-4 shrink-0 transition-transform group-hover:translate-x-0.5 group-hover:-translate-y-0.5\"\n                        aria-hidden=\"true\"\n                      />\n                    </a>\n                  </li>\n                  @if (!last) {\n                    <ui-separator />\n                  }\n                }\n              </ul>\n            }\n          </div>\n        </div>\n      </div>\n    </section>\n  `,\n})\nexport class UiCaseStudyFilterableListComponent {\n  protected readonly ArrowUpRight = ArrowUpRight\n  protected readonly allLabel = ALL\n\n  @Input() set initialStudies(v: CaseStudyListStudy[] | undefined) {\n    this.studies.set((v ?? defaultStudies).map((s) => ({ ...s })))\n  }\n  @Input() set defaultIndustry(v: string | undefined) {\n    this.active.set(v ?? ALL)\n  }\n  @Input('class') className?: string\n\n  readonly studies = signal<CaseStudyListStudy[]>(defaultStudies.map((s) => ({ ...s })))\n  readonly active = signal<string>(ALL)\n\n  readonly industries = computed(() => [ALL, ...new Set(this.studies().map((s) => s.industry))])\n  readonly visible = computed(() => {\n    const active = this.active()\n    return active === ALL ? this.studies() : this.studies().filter((s) => s.industry === active)\n  })\n\n  get rootClass(): string {\n    return cn('bg-background', this.className)\n  }\n\n  // Single-select emits '' when the pressed chip is pressed again; fall back to ALL so the\n  // list is never empty by accident.\n  onFilterChange(value: string | string[]): void {\n    const next = Array.isArray(value) ? (value[0] ?? '') : value\n    this.active.set(next || ALL)\n  }\n\n  showAll(): void {\n    this.active.set(ALL)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/case-study-filterable-list/case-study-filterable-list.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/case-study-filterable-list/index.ts",
      "content": "export { UiCaseStudyFilterableListComponent, type CaseStudyListStudy } from './case-study-filterable-list.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/case-study-filterable-list/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/separator.json",
    "https://uipkge.dev/r/angular/toggle-group.json"
  ],
  "description": "Filterable index of customer stories with industry chips above rows carrying the headline result, stack, and read time, plus an empty state.",
  "categories": [
    "marketing"
  ],
  "deprecated": true,
  "replacedBy": "case-study"
}