{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "ratings-review-badges",
  "title": "Ratings & Review Badges",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/ratings-review-badges/ratings-review-badges.component.ts",
      "content": "// Third-party proof strip: four review-platform cards with star rating, score out of\n// five, review count, and a category award line, over a rating-distribution bar and a\n// verified-reviews footnote. Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, Input } from '@angular/core'\nimport { LucideAngularModule, Star } 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 { UiProgressComponent } from '@/ui/progress/progress.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\n\ninterface Platform {\n  name: string\n  score: number\n  reviews: number\n  award: string\n}\n\ninterface DistributionRow {\n  stars: number\n  share: number\n}\n\nconst platforms: Platform[] = [\n  { name: 'G2', score: 4.8, reviews: 412, award: 'Leader — Analytics Platforms, Winter 2026' },\n  { name: 'Capterra', score: 4.7, reviews: 268, award: 'Best Value — Business Intelligence' },\n  { name: 'Product Hunt', score: 4.9, reviews: 1340, award: '#1 Product of the Day' },\n  { name: 'TrustRadius', score: 4.6, reviews: 97, award: 'Top Rated — Data Governance' },\n]\n\nconst distribution: DistributionRow[] = [\n  { stars: 5, share: 78 },\n  { stars: 4, share: 16 },\n  { stars: 3, share: 4 },\n  { stars: 2, share: 1 },\n  { stars: 1, share: 1 },\n]\n\nconst STAR_SLOTS = [1, 2, 3, 4, 5]\n\n/** Fill percentage for one star slot, so a 4.6 renders a real partial star. */\nfunction fillFor(score: number, slot: number): string {\n  return `${Math.min(Math.max(score - (slot - 1), 0), 1) * 100}%`\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-ratings-review-badges, [ui-ratings-review-badges]',\n  standalone: true,\n  // The block renders its own root <section>: keep this wrapper out of the layout.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiProgressComponent,\n    UiSeparatorComponent,\n  ],\n  template: `\n    <section data-slot=\"ratings-review-badges\" [class]=\"rootClass\">\n      <div class=\"mx-auto max-w-6xl px-6 py-20 lg:py-28\">\n        <div class=\"max-w-2xl\">\n          <span ui-badge variant=\"secondary\">Reviews</span>\n          <h2 class=\"mt-4 text-3xl font-semibold tracking-tight sm:text-4xl\">Rated by the people who run it daily</h2>\n          <p class=\"text-muted-foreground mt-3 text-lg\">\n            Every score below is pulled from a public review platform. None of them are ours to edit.\n          </p>\n        </div>\n\n        <div class=\"mt-10 grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n          @for (platform of platforms; track platform.name) {\n            <div ui-card>\n              <div ui-card-content class=\"p-5\">\n                <div class=\"flex items-baseline justify-between gap-3\">\n                  <p class=\"text-sm font-semibold\">{{ platform.name }}</p>\n                  <p class=\"text-muted-foreground font-mono text-xs\">{{ platform.reviews }} reviews</p>\n                </div>\n\n                <div class=\"mt-3 flex items-center gap-2\">\n                  <div class=\"flex items-center gap-0.5\" role=\"img\" [attr.aria-label]=\"platform.score + ' out of 5'\">\n                    @for (slot of starSlots; track slot) {\n                      <span class=\"relative inline-flex\">\n                        <lucide-icon [img]=\"Star\" class=\"text-muted-foreground/30 size-4\" aria-hidden=\"true\" />\n                        <!-- Dynamic clip width is the only way to draw a partial star. -->\n                        <span\n                          class=\"absolute inset-y-0 left-0 overflow-hidden\"\n                          [style.width]=\"fillFor(platform.score, slot)\"\n                          aria-hidden=\"true\"\n                        >\n                          <lucide-icon [img]=\"Star\" class=\"fill-primary text-primary size-4\" />\n                        </span>\n                      </span>\n                    }\n                  </div>\n                  <span class=\"text-sm font-medium\">{{ platform.score.toFixed(1) }}</span>\n                </div>\n\n                <p class=\"text-muted-foreground mt-4 text-xs leading-relaxed\">{{ platform.award }}</p>\n              </div>\n            </div>\n          }\n        </div>\n\n        <ui-separator class=\"my-10\" />\n\n        <div class=\"grid gap-10 lg:grid-cols-[1fr_1.4fr] lg:items-center\">\n          <div>\n            <p class=\"font-display text-5xl font-bold tracking-tight\">4.8</p>\n            <p class=\"text-muted-foreground mt-2 text-sm\">\n              Weighted average across 2,117 verified reviews on four platforms.\n            </p>\n            <button ui-button variant=\"outline\" class=\"mt-5\">Read the reviews</button>\n          </div>\n\n          <dl class=\"space-y-3\">\n            @for (row of distribution; track row.stars) {\n              <div class=\"flex items-center gap-4\">\n                <dt class=\"text-muted-foreground w-12 shrink-0 font-mono text-xs\">{{ row.stars }} star</dt>\n                <dd class=\"flex min-w-0 grow items-center gap-4\">\n                  <div ui-progress [value]=\"row.share\" class=\"h-1.5\" [aria-label]=\"row.stars + ' star reviews'\"></div>\n                  <span class=\"text-muted-foreground w-10 shrink-0 text-right font-mono text-xs\">{{ row.share }}%</span>\n                </dd>\n              </div>\n            }\n          </dl>\n        </div>\n      </div>\n    </section>\n  `,\n})\nexport class UiRatingsReviewBadgesComponent {\n  protected readonly Star = Star\n  protected readonly platforms = platforms\n  protected readonly distribution = distribution\n  protected readonly starSlots = STAR_SLOTS\n\n  @Input('class') className?: string\n\n  get rootClass(): string {\n    return cn('bg-background', this.className)\n  }\n\n  fillFor(score: number, slot: number): string {\n    return fillFor(score, slot)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/ratings-review-badges/ratings-review-badges.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/ratings-review-badges/index.ts",
      "content": "export { UiRatingsReviewBadgesComponent } from './ratings-review-badges.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/ratings-review-badges/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/progress.json",
    "https://uipkge.dev/r/angular/separator.json"
  ],
  "description": "Third-party proof strip: four review-platform cards with star rating, score out of five, review count, and a category award line, over a rating-distribution bar and a verified-reviews footnote.",
  "categories": [
    "marketing"
  ]
}